Parse ITS entries in MADT table to probe ITS
Signed-off-by: Hanjun Guo hanjun.guo@linaro.org --- drivers/irqchip/irq-gic-v3-its.c | 54 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index c3652cd..fa2e828 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -15,6 +15,7 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */
+#include <linux/acpi.h> #include <linux/bitmap.h> #include <linux/cpu.h> #include <linux/delay.h> @@ -1567,6 +1568,47 @@ int its_cpu_init(void) return 0; }
+#ifdef CONFIG_ACPI +static struct irq_domain *its_parent __initdata; + +static int __init +gic_acpi_parse_madt_its(struct acpi_subtable_header *header, + const unsigned long end) +{ + struct acpi_madt_generic_translator *its_entry; + struct its_node *its; + + if (BAD_MADT_ENTRY(header, end)) + return -EINVAL; + + its_entry = (struct acpi_madt_generic_translator *)header; + + pr_info("ACPI: ITS: ID: 0x%x\n", its_entry->translation_id); + + /* ITS works as msi controller in ACPI case */ + its = its_probe(its_entry->base_address, 2 * SZ_64K, NULL, its_parent, + true); + if (!IS_ERR(its)) + return 0; + + pr_err("ACPI: failed probing num %d ITS\n", its_entry->translation_id); + return PTR_ERR(its); +} + +void __init its_acpi_probe(struct irq_domain *parent_domain) +{ + int count; + + its_parent = parent_domain; + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR, + gic_acpi_parse_madt_its, 0); + if (count <= 0) + pr_info("No valid GIC ITS entries exist\n"); +} +#else +static inline void __init its_acpi_probe(struct irq_domain *parent_domain) { } +#endif + static struct of_device_id its_device_id[] = { { .compatible = "arm,gic-v3-its", }, {}, @@ -1575,11 +1617,15 @@ static struct of_device_id its_device_id[] = { int __init its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *parent_domain) { - struct device_node *np; + if (node) { + struct device_node *np;
- for (np = of_find_matching_node(node, its_device_id); np; - np = of_find_matching_node(np, its_device_id)) { - its_of_probe(np, parent_domain); + for (np = of_find_matching_node(node, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + its_of_probe(np, parent_domain); + } + } else { + its_acpi_probe(parent_domain); }
if (list_empty(&its_nodes)) {