mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 23:21:31 +00:00
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
This commit is contained in:
commit
1b6069f51e
@ -245,35 +245,60 @@ 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
|
||||
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)++;
|
||||
}
|
||||
|
||||
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(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)
|
||||
val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
|
||||
else
|
||||
val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
|
||||
|
||||
writel_relaxed(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user