Commit 1b6069f5 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/controller/mediatek'

- Clear MSI interrupt status before handler to avoid missing MSIs that
  occur after the handler (qizhong cheng)

- Update mediatek-gen3 translation window setup to handle MMIO space that
  is not a power of two in size (Jianjun Wang)

* pci/controller/mediatek:
  PCI: mediatek-gen3: Fix translation window size calculation
  PCI: mediatek: Clear interrupt status before dispatching handler
parents 1800c660 9ccc1318
Loading
Loading
Loading
Loading
+50 −35
Original line number Diff line number Diff line
@@ -245,36 +245,61 @@ static int mtk_pcie_set_trans_table(struct mtk_gen3_pcie *pcie,
				    resource_size_t cpu_addr,
				    resource_size_t pci_addr,
				    resource_size_t size,
				    unsigned long type, int num)
				    unsigned long type, int *num)
{
	resource_size_t remaining = size;
	resource_size_t table_size;
	resource_size_t addr_align;
	const char *range_type;
	void __iomem *table;
	u32 val;

	if (num >= PCIE_MAX_TRANS_TABLES) {
		dev_err(pcie->dev, "not enough translate table for addr: %#llx, limited to [%d]\n",
			(unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);
		return -ENODEV;
	while (remaining && (*num < PCIE_MAX_TRANS_TABLES)) {
		/* Table size needs to be a power of 2 */
		table_size = BIT(fls(remaining) - 1);

		if (cpu_addr > 0) {
			addr_align = BIT(ffs(cpu_addr) - 1);
			table_size = min(table_size, addr_align);
		}

	table = pcie->base + PCIE_TRANS_TABLE_BASE_REG +
		num * PCIE_ATR_TLB_SET_OFFSET;
		/* Minimum size of translate table is 4KiB */
		if (table_size < 0x1000) {
			dev_err(pcie->dev, "illegal table size %#llx\n",
				(unsigned long long)table_size);
			return -EINVAL;
		}

	writel_relaxed(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(size) - 1),
		       table);
	writel_relaxed(upper_32_bits(cpu_addr),
		       table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
	writel_relaxed(lower_32_bits(pci_addr),
		       table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
	writel_relaxed(upper_32_bits(pci_addr),
		       table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);
		table = pcie->base + PCIE_TRANS_TABLE_BASE_REG + *num * PCIE_ATR_TLB_SET_OFFSET;
		writel_relaxed(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(table_size) - 1), table);
		writel_relaxed(upper_32_bits(cpu_addr), table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
		writel_relaxed(lower_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
		writel_relaxed(upper_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);

	if (type == IORESOURCE_IO)
		if (type == IORESOURCE_IO) {
			val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
	else
			range_type = "IO";
		} else {
			val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
			range_type = "MEM";
		}

		writel_relaxed(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);

		dev_dbg(pcie->dev, "set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",
			range_type, *num, (unsigned long long)cpu_addr,
			(unsigned long long)pci_addr, (unsigned long long)table_size);

		cpu_addr += table_size;
		pci_addr += table_size;
		remaining -= table_size;
		(*num)++;
	}

	if (remaining)
		dev_warn(pcie->dev, "not enough translate table for addr: %#llx, limited to [%d]\n",
			 (unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);

	return 0;
}

@@ -380,30 +405,20 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie)
		resource_size_t cpu_addr;
		resource_size_t pci_addr;
		resource_size_t size;
		const char *range_type;

		if (type == IORESOURCE_IO) {
		if (type == IORESOURCE_IO)
			cpu_addr = pci_pio_to_address(res->start);
			range_type = "IO";
		} else if (type == IORESOURCE_MEM) {
		else if (type == IORESOURCE_MEM)
			cpu_addr = res->start;
			range_type = "MEM";
		} else {
		else
			continue;
		}

		pci_addr = res->start - entry->offset;
		size = resource_size(res);
		err = mtk_pcie_set_trans_table(pcie, cpu_addr, pci_addr, size,
					       type, table_index);
					       type, &table_index);
		if (err)
			return err;

		dev_dbg(pcie->dev, "set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",
			range_type, table_index, (unsigned long long)cpu_addr,
			(unsigned long long)pci_addr, (unsigned long long)size);

		table_index++;
	}

	return 0;
+8 −2
Original line number Diff line number Diff line
@@ -617,12 +617,18 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
		if (status & MSI_STATUS){
			unsigned long imsi_status;

			/*
			 * The interrupt status can be cleared even if the
			 * MSI status remains pending. As such, given the
			 * edge-triggered interrupt type, its status should
			 * be cleared before being dispatched to the
			 * handler of the underlying device.
			 */
			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
			while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
				for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM)
					generic_handle_domain_irq(port->inner_domain, bit);
			}
			/* Clear MSI interrupt status */
			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
		}
	}