From: John Jacques <[email protected]> Added support for PCIe Message Signaled Interrupts (MSI). Fixed the PCIe Legacy (INTx) interrupt handling. Added the proper interrupt mapping and assignments.
Signed-off-by: Palani <[email protected]> Signed-off-by: John Jacques <[email protected]> --- arch/arm64/boot/dts/intel/axc67xx.dtsi | 75 ++++++++++--------- arch/arm64/boot/dts/intel/axm56xx.dtsi | 45 +++++++++++- drivers/pci/host/pcie-axxia.c | 128 ++++++++++++++++++++++++++------- drivers/pci/host/pcie-axxia.h | 3 + 4 files changed, 191 insertions(+), 60 deletions(-) diff --git a/arch/arm64/boot/dts/intel/axc67xx.dtsi b/arch/arm64/boot/dts/intel/axc67xx.dtsi index f6712fb..0c65b99 100644 --- a/arch/arm64/boot/dts/intel/axc67xx.dtsi +++ b/arch/arm64/boot/dts/intel/axc67xx.dtsi @@ -342,7 +342,7 @@ mtc: mtc@8080210000 { compatible = "lsi,mtc"; reg = <0x80 0x80210000 0 0x10000>; - interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; @@ -370,40 +370,45 @@ 0x03000000 0x00000000 0xa0000000 0xc0 0x00000000 0x00 0x40000000>; /* outbound mem */ - interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic 0 57 4>, + <0 0 0 2 &gic 0 57 4>, + <0 0 0 3 &gic 0 57 4>, + <0 0 0 4 &gic 0 57 4>; + interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 59 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 60 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 61 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 62 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 63 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 64 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 65 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 66 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 67 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 68 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 69 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 70 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 71 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 72 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 73 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 74 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 76 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 77 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 78 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 80 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 81 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 82 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 83 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 84 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 85 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 86 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 87 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 88 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 89 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 90 IRQ_TYPE_EDGE_RISING>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/intel/axm56xx.dtsi b/arch/arm64/boot/dts/intel/axm56xx.dtsi index fc82673..e4ecab7 100644 --- a/arch/arm64/boot/dts/intel/axm56xx.dtsi +++ b/arch/arm64/boot/dts/intel/axm56xx.dtsi @@ -301,7 +301,40 @@ 0xc0 0x00000000 0x00 0x40000000>; /* outbound mem */ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 97 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 98 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 99 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 100 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 101 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 102 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 103 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 104 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 105 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 106 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 107 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 108 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 109 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 110 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 111 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 112 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 113 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 114 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 115 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 116 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 117 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 118 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 119 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 120 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 121 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 122 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 123 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 124 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 125 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 126 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 127 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 129 IRQ_TYPE_EDGE_RISING>; status = "disabled"; }; @@ -323,6 +356,11 @@ 0x03000000 0x00000000 0xa0000000 0xc8 0x00000000 0x00 0x40000000>; /* outbound mem */ + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic 0 92 4>, + <0 0 0 2 &gic 0 92 4>, + <0 0 0 3 &gic 0 92 4>, + <0 0 0 4 &gic 0 92 4>; interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; @@ -346,6 +384,11 @@ 0x03000000 0x00000000 0xa0000000 0xd0 0x00000000 0x00 0x40000000>; /* outbound mem */ + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic 0 93 4>, + <0 0 0 2 &gic 0 93 4>, + <0 0 0 3 &gic 0 93 4>, + <0 0 0 4 &gic 0 93 4>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; diff --git a/drivers/pci/host/pcie-axxia.c b/drivers/pci/host/pcie-axxia.c index fb14f1a..1abee65 100644 --- a/drivers/pci/host/pcie-axxia.c +++ b/drivers/pci/host/pcie-axxia.c @@ -440,12 +440,19 @@ static const struct irq_domain_ops axxia_msi_domain_ops = { void axxia_dw_pcie_msi_init(struct pcie_port *pp) { + u64 msi_target; pp->msi_data = __get_free_pages(GFP_KERNEL, 0); + msi_target = virt_to_phys((void *)pp->msi_data); + dev_info(pp->dev, + "%s: MSI addr virt: %lx, phys: %llx\n", + __func__, pp->msi_data, msi_target); /* program the msi_data */ axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4, - virt_to_phys((void *)pp->msi_data)); - axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0); + (u32)(msi_target & 0xffffffff)); + axxia_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, + (u32)(msi_target >> 32 & 0xffffffff)); + } /* MSI int handler */ @@ -480,9 +487,55 @@ static void axxia_pcie_msi_init(struct pcie_port *pp) axxia_dw_pcie_msi_init(pp); } +void axxia_dw_pcie_handle_msi_irq(struct pcie_port *pp, int offset) +{ + unsigned long val; + int i, pos, irq; + + for (i = 0; i < MAX_MSI_CTRLS; i++) { + axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, + (u32 *)&val); + if (val) { + pos = 0; + while ((pos = find_next_bit(&val, 32, pos)) != 32) { + + dev_dbg(pp->dev, + "msi valid i = %d, val = %lx, pos = %d\n", + i, val, pos); + irq = irq_find_mapping(pp->irq_domain, + i * 32 + pos); + axxia_pcie_wr_own_conf(pp, + PCIE_MSI_INTR0_STATUS + i * 12, + 4, 1 << pos); + generic_handle_irq(irq); + pos++; + } + } + } +} + +static void axxia_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pcie_port *pp = irq_desc_get_handler_data(desc); + u32 offset = irq - pp->msi_irqs[0]; + struct irq_chip *chip = irq_desc_get_chip(desc); + + dev_dbg(pp->dev, "%s, irq %d i %d\n", __func__, irq, offset); + + /* + * The chained irq handler installation would have replaced normal + * interrupt driver handler so we need to take care of mask/unmask and + * ack operation. + */ + chained_irq_enter(chip, desc); + axxia_dw_pcie_handle_msi_irq(pp, offset); + chained_irq_exit(chip, desc); +} + static void axxia_pcie_enable_interrupts(struct pcie_port *pp) { u32 val; + int i; /* Unmask */ axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_MASK, &val); @@ -493,9 +546,19 @@ static void axxia_pcie_enable_interrupts(struct pcie_port *pp) axxia_cc_gpreg_writel(pp, val, CC_GPREG_EDG_IRQ_MASK); if (IS_ENABLED(CONFIG_PCI_MSI)) { /* unmask MSI */ - axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_MASK_HI, &val); - val |= MSI_ASSERTED; - axxia_cc_gpreg_writel(pp, val, CC_GPREG_EDG_IRQ_MASK_HI); + if (pp->num_msi_irqs == 0) { + axxia_cc_gpreg_readl(pp, + CC_GPREG_EDG_IRQ_MASK_HI, &val); + val |= MSI_ASSERTED; + axxia_cc_gpreg_writel(pp, val, + CC_GPREG_EDG_IRQ_MASK_HI); + } else { + for (i = 0; i < pp->num_msi_irqs; i++) { + irq_set_chained_handler(pp->msi_irqs[i], + axxia_pcie_msi_irq_handler); + irq_set_handler_data(pp->msi_irqs[i], pp); + } + } axxia_pcie_msi_init(pp); } } @@ -650,12 +713,15 @@ static irqreturn_t axxia_pcie_irq_handler(int irq, void *arg) CC_GPREG_EDG_IRQ_STAT); if (IS_ENABLED(CONFIG_PCI_MSI)) { - axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_STAT_HI, &val); - if (val & MSI_ASSERTED) { - ret = axxia_dw_handle_msi_irq(pp); - axxia_cc_gpreg_writel(pp, MSI_ASSERTED, + if (pp->num_msi_irqs == 0) { + axxia_cc_gpreg_readl(pp, + CC_GPREG_EDG_IRQ_STAT_HI, &val); + if (val & MSI_ASSERTED) { + ret = axxia_dw_handle_msi_irq(pp); + axxia_cc_gpreg_writel(pp, MSI_ASSERTED, CC_GPREG_EDG_IRQ_STAT_HI); - return ret; + return ret; + } } } return IRQ_HANDLED; @@ -672,7 +738,6 @@ static void axxia_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); } - static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, unsigned int nvec, unsigned int pos) { @@ -681,12 +746,7 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base, for (i = 0; i < nvec; i++) { irq_set_msi_desc_off(irq_base, i, NULL); /* Disable corresponding interrupt on MSI controller */ - if (!pp->ops) - dev_err(pp->dev, "ops not set for pcie_port\n"); - if (pp->ops && pp->ops->msi_clear_irq) - pp->ops->msi_clear_irq(pp, pos + i); - else - axxia_dw_pcie_msi_clear_irq(pp, pos + i); + axxia_dw_pcie_msi_clear_irq(pp, pos + i); } bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec)); @@ -740,24 +800,34 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) return -ENOSPC; } +static void axxia_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos) +{ + struct msi_msg msg; + u64 msi_target; + + msi_target = virt_to_phys((void *)pp->msi_data); + msg.address_lo = (u32)(msi_target & 0xffffffff); + msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff); + msg.data = pos; + + pci_write_msi_msg(irq, &msg); +} + static int axxia_dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, struct msi_desc *desc) { int irq, pos; - struct msi_msg msg; struct pcie_port *pp = pdev->bus->sysdata; + if (desc->msi_attrib.is_msix) + return -EINVAL; + irq = assign_irq(1, desc, &pos); if (irq < 0) return irq; - msg.address_lo = virt_to_phys((void *)pp->msi_data); - msg.address_hi = 0x0; - msg.data = pos; - - pci_write_msi_msg(irq, &msg); - + axxia_msi_setup_msg(pp, irq, pos); return 0; } @@ -893,6 +963,16 @@ int axxia_pcie_host_init(struct pcie_port *pp) dev_err(pp->dev, "failed to get irq\n"); return -ENODEV; } + pp->num_msi_irqs = 0; + for (i = 0; i < AXXIA_MSI_IRQL; i++) { + pp->msi_irqs[i] = platform_get_irq(pdev, i+2); + if (pp->msi_irqs[i] <= 0) + break; + pp->num_msi_irqs++; + } + dev_info(pp->dev, "num_msi = %d, irq = %d\n", + pp->num_msi_irqs, pp->irqs); + ret = devm_request_irq(pp->dev, pp->irqs, axxia_pcie_irq_handler, IRQF_SHARED | IRQF_NO_THREAD, "axxia-pcie", pp); if (ret) { diff --git a/drivers/pci/host/pcie-axxia.h b/drivers/pci/host/pcie-axxia.h index ffc8d73..5a965d7 100644 --- a/drivers/pci/host/pcie-axxia.h +++ b/drivers/pci/host/pcie-axxia.h @@ -21,6 +21,7 @@ */ #define MAX_MSI_IRQS 64 #define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32) +#define AXXIA_MSI_IRQL 32 struct pcie_port { struct device *dev; @@ -52,6 +53,8 @@ struct pcie_port { struct pcie_host_ops *ops; int irqs; /* removed 34 not sure why it's there [34]; */ + int msi_irqs[AXXIA_MSI_IRQL]; + int num_msi_irqs; unsigned long msi_data; struct irq_domain *irq_domain; struct msi_controller chip; -- 2.7.4 -- _______________________________________________ linux-yocto mailing list [email protected] https://lists.yoctoproject.org/listinfo/linux-yocto
