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

Reply via email to