diff options
author | Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> | 2015-12-10 11:55:30 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-12-21 10:43:35 -0500 |
commit | 0644b3daca28dcb320373ae20069c269c9386304 (patch) | |
tree | 122327cebd0aee36ee4f5049f35c58a87a10279c /drivers/irqchip | |
parent | 4266ab1a8ff5715e48b2e89046305864650ce025 (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.c | 110 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic.c | 6 |
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 | ||
376 | int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) | 385 | static 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 | ||
427 | static int acpi_num_msi; | ||
428 | |||
429 | static 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 | |||
444 | static int __init | ||
445 | acpi_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 | |||
482 | static 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 | |||
503 | err_out: | ||
504 | gicv2m_teardown(); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | #else /* CONFIG_ACPI */ | ||
508 | static int __init gicv2m_acpi_init(struct irq_domain *parent) | ||
509 | { | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | #endif /* CONFIG_ACPI */ | ||
513 | |||
514 | int __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 | } |
1364 | IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, | 1368 | IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, |