From: Suravee Suthikulpanit <suravee.suthikulpa...@amd.com>

This patch remove register index 4 in gic binding, and
introduce the "v2m" subnode. It also changes in the
gic_of_init function to probe for v2m subnode before calling
the gicv2m_of_init.

Besides, this patch also moves the "struct msi_chip" from
"struct gic_chip_data" to "struct v2m_data".

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpa...@amd.com>
Cc: Mark Rutland <mark.rutl...@arm.com>
Cc: Marc Zyngier <marc.zyng...@arm.com>
Cc: Jason Cooper <ja...@lakedaemon.net>
---
 Documentation/devicetree/bindings/arm/gic.txt |  37 +++++++--
 drivers/irqchip/irq-gic-v2m.c                 | 115 +++++++++-----------------
 drivers/irqchip/irq-gic.c                     |  30 +++----
 drivers/irqchip/irq-gic.h                     |  10 +--
 4 files changed, 91 insertions(+), 101 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/gic.txt 
b/Documentation/devicetree/bindings/arm/gic.txt
index d2eea0b..9e38abe 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -12,7 +12,6 @@ Main node required properties:
 
 - compatible : should be one of:
        "arm,gic-400"
-       "arm,gic-400-v2m"
        "arm,cortex-a15-gic"
        "arm,cortex-a9-gic"
        "arm,cortex-a7-gic"
@@ -49,7 +48,6 @@ Main node required properties:
      1   | GIC cpu interface register base and size
      2   | VGIC interface control register base and size (Optional)
      3   | VGIC CPU interface register base and size (Optional)
-     4   | GICv2m MSI interface register base and size (Optional)
 
 Optional
 - interrupts   : Interrupt source of the parent interrupt controller on
@@ -66,9 +64,6 @@ Optional
                  input line is assigned dynamically when the corresponding
                  peripheral's crossbar line is mapped.
 
-- msi-controller : Identifies the node as an MSI controller.
-                   (Required for GICv2m)
-
 Example:
 
        intc: interrupt-controller@fff11000 {
@@ -109,3 +104,35 @@ Example:
                      <0x2c006000 0x2000>;
                interrupts = <1 9 0xf04>;
        };
+
+
+* GICv2m extension for MSI/MSI-x support (Optional)
+
+Certain revision of GIC-400 supports MSI/MSI-x via V2M register frame.
+This is enabled by specifying v2m sub-node.
+
+Required properties:
+
+- msi-controller : Identifies the node as an MSI controller.
+
+- reg : GICv2m MSI interface register base and size
+
+Example:
+
+       interrupt-controller@e1101000 {
+               compatible = "arm,gic-400";
+               #interrupt-cells = <3>;
+               #address-cells = <2>;
+               #size-cells = <2>;
+               interrupt-controller;
+               interrupts = <1 8 0xf04>;
+               ranges = <0 0 0 0xe1100000 0 0x100000>;
+               reg = <0x0 0xe1110000 0 0x01000>,
+                     <0x0 0xe112f000 0 0x02000>,
+                     <0x0 0xe1140000 0 0x10000>,
+                     <0x0 0xe1160000 0 0x10000>;
+               v2m {
+                       msi-controller;
+                       reg = <0x0 0x80000 0 0x1000>;
+               };
+       };
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 57b5a51..1ac0ace 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -42,8 +42,6 @@
 #define V2M_MIN_SPI                    32
 #define V2M_MAX_SPI                    1019
 
-#define GIC_OF_MSIV2M_RANGE_INDEX      4
-
 /*
  * alloc_msi_irq - Allocate MSIs from avaialbe MSI bitmap.
  * @data: Pointer to v2m_data
@@ -85,17 +83,10 @@ static int alloc_msi_irq(struct v2m_data *data, int nvec, 
int *irq)
        return ret;
 }
 
-static struct v2m_data *to_v2m_data(struct msi_chip *chip)
-{
-       struct gic_chip_data *gic = container_of(chip, struct gic_chip_data,
-                                                msi_chip);
-       return &gic->v2m_data;
-}
-
 static void gicv2m_teardown_msi_irq(struct msi_chip *chip, unsigned int irq)
 {
        int pos;
-       struct v2m_data *data = to_v2m_data(chip);
+       struct v2m_data *data = container_of(chip, struct v2m_data, msi_chip);
 
        spin_lock(&data->msi_cnt_lock);
 
@@ -112,7 +103,7 @@ static int gicv2m_setup_msi_irq(struct msi_chip *chip, 
struct pci_dev *pdev,
        int avail, irq = 0;
        struct msi_msg msg;
        phys_addr_t addr;
-       struct v2m_data *data = to_v2m_data(chip);
+       struct v2m_data *data = container_of(chip, struct v2m_data, msi_chip);
 
        if (!desc) {
                dev_err(&pdev->dev,
@@ -141,18 +132,46 @@ static int gicv2m_setup_msi_irq(struct msi_chip *chip, 
struct pci_dev *pdev,
        return 0;
 }
 
-static int __init
-gicv2m_msi_init(struct device_node *node, struct v2m_data *v2m)
+static void gicv2m_mask_irq(struct irq_data *d)
+{
+       gic_mask_irq(d);
+       if (d->msi_desc)
+               mask_msi_irq(d);
+}
+
+static void gicv2m_unmask_irq(struct irq_data *d)
 {
+       gic_unmask_irq(d);
+       if (d->msi_desc)
+               unmask_msi_irq(d);
+}
+
+static struct irq_chip gicv2m_chip;
+
+#ifdef CONFIG_OF
+int __init
+gicv2m_of_init(struct device_node *node, struct gic_chip_data *gic)
+{
+       int ret;
        unsigned int val;
+       struct v2m_data *v2m = &gic->v2m_data;
 
-       if (of_address_to_resource(node, GIC_OF_MSIV2M_RANGE_INDEX,
-                                  &v2m->res)) {
+       v2m->msi_chip.owner = THIS_MODULE;
+       v2m->msi_chip.of_node = node;
+       v2m->msi_chip.setup_irq = gicv2m_setup_msi_irq;
+       v2m->msi_chip.teardown_irq = gicv2m_teardown_msi_irq;
+       ret = of_pci_msi_chip_add(&v2m->msi_chip);
+       if (ret) {
+               pr_info("GICv2m: Failed to add msi_chip.\n");
+               return ret;
+       }
+
+       if (of_address_to_resource(node, 0, &v2m->res)) {
                pr_err("GICv2m: Failed locate GICv2m MSI register frame\n");
                return -EINVAL;
        }
 
-       v2m->base = of_iomap(node, GIC_OF_MSIV2M_RANGE_INDEX);
+       v2m->base = of_iomap(node, 0);
        if (!v2m->base) {
                pr_err("GICv2m: Failed to map GIC MSI registers\n");
                return -EINVAL;
@@ -184,65 +203,13 @@ gicv2m_msi_init(struct device_node *node, struct v2m_data 
*v2m)
        pr_info("GICv2m: SPI range [%d:%d]\n",
                v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
 
-       return 0;
-}
+       memcpy(&gicv2m_chip, gic->irq_chip, sizeof(struct irq_chip));
+       gicv2m_chip.name = "GICv2m",
+       gicv2m_chip.irq_mask = gicv2m_mask_irq;
+       gicv2m_chip.irq_unmask = gicv2m_unmask_irq;
+       gic->irq_chip = &gicv2m_chip;
 
-static void gicv2m_mask_irq(struct irq_data *d)
-{
-       gic_mask_irq(d);
-       if (d->msi_desc)
-               mask_msi_irq(d);
-}
-
-static void gicv2m_unmask_irq(struct irq_data *d)
-{
-       gic_unmask_irq(d);
-       if (d->msi_desc)
-               unmask_msi_irq(d);
+       return 0;
 }
 
-static struct irq_chip gicv2m_chip = {
-       .name                   = "GICv2m",
-       .irq_mask               = gicv2m_mask_irq,
-       .irq_unmask             = gicv2m_unmask_irq,
-       .irq_eoi                = gic_eoi_irq,
-       .irq_set_type           = gic_set_type,
-       .irq_retrigger          = gic_retrigger,
-#ifdef CONFIG_SMP
-       .irq_set_affinity       = gic_set_affinity,
-#endif
-#ifdef CONFIG_PM
-       .irq_set_wake           = gic_set_wake,
-#endif
-};
-
-#ifdef CONFIG_OF
-static int __init
-gicv2m_of_init(struct device_node *node, struct device_node *parent)
-{
-       struct gic_chip_data *gic;
-       int ret;
-
-       ret = _gic_of_init(node, parent, &gicv2m_chip, &gic);
-       if (ret) {
-               pr_err("GICv2m: Failed to initialize GIC\n");
-               return ret;
-       }
-
-       gic->msi_chip.owner = THIS_MODULE;
-       gic->msi_chip.of_node = node;
-       gic->msi_chip.setup_irq = gicv2m_setup_msi_irq;
-       gic->msi_chip.teardown_irq = gicv2m_teardown_msi_irq;
-       ret = of_pci_msi_chip_add(&gic->msi_chip);
-       if (ret) {
-               /*
-               * Note: msi-controller is checked in of_pci_msi_chip_add().
-               * MSI support is optional, and enabled only if msi-controller
-               * is specified. Hence, return 0.
-               */
-               return 0;
-       }
-
-       return gicv2m_msi_init(node, &gic->v2m_data);
-}
 #endif /* CONFIG_OF */
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index cedaeb4..d308d93 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -116,6 +116,7 @@ struct gic_chip_data *irq_data_get_gic_chip_data(struct 
irq_data *d)
 {
        struct gic_chip_data *gic_data;
        struct msi_chip *mchip;
+       struct v2m_data *v2mdat;
 
        /*
         * For MSI, irq_data.chip_data points to struct msi_chip.
@@ -123,7 +124,8 @@ struct gic_chip_data *irq_data_get_gic_chip_data(struct 
irq_data *d)
         */
        if (d->msi_desc) {
                mchip = irq_data_get_irq_chip_data(d);
-               gic_data = container_of(mchip, struct gic_chip_data, msi_chip);
+               v2mdat = container_of(mchip, struct v2m_data, msi_chip);
+               gic_data = container_of(v2mdat, struct gic_chip_data, v2m_data);
        } else {
                gic_data = irq_data_get_irq_chip_data(d);
        }
@@ -989,14 +991,14 @@ void __init gic_init_bases(unsigned int gic_nr, int 
irq_start,
 #ifdef CONFIG_OF
 static int gic_cnt __initdata;
 
-int __init
-_gic_of_init(struct device_node *node, struct device_node *parent,
-            struct irq_chip *chip, struct gic_chip_data **gic)
+static int
+__init gic_of_init(struct device_node *node, struct device_node *parent)
 {
+       struct device_node *child;
        void __iomem *cpu_base;
        void __iomem *dist_base;
        u32 percpu_offset;
-       int irq;
+       int irq, ret;
 
        if (WARN_ON(!node))
                return -ENODEV;
@@ -1010,7 +1012,15 @@ _gic_of_init(struct device_node *node, struct 
device_node *parent,
        if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
                percpu_offset = 0;
 
-       gic_data[gic_cnt].irq_chip = chip;
+       gic_data[gic_cnt].irq_chip = &gic_chip;
+
+       /* Currently, we only support one v2m subnode. */
+       child = of_get_child_by_name(node, "v2m");
+       if (child) {
+               ret = gicv2m_of_init(child, &gic_data[gic_cnt]);
+               if (ret)
+                       return ret;
+       }
 
        gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
        if (!gic_cnt)
@@ -1021,18 +1031,10 @@ _gic_of_init(struct device_node *node, struct 
device_node *parent,
                gic_cascade_irq(gic_cnt, irq);
        }
 
-       if (gic)
-               *gic = &gic_data[gic_cnt];
        gic_cnt++;
        return 0;
 }
 
-static int __init
-gic_of_init(struct device_node *node, struct device_node *parent)
-{
-       return _gic_of_init(node, parent, &gic_chip, NULL);
-}
-
 IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
 IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
 IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
diff --git a/drivers/irqchip/irq-gic.h b/drivers/irqchip/irq-gic.h
index 83aa772..2ec6bc3 100644
--- a/drivers/irqchip/irq-gic.h
+++ b/drivers/irqchip/irq-gic.h
@@ -11,6 +11,7 @@ union gic_base {
 #ifdef CONFIG_ARM_GIC_V2M
 struct v2m_data {
        spinlock_t msi_cnt_lock;
+       struct msi_chip msi_chip;
        struct resource res;      /* GICv2m resource */
        void __iomem *base;       /* GICv2m virt address */
        unsigned int spi_start;   /* The SPI number that MSIs start */
@@ -35,20 +36,13 @@ struct gic_chip_data {
        void __iomem *(*get_base)(union gic_base *);
 #endif
        struct irq_chip *irq_chip;
-       struct msi_chip msi_chip;
 #ifdef CONFIG_ARM_GIC_V2M
        struct v2m_data v2m_data;
 #endif
 };
 
-#ifdef CONFIG_OF
-int _gic_of_init(struct device_node *node,
-                struct device_node *parent,
-                struct irq_chip *chip,
-                struct gic_chip_data **gic) __init;
-#endif
-
 void gic_mask_irq(struct irq_data *d);
 void gic_unmask_irq(struct irq_data *d);
+int gicv2m_of_init(struct device_node *node, struct gic_chip_data *gic) __init;
 
 #endif /* _IRQ_GIC_H_ */
-- 
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to