@@ -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>;
+ };
+ };
@@ -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 */
@@ -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);
@@ -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_ */