From: Palani <palaniappan.ramanat...@intel.com>

Implemented the MSI domain ops to support Multiple MSI interrupts
in X9 and XLF. Added support for MSI-X interrupts for all the
PEI(0/1/2) host controllers in X9.

Signed-off-by: Palani <palaniappan.ramanat...@intel.com>
---
 drivers/pci/host/pcie-axxia.c | 465 ++++++++++++++++++++++++++++++------------
 drivers/pci/host/pcie-axxia.h |   5 +-
 2 files changed, 338 insertions(+), 132 deletions(-)

diff --git a/drivers/pci/host/pcie-axxia.c b/drivers/pci/host/pcie-axxia.c
index 99c9020..bab3d77 100644
--- a/drivers/pci/host/pcie-axxia.c
+++ b/drivers/pci/host/pcie-axxia.c
@@ -28,9 +28,12 @@
 #include <linux/axxia-pei.h>
 #include <linux/time.h>
 #include <linux/lsi-ncr.h>
+#include <asm-generic/msi.h>
 
 #include "pcie-axxia.h"
 
+#define AXXIA_GENERIC_MSI_DOMAIN_IRQ 1
+
 #define PEI_GENERAL_CORE_CTL_REG 0x38
 #define PEI_SII_PWR_MGMT_REG 0xD4
 #define PEI_SII_DBG_0_MON_REG 0xEC
@@ -114,6 +117,9 @@
 #define PCIE_MSIX_INTR0_ENABLE 0xb4
 #define PCIE_MSIX_INTR0_STATUS 0xb0
 
+#define AXI_GPREG_EDG_IRQ_STAT_HI                 0x3a0
+#define AXI_GPREG_EDG_IRQ_MASK_HI                 0x3a4
+#define MSIX_ASSERTED                    (0x1 << 8)
 /* SYSCON */
 #define AXXIA_SYSCON_BASE             0x8002C00000
 
@@ -468,6 +474,222 @@ static struct pci_ops axxia_pciex_pci_ops = {
        .write = axxia_pciex_write_config,
 };
 
+static void axxia_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val &= ~(1 << bit);
+       axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
+static void axxia_dw_pcie_msix_set_irq(struct pcie_port *pp, int irq, int mask)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 16) * 12;
+       bit = irq % 16;
+       axxia_axi_gpreg_readl(pp, PCIE_MSIX_INTR0_ENABLE + res, &val);
+       if (mask)
+               val |= 1 << bit;
+       else
+               val &= ~(1 << bit);
+       axxia_axi_gpreg_writel(pp, val, PCIE_MSIX_INTR0_ENABLE + res);
+       bit = irq % 32;
+       axxia_axi_gpreg_readl(pp, PEI_MSIX_INTR_ENABLE + res, &val);
+       if (mask)
+               val |= 1 << bit;
+       else
+               val &= ~(1 << bit);
+       axxia_axi_gpreg_writel(pp, val, PEI_MSIX_INTR_ENABLE + res);
+}
+
+static void axxia_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+       unsigned int res, bit, val;
+
+       res = (irq / 32) * 12;
+       bit = irq % 32;
+       axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+       val |= 1 << bit;
+       axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
+static int axxia_check_set_msi_mode(struct pcie_port *pp, u32 is_msix)
+{
+       u32 val;
+
+       if (pp->msi_mode == AXXIA_MSI_UNCONFIGURED) {
+               if (is_msix) {
+                       axxia_axi_gpreg_readl(pp, AXI_GPREG_MSTR, &val);
+                       val &= ~CFG_MSI_MODE;
+                       axxia_axi_gpreg_writel(pp, val, AXI_GPREG_MSTR);
+                       pp->msi_mode = AXXIA_MSIX_MODE;
+               } else {
+                       axxia_axi_gpreg_readl(pp, AXI_GPREG_MSTR, &val);
+                       val |= CFG_MSI_MODE;
+                       axxia_axi_gpreg_writel(pp, val, AXI_GPREG_MSTR);
+                       pp->msi_mode = AXXIA_MSI_MODE;
+               }
+       } else {
+               if ((is_msix && (pp->msi_mode == AXXIA_MSI_MODE)) ||
+                       ((!is_msix) && (pp->msi_mode == AXXIA_MSIX_MODE))) {
+                       dev_info(pp->dev,
+                       "Axxia already in %s mode, %s not supported\n",
+                       pp->msi_mode == AXXIA_MSI_MODE ? "MSI" : "MSIX",
+                       pp->msi_mode == AXXIA_MSI_MODE ? "MSIX" : "MSI");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+
+#ifdef AXXIA_GENERIC_MSI_DOMAIN_IRQ
+static struct irq_chip axxia_msi_top_irq_chip = {
+       .name = "PCI-MSI",
+};
+
+static struct msi_domain_info axxia_msi_domain_info = {
+       .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+                  MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
+       .chip   = &axxia_msi_top_irq_chip,
+};
+
+static void axxia_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+       struct pcie_port *pp = irq_data_get_irq_chip_data(data);
+       u64 msi_target = virt_to_phys((void *)pp->msi_data);
+
+       if (pp->msi_mode == AXXIA_MSIX_MODE) {
+               msi_target = msi_target + (data->hwirq * 4);
+               msg->address_lo = (u32)(msi_target & 0xffffffff);
+               msg->address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+               msg->data = 0x12345678;
+       } else {
+               msg->address_lo = (u32)(msi_target & 0xffffffff);
+               msg->address_hi = (u32)(msi_target >> 32 & 0xffffffff);
+               msg->data = data->hwirq;
+       }
+
+}
+
+static int axxia_irq_set_affinity(struct irq_data *data,
+                                 const struct cpumask *mask, bool force)
+{
+       return -EINVAL;
+}
+
+static struct irq_chip axxia_msi_bottom_irq_chip = {
+       .name                   = "MSI",
+       .irq_compose_msi_msg    = axxia_compose_msi_msg,
+       .irq_set_affinity       = axxia_irq_set_affinity,
+};
+
+static int axxia_pcie_irq_domain_alloc(struct irq_domain *domain,
+               unsigned int virq, unsigned int nr_irqs, void *args)
+{
+       struct pcie_port *pp = domain->host_data;
+       int msi_irq;
+       unsigned i;
+       msi_alloc_info_t *va = args;
+       struct msi_desc *desc = va->desc;
+       int is_msix = 0;
+
+       if (desc) {
+               if (desc->msi_attrib.is_msix)
+                       is_msix = 1;
+               else
+                       is_msix = 0;
+       } else {
+               dev_err(pp->dev, "msi_desc not set.. Default to MSI\n");
+               is_msix = 0;
+       }
+
+       mutex_lock(&pp->bitmap_lock);
+
+       msi_irq = bitmap_find_next_zero_area(pp->bitmap, MAX_MSI_IRQS,
+                                       0, nr_irqs, 0);
+
+       if (((is_msix == 0) && (msi_irq < 32)) ||
+               (is_msix && (msi_irq < MAX_MSI_IRQS)))
+               bitmap_set(pp->bitmap, msi_irq, nr_irqs);
+       else
+               msi_irq = -ENOSPC;
+
+       mutex_unlock(&pp->bitmap_lock);
+       if (msi_irq < 0)
+               return msi_irq;
+
+       axxia_check_set_msi_mode(pp, is_msix);
+       for (i = 0; i < nr_irqs; i++) {
+               irq_domain_set_info(domain, virq + i, msi_irq + i,
+                                   &axxia_msi_bottom_irq_chip,
+                                   domain->host_data, handle_simple_irq, NULL,
+                                   NULL);
+               if (is_msix)
+                       axxia_dw_pcie_msix_set_irq(pp, msi_irq + i, 1);
+               else
+                       axxia_dw_pcie_msi_set_irq(pp, msi_irq + i);
+       }
+       return 0;
+}
+
+static void axxia_pcie_irq_domain_free(struct irq_domain *domain,
+                                 unsigned int virq, unsigned int nr_irqs)
+{
+       struct pcie_port *pp = domain->host_data;
+       struct irq_data *data = irq_domain_get_irq_data(domain, virq);
+       int i;
+
+       mutex_lock(&pp->bitmap_lock);
+       bitmap_clear(pp->bitmap, data->hwirq, nr_irqs);
+       mutex_unlock(&pp->bitmap_lock);
+
+       for (i = 0; i < nr_irqs; i++) {
+               if (pp->msi_mode == AXXIA_MSIX_MODE)
+                       axxia_dw_pcie_msix_set_irq(pp, data->hwirq + i, 0);
+               else
+                       axxia_dw_pcie_msi_clear_irq(pp, data->hwirq + i);
+       }
+       if (bitmap_empty(pp->bitmap, MAX_MSI_IRQS))
+               pp->msi_mode = AXXIA_MSI_UNCONFIGURED;
+       irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+static const struct irq_domain_ops axxia_msi_domain_ops = {
+       .alloc  = axxia_pcie_irq_domain_alloc,
+       .free   = axxia_pcie_irq_domain_free,
+};
+
+static int axxia_pcie_allocate_domains(struct pcie_port *pp)
+{
+       pp->irq_domain = irq_domain_add_linear(NULL, MAX_MSI_IRQS,
+                                                  &axxia_msi_domain_ops, pp);
+       if (!pp->irq_domain)
+               return -ENOMEM;
+
+       pp->chip.domain = pci_msi_create_irq_domain(NULL,
+                                                    &axxia_msi_domain_info,
+                                                    pp->irq_domain);
+
+       if (!pp->chip.domain) {
+               irq_domain_remove(pp->irq_domain);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void axxia_free_domains(struct pcie_port *pp)
+{
+       if (pp->chip.domain)
+               irq_domain_remove(pp->chip.domain);
+       if (pp->irq_domain)
+               irq_domain_remove(pp->irq_domain);
+}
+#else
 static struct irq_chip axxia_dw_msi_irq_chip = {
        .name = "PCI-MSI",
        .irq_enable = pci_msi_unmask_irq,
@@ -490,8 +712,7 @@ static int axxia_dw_pcie_msi_map(struct irq_domain *domain, 
unsigned int irq,
 static const struct irq_domain_ops axxia_msi_domain_ops = {
        .map = axxia_dw_pcie_msi_map,
 };
-
-
+#endif
 void axxia_dw_pcie_msi_init(struct pcie_port *pp)
 {
        u64 msi_target;
@@ -519,66 +740,59 @@ static void axxia_pcie_msi_init(struct pcie_port *pp)
 }
 
 /* MSI int handler */
-static int axxia_dw_pcie_handle_msi_irq(struct pcie_port *pp, int offset)
+static int axxia_dw_pcie_handle_msi_irq(struct pcie_port *pp, u32 va)
 {
-       unsigned long val;
+       unsigned long val = va;
        int i, pos, irq;
        int ret = 0;
-
-       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) {
-                       ret = 1;
-                       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++;
-                       }
+       i = 0;
+       if (val) {
+               ret = 1;
+               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++;
                }
        }
        return ret;
 }
 
 /* MSIx int handler */
-static void axxia_dw_pcie_handle_msix_irq(struct pcie_port *pp, int offset)
+int axxia_dw_pcie_handle_msix_irq(struct pcie_port *pp, int offset)
 {
-       unsigned long val, val1;
+       unsigned long val;
        int i, pos, irq;
+       int ret;
 
-       axxia_axi_gpreg_readl(pp, PEI_MSIX_INTR_STATUS,
-                       (u32 *)&val1);
-       if (val1) {
-               for (i = 0; i < MAX_MSI_CTRLS*2; i++) {
-                       axxia_axi_gpreg_readl(pp,
-                                PCIE_MSIX_INTR0_STATUS + i * 12,
-                                                       (u32 *)&val);
-
-                       if (val) {
-                               pos = 0;
-                               while ((pos = find_next_bit(&val, 16, pos))
-                                                                != 16) {
-                                       irq = irq_find_mapping(pp->irq_domain,
-                                                       i * 16 + pos);
-                                       axxia_axi_gpreg_writel(pp, 1 << pos,
-                                       PCIE_MSIX_INTR0_STATUS + i * 12);
-                                       generic_handle_irq(irq);
-                                       pos++;
-                               }
-                       }
+       i = offset;
+       axxia_axi_gpreg_readl(pp,
+                PCIE_MSIX_INTR0_STATUS + i * 12, (u32 *)&val);
+
+       if (val) {
+               ret = 1;
+               pos = 0;
+               while ((pos = find_next_bit(&val, 16, pos))
+                                                != 16) {
+                       irq = irq_find_mapping(pp->irq_domain,
+                                       i * 16 + pos);
+                       axxia_axi_gpreg_writel(pp, 1 << pos,
+                               PCIE_MSIX_INTR0_STATUS + i * 12);
+                       generic_handle_irq(irq);
+                       pos++;
                }
-
-       axxia_axi_gpreg_writel(pp,  val1, PEI_MSIX_INTR_STATUS);
        }
+
+       axxia_axi_gpreg_writel(pp,  1 << i, PEI_MSIX_INTR_STATUS);
+       return ret;
 }
 
 static void axxia_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
@@ -586,8 +800,9 @@ 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);
+       u32 val1;
 
-       dev_dbg(pp->dev, "%s, irq %d i %d\n", __func__, irq, offset);
+       dev_dbg(pp->dev, "%s, irq %d of=%d\n", __func__, irq, offset);
 
        /*
         * The chained irq handler installation would have replaced normal
@@ -595,8 +810,17 @@ static void axxia_pcie_msi_irq_handler(unsigned int irq, 
struct irq_desc *desc)
         * ack operation.
         */
        chained_irq_enter(chip, desc);
-       axxia_dw_pcie_handle_msi_irq(pp, offset);
-       axxia_dw_pcie_handle_msix_irq(pp, offset);
+       if (offset == 0) {
+               axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS, 4,
+                               (u32 *)&val1);
+               if (val1)
+                       axxia_dw_pcie_handle_msi_irq(pp, val1);
+       }
+
+       axxia_axi_gpreg_readl(pp, PEI_MSIX_INTR_STATUS,
+                                       (u32 *)&val1);
+       if ((val1) & (1 << offset))
+               axxia_dw_pcie_handle_msix_irq(pp, offset);
        chained_irq_exit(chip, desc);
 }
 
@@ -620,6 +844,12 @@ static void axxia_pcie_enable_interrupts(struct pcie_port 
*pp)
                        val |= MSI_ASSERTED;
                        axxia_cc_gpreg_writel(pp, val,
                                CC_GPREG_EDG_IRQ_MASK_HI);
+                       axxia_axi_gpreg_readl(pp,
+                               AXI_GPREG_EDG_IRQ_MASK_HI, &val);
+                       val |= MSIX_ASSERTED;
+                       axxia_axi_gpreg_writel(pp, val,
+                               AXI_GPREG_EDG_IRQ_MASK_HI);
+
                } else {
                        for (i = 0; i < pp->num_msi_irqs; i++) {
                                irq_set_chained_handler(pp->msi_irqs[i],
@@ -1058,8 +1288,9 @@ static int axxia_pcie_establish_link(struct pcie_port *pp)
 static irqreturn_t axxia_pcie_irq_handler(int irq, void *arg)
 {
        struct pcie_port *pp = arg;
-       u32 val;
-       int ret;
+       u32 val, val1;
+       int i;
+       int ret = 0;
        u32 offset;
 
        axxia_cc_gpreg_readl(pp, CC_GPREG_EDG_IRQ_STAT, &val);
@@ -1089,49 +1320,39 @@ static irqreturn_t axxia_pcie_irq_handler(int irq, void 
*arg)
                        axxia_cc_gpreg_readl(pp,
                                CC_GPREG_EDG_IRQ_STAT_HI, &val);
                        if (val & MSI_ASSERTED) {
-                               ret = axxia_dw_pcie_handle_msi_irq(pp, offset);
+                               axxia_pcie_rd_own_conf(pp,
+                               PCIE_MSI_INTR0_STATUS, 4, (u32 *)&val1);
+                               if (val1)
+                                       ret = axxia_dw_pcie_handle_msi_irq(pp,
+                                                                        val1);
                                axxia_cc_gpreg_writel(pp, MSI_ASSERTED,
                                              CC_GPREG_EDG_IRQ_STAT_HI);
                                if (!ret)
                                        return IRQ_NONE;
                        }
+                       axxia_axi_gpreg_readl(pp,
+                               AXI_GPREG_EDG_IRQ_STAT_HI, &val);
+                       if (val & MSIX_ASSERTED) {
+                               axxia_axi_gpreg_readl(pp, PEI_MSIX_INTR_STATUS,
+                                                               (u32 *)&val1);
+                               for (i = 0 ; i < 32; i++) {
+                                       if ((val1) & (1 << i))
+                                               ret =
+                                               axxia_dw_pcie_handle_msix_irq(
+                                                               pp, i);
+                               }
+                               axxia_axi_gpreg_writel(pp, MSIX_ASSERTED,
+                                             AXI_GPREG_EDG_IRQ_STAT_HI);
+                               if (!ret)
+                                       return IRQ_NONE;
+                       }
+
                }
        }
        return IRQ_HANDLED;
 }
 
-static void axxia_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
-{
-       unsigned int res, bit, val;
-
-       res = (irq / 32) * 12;
-       bit = irq % 32;
-       axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-       val &= ~(1 << bit);
-       axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
-}
-
-static void axxia_dw_pcie_msix_set_irq(struct pcie_port *pp, int irq, int mask)
-{
-       unsigned int res, bit, val;
-
-       res = (irq / 16) * 12;
-       bit = irq % 16;
-       axxia_axi_gpreg_readl(pp, PCIE_MSIX_INTR0_ENABLE + res, &val);
-       if (mask)
-               val |= 1 << bit;
-       else
-               val &= ~(1 << bit);
-       axxia_axi_gpreg_writel(pp, val, PCIE_MSIX_INTR0_ENABLE + res);
-       bit = irq % 32;
-       axxia_axi_gpreg_readl(pp, PEI_MSIX_INTR_ENABLE + res, &val);
-       if (mask)
-               val |= 1 << bit;
-       else
-               val &= ~(1 << bit);
-       axxia_axi_gpreg_writel(pp, val, PEI_MSIX_INTR_ENABLE + res);
-}
-
+#ifndef AXXIA_GENERIC_MSI_DOMAIN_IRQ
 static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
                unsigned int nvec, unsigned int pos, u32 is_msix)
 {
@@ -1152,17 +1373,6 @@ static void clear_irq_range(struct pcie_port *pp, 
unsigned int irq_base,
                pp->msi_mode = AXXIA_MSI_UNCONFIGURED;
 }
 
-static void axxia_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
-{
-       unsigned int res, bit, val;
-
-       res = (irq / 32) * 12;
-       bit = irq % 32;
-       axxia_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
-       val |= 1 << bit;
-       axxia_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
-}
-
 
 static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
 {
@@ -1208,35 +1418,6 @@ no_valid_irq:
        return -ENOSPC;
 }
 
-static int axxia_check_set_msi_mode(struct pcie_port *pp, u32 is_msix)
-{
-       u32 val;
-
-       if (pp->msi_mode == AXXIA_MSI_UNCONFIGURED) {
-               if (is_msix) {
-                       axxia_axi_gpreg_readl(pp, AXI_GPREG_MSTR, &val);
-                       val &= ~CFG_MSI_MODE;
-                       axxia_axi_gpreg_writel(pp, val, AXI_GPREG_MSTR);
-                       pp->msi_mode = AXXIA_MSIX_MODE;
-               } else {
-                       axxia_axi_gpreg_readl(pp, AXI_GPREG_MSTR, &val);
-                       val |= CFG_MSI_MODE;
-                       axxia_axi_gpreg_writel(pp, val, AXI_GPREG_MSTR);
-                       pp->msi_mode = AXXIA_MSI_MODE;
-               }
-       } else {
-               if ((is_msix && (pp->msi_mode == AXXIA_MSI_MODE)) ||
-                       ((!is_msix) && (pp->msi_mode == AXXIA_MSIX_MODE))) {
-                       dev_info(pp->dev,
-                       "Axxia already in %s mode, %s not supported\n",
-                       pp->msi_mode == AXXIA_MSI_MODE ? "MSI" : "MSIX",
-                       pp->msi_mode == AXXIA_MSI_MODE ? "MSIX" : "MSI");
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-
 static void axxia_msi_setup_msg(struct pcie_port *pp, unsigned int irq,
                                        u32 pos, u32 is_msix)
 {
@@ -1296,7 +1477,7 @@ static struct msi_controller axxia_dw_pcie_msi_chip = {
        .setup_irq = axxia_dw_msi_setup_irq,
        .teardown_irq = axxia_dw_msi_teardown_irq,
 };
-
+#endif
 int axxia_pcie_host_init(struct pcie_port *pp)
 {
        struct device_node *np = pp->dev->of_node;
@@ -1427,7 +1608,23 @@ int axxia_pcie_host_init(struct pcie_port *pp)
                dev_err(pp->dev, "failed to request irq\n");
                return ret;
        }
+#ifdef AXXIA_GENERIC_MSI_DOMAIN_IRQ
+       ret = BITS_TO_LONGS(MAX_MSI_IRQS) * sizeof(long);
+       pp->bitmap = kzalloc(ret, GFP_KERNEL);
+       if (!pp->bitmap) {
+               dev_err(pp->dev, "PCIE: Error allocating MSI bitmap\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&pp->bitmap_lock);
 
+
+       ret = axxia_pcie_allocate_domains(pp);
+       if (ret) {
+               pr_err("PCIE: Failed to create MSI IRQ domain\n");
+               return ret;
+       }
+#else
        if (IS_ENABLED(CONFIG_PCI_MSI)) {
                pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
                                        MAX_MSI_IRQS, &axxia_msi_domain_ops,
@@ -1440,23 +1637,31 @@ int axxia_pcie_host_init(struct pcie_port *pp)
                for (i = 0; i < MAX_MSI_IRQS; i++)
                        irq_create_mapping(pp->irq_domain, i);
        }
-
+#endif
        axxia_pcie_enable_interrupts(pp);
 
        bus = pci_create_root_bus(&pdev->dev, pp->root_bus_nr,
                                  &axxia_pciex_pci_ops, pp, &res);
        if (!bus)
-               return 1;
+               goto fail_ret;
 #ifdef CONFIG_PCI_MSI
        pp->msi_mode = AXXIA_MSI_UNCONFIGURED;
+#ifdef AXXIA_GENERIC_MSI_DOMAIN_IRQ
+       bus->msi = &pp->chip;
+#else
        bus->msi = &axxia_dw_pcie_msi_chip;
 #endif
-
+#endif
        pci_scan_child_bus(bus);
        pci_assign_unassigned_bus_resources(bus);
        pci_bus_add_devices(bus);
 
        return 0;
+fail_ret:
+#ifdef AXXIA_GENERIC_MSI_DOMAIN_IRQ
+       axxia_free_domains(pp);
+#endif
+       return 1;
 }
 
 static int axxia_pcie_probe(struct platform_device *pdev)
diff --git a/drivers/pci/host/pcie-axxia.h b/drivers/pci/host/pcie-axxia.h
index 2fa15f6..4624a4d 100644
--- a/drivers/pci/host/pcie-axxia.h
+++ b/drivers/pci/host/pcie-axxia.h
@@ -19,8 +19,7 @@
  * it 32 as of now. Probably we will never need more than 32. If needed,
  * then increment it in multiple of 32.
  */
-#define MAX_MSI_IRQS                   64
-#define MAX_MSI_CTRLS                  (MAX_MSI_IRQS / 32)
+#define MAX_MSI_IRQS                   256
 #define AXXIA_MSI_IRQL                 32
 #define AXXIA_MSI_UNCONFIGURED         0
 #define AXXIA_MSI_MODE                 1
@@ -62,6 +61,8 @@ struct pcie_port {
        u32                     msi_mode;
        unsigned long           msi_data;
        struct irq_domain       *irq_domain;
+       struct mutex            bitmap_lock;
+       unsigned long           *bitmap;
        struct msi_controller chip;
        DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
 #if 0
-- 
2.7.4

-- 
_______________________________________________
linux-yocto mailing list
linux-yocto@yoctoproject.org
https://lists.yoctoproject.org/listinfo/linux-yocto

Reply via email to