aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorSuravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>2015-12-10 11:55:30 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2015-12-21 10:43:35 -0500
commit0644b3daca28dcb320373ae20069c269c9386304 (patch)
tree122327cebd0aee36ee4f5049f35c58a87a10279c /drivers/irqchip
parent4266ab1a8ff5715e48b2e89046305864650ce025 (diff)
irqchip/gic-v2m: acpi: Introducing GICv2m ACPI support
This patch introduces gicv2m_acpi_init(), which uses information in MADT GIC MSI frames structure to initialize GICv2m driver. It also exposes gicv2m_init() function, which simplifies callers to a single GICv2m init function. Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Tested-by: Duc Dang <dhdang@apm.com> Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net> Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-gic-v2m.c110
-rw-r--r--drivers/irqchip/irq-gic.c6
2 files changed, 114 insertions, 2 deletions
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 779c3906a22e..7e2975df4473 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -15,9 +15,11 @@
15 15
16#define pr_fmt(fmt) "GICv2m: " fmt 16#define pr_fmt(fmt) "GICv2m: " fmt
17 17
18#include <linux/acpi.h>
18#include <linux/irq.h> 19#include <linux/irq.h>
19#include <linux/irqdomain.h> 20#include <linux/irqdomain.h>
20#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/msi.h>
21#include <linux/of_address.h> 23#include <linux/of_address.h>
22#include <linux/of_pci.h> 24#include <linux/of_pci.h>
23#include <linux/slab.h> 25#include <linux/slab.h>
@@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
138 fwspec.param[0] = 0; 140 fwspec.param[0] = 0;
139 fwspec.param[1] = hwirq - 32; 141 fwspec.param[1] = hwirq - 32;
140 fwspec.param[2] = IRQ_TYPE_EDGE_RISING; 142 fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
143 } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
144 fwspec.fwnode = domain->parent->fwnode;
145 fwspec.param_count = 2;
146 fwspec.param[0] = hwirq;
147 fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
141 } else { 148 } else {
142 return -EINVAL; 149 return -EINVAL;
143 } 150 }
@@ -255,6 +262,8 @@ static void gicv2m_teardown(void)
255 kfree(v2m->bm); 262 kfree(v2m->bm);
256 iounmap(v2m->base); 263 iounmap(v2m->base);
257 of_node_put(to_of_node(v2m->fwnode)); 264 of_node_put(to_of_node(v2m->fwnode));
265 if (is_fwnode_irqchip(v2m->fwnode))
266 irq_domain_free_fwnode(v2m->fwnode);
258 kfree(v2m); 267 kfree(v2m);
259 } 268 }
260} 269}
@@ -373,9 +382,11 @@ static struct of_device_id gicv2m_device_id[] = {
373 {}, 382 {},
374}; 383};
375 384
376int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) 385static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
386 struct irq_domain *parent)
377{ 387{
378 int ret = 0; 388 int ret = 0;
389 struct device_node *node = to_of_node(parent_handle);
379 struct device_node *child; 390 struct device_node *child;
380 391
381 for (child = of_find_matching_node(node, gicv2m_device_id); child; 392 for (child = of_find_matching_node(node, gicv2m_device_id); child;
@@ -411,3 +422,100 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
411 gicv2m_teardown(); 422 gicv2m_teardown();
412 return ret; 423 return ret;
413} 424}
425
426#ifdef CONFIG_ACPI
427static int acpi_num_msi;
428
429static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
430{
431 struct v2m_data *data;
432
433 if (WARN_ON(acpi_num_msi <= 0))
434 return NULL;
435
436 /* We only return the fwnode of the first MSI frame. */
437 data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry);
438 if (!data)
439 return NULL;
440
441 return data->fwnode;
442}
443
444static int __init
445acpi_parse_madt_msi(struct acpi_subtable_header *header,
446 const unsigned long end)
447{
448 int ret;
449 struct resource res;
450 u32 spi_start = 0, nr_spis = 0;
451 struct acpi_madt_generic_msi_frame *m;
452 struct fwnode_handle *fwnode;
453
454 m = (struct acpi_madt_generic_msi_frame *)header;
455 if (BAD_MADT_ENTRY(m, end))
456 return -EINVAL;
457
458 res.start = m->base_address;
459 res.end = m->base_address + SZ_4K;
460
461 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
462 spi_start = m->spi_base;
463 nr_spis = m->spi_count;
464
465 pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
466 spi_start, nr_spis);
467 }
468
469 fwnode = irq_domain_alloc_fwnode((void *)m->base_address);
470 if (!fwnode) {
471 pr_err("Unable to allocate GICv2m domain token\n");
472 return -EINVAL;
473 }
474
475 ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
476 if (ret)
477 irq_domain_free_fwnode(fwnode);
478
479 return ret;
480}
481
482static int __init gicv2m_acpi_init(struct irq_domain *parent)
483{
484 int ret;
485
486 if (acpi_num_msi > 0)
487 return 0;
488
489 acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME,
490 acpi_parse_madt_msi, 0);
491
492 if (acpi_num_msi <= 0)
493 goto err_out;
494
495 ret = gicv2m_allocate_domains(parent);
496 if (ret)
497 goto err_out;
498
499 pci_msi_register_fwnode_provider(&gicv2m_get_fwnode);
500
501 return 0;
502
503err_out:
504 gicv2m_teardown();
505 return -EINVAL;
506}
507#else /* CONFIG_ACPI */
508static int __init gicv2m_acpi_init(struct irq_domain *parent)
509{
510 return -EINVAL;
511}
512#endif /* CONFIG_ACPI */
513
514int __init gicv2m_init(struct fwnode_handle *parent_handle,
515 struct irq_domain *parent)
516{
517 if (is_of_node(parent_handle))
518 return gicv2m_of_init(parent_handle, parent);
519
520 return gicv2m_acpi_init(parent);
521}
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index fcd327f49e8e..644e8bbe130c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1234,7 +1234,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
1234 } 1234 }
1235 1235
1236 if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) 1236 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1237 gicv2m_of_init(node, gic_data[gic_cnt].domain); 1237 gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);
1238 1238
1239 gic_cnt++; 1239 gic_cnt++;
1240 return 0; 1240 return 0;
@@ -1359,6 +1359,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
1359 __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); 1359 __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
1360 1360
1361 acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); 1361 acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
1362
1363 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
1364 gicv2m_init(NULL, gic_data[0].domain);
1365
1362 return 0; 1366 return 0;
1363} 1367}
1364IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 1368IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,