From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752954AbbLIBtV (ORCPT ); Tue, 8 Dec 2015 20:49:21 -0500 Received: from mail-by2on0091.outbound.protection.outlook.com ([207.46.100.91]:5856 "EHLO na01-by2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752647AbbLIBsf (ORCPT ); Tue, 8 Dec 2015 20:48:35 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Suravee.Suthikulpanit@amd.com; From: Suravee Suthikulpanit To: , , , CC: Lorenzo Pieralisi , Will Deacon , Catalin Marinas , , , , , , , , Suravee Suthikulpanit Subject: [PATCH v5 5/5] gicv2m: acpi: Introducing GICv2m ACPI support Date: Tue, 8 Dec 2015 17:48:06 -0800 Message-ID: <1449625686-5594-6-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: BLUPR05CA0068.namprd05.prod.outlook.com (10.141.20.38) To BY1PR12MB0437.namprd12.prod.outlook.com (25.162.147.139) X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;2:ZcChQE/hPTswTvEtlfKq7RYBNphRP4vazRXGfBRApPtuPl27awcG5V2Ml1nINFrimvijwhJqCYV//K/heBd2TmAiznTHZwvXIeSTPuSXzNFGSODxUF9Ur1beYFK74X8fhTqdFaJcW1hGxVxqNhLfIw==;3:SNR3jsMQQysdfbhEH76KwP6NxlPmJHuGcwM3P/p5wIpw0kWAf/p7/nhpkSukyMUSPtQISe7mHuv7jODomHFacteyeui+y5jQHZAsX7+NmYrm1vCQ/CdmMdkg9YXFqBa4;25:CGWICTzWaeEVn+Qx5WPGZaPGy4ilV33Dek+OHOY5wzz7O8SpYMRSNYYLZfK/X5XF8oJp8/i+IBAU2vfniMhopd+OORU+HhEKsxncLoMxa6tCqdVyauT4fNO1XEIl2LdUPvmyp4QwpVrZDkmF4Petl0tKHSHobdf0xHMerYitb8Q5OijeBNPIzlduvHbX41Rk7LGfoSwWh/+rOZTVbsTazBGc5Kre8sAA12oX5xlJLHnJId/weI52QkSGQcj6tyr20bhHzM7VLlrB90FGSI0nSQ== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY1PR12MB0437; X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;20:REo5bR9OhvUL7WEQD7y9Pa5NHuIJlEdM1BPjpdhGv9vH/Nb29SyU4N3/8TZswREO8J8E6wIxRx88Ptgq/Lhwzibz2xHOBGq446QtS4TcQw4WPSnoaunTfeWQspI7D2VCy11XZXeK50EZwYEh4jPPDQgLEsi3IjZ3tX5hPSsrCjDFkFcDHVZJQG3vNhCp8kmsY9vEX2D+Y3C1u6vF6HSaanLPHI/KIZ7gXGUYAEBdxMA81RJxtriQknxB6LzQIvZilTxvAGesNyT5j7/9F2RsCwTMsu1gBTtPtsSHKEanYYsVOx7SC+Lh091SR6JEMwn3zIrkowCXe7I4utcCojpsH6u1SS5HMKJpxOi3X5zIG08hTIk6L8+9yepzWFazZs4WoGjoB1vU25LRxlRUQAqCW18cEZHdARKUsgKQyxH/L0Q0dRXDxfAmx2UFCfpcNTq6MrmC92TzKHD79oBe1xZC7BX31r2vSAPr8/5hX4dSH2oIN5Ja+lH1cm/d9ATJzZ0k;4:/pyBjQKLGysy0KYE2ZzeWg6qoRtUklE8ozC08Fgi/cL5kMY5l1R5exjSaP3rckAPZ8SG5A21assChYEBto/kYJ2BN8qAFnuFyMd+cxP/DZbpgn5Tx/0HwduZMTo2lVomA386DkSEVZUXPP97WG9wh82Cnwyh6Bp0xR0TTL8zssmVfsXkfZSeX+v9l+tpqzTutoJeNKSvTabelCKJGJ3A7ZEk6UTAfT8+QzCFDwGvdGo6ImYXILVV7Cd//ytmKZMr1sgqiVm73DStTX/IGgImlTI2GgABZ2rBWqbfLBPRdIwy8JLDoqc76VAXc2CP4wnU+O/JIyhyMW189WeJjKKs2wgY1Ufm6hj46Oueo9fAKmVJxG+2Ud3JdPtkNFZje+HBv38Ob4BGibYp8mdKtEM+AC7IAtGxbLwsiBl2CWJNAXI= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(520078)(5005006)(8121501046)(3002001)(10201501046);SRVR:BY1PR12MB0437;BCL:0;PCL:0;RULEID:;SRVR:BY1PR12MB0437; X-Forefront-PRVS: 0785459C39 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(6009001)(189002)(199003)(36756003)(77096005)(2950100001)(86362001)(229853001)(92566002)(101416001)(53416004)(122386002)(97736004)(2201001)(42186005)(87976001)(5001770100001)(19580405001)(5004730100002)(50226001)(48376002)(19580395003)(1096002)(47776003)(189998001)(50986999)(66066001)(5003940100001)(106356001)(5008740100001)(6116002)(50466002)(3846002)(586003)(76176999)(105586002)(40100003);DIR:OUT;SFP:1101;SCL:1;SRVR:BY1PR12MB0437;H:ssuthiku-fedora-lt.amd.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BY1PR12MB0437;23:maFqAsKc2kESLMOtz8ovya3X5zi40vJdXkKvpHvyF?= =?us-ascii?Q?kCA1KRBzfhx9WFCw/pO5fSg3XJ5Co02oKmg3vw50RYnhTHsryS6VStGQnSyp?= =?us-ascii?Q?HznUwgvf0VPkEEIPqF2JYYLtZjBSHEaGBBAKyfD8wiwGhus6PrdobSB93sU3?= =?us-ascii?Q?qeHOwB54g7cER6NdrRcT+QDrjW8qBV/bTS/xTe0PaGnQ9HF41ejoHYudUxZG?= =?us-ascii?Q?1v7bFgq/gGi5MVeAYsvgEHEyxDDK9JGBeCMZM61+NaWKtXQgvt27ywM+vPKU?= =?us-ascii?Q?3cuLu8wUdlqNlwYwlPl/Re/6pFz0jQEoM5/gEdxWMcRz2q2vywgMx0CG2MGK?= =?us-ascii?Q?eZHFlaTsSf5ZXhxdpvghuGO/LyKpfHqA0nc4rxhDgD1WxvK1fkDH65Ez/TGk?= =?us-ascii?Q?BG6AtJ6+fuauOi6XozlpvSDMhbl7x+IHdO6gMQS4EZzQz/dkzOiT3RdHHm5k?= =?us-ascii?Q?jMQw2LUnKAommxMIKt/x14iSGCx0dEwdUfy5kCnbmLfSTfOJF8zv6TGI7khg?= =?us-ascii?Q?o8CwaFjSwtEklstGMGWKDvwZiShHdl3rm1CTu12KPNPpB+3l4eN4I898K566?= =?us-ascii?Q?IMfz1381MyU/NvJ9U1z0zqzXsXd2bguMNWB3eeYoy7mlgC0nXX5az12jvhtL?= =?us-ascii?Q?tEfcY5oV0AFjNrT01jSldspsX7vGB7qCbfOxVQX4lzWhJOWolpwIdWJ415rS?= =?us-ascii?Q?BAzfkDaXAse0qahuD5yW6lJMvLzNT8n9MK7hpl8SLrloqvG3su3jb/Gw9o5Z?= =?us-ascii?Q?4znWNHKMeQJuROlar2fHsavICe4vGIk0B3/LWZ2/MjWoiTuG1se6vbCSUl9m?= =?us-ascii?Q?mWtEMlpFlOc0LJSnkb0I5cWjdefyL0bBhHzFA3erR4JpROTA7hxnHwuWpjZ/?= =?us-ascii?Q?0OJKR13GBKqgKsmt/W3ZYZu6dKshPFPJSoYoAGYTlb4QkUH+2iFITXFRUWbI?= =?us-ascii?Q?XI73OLtgmdCg9uMWdc2Zg/CvMkVVncUsT1zbwzCDz7CX2oW9FjlccIETncSl?= =?us-ascii?Q?Pg=3D?= X-Microsoft-Exchange-Diagnostics: 1;BY1PR12MB0437;5:dUoyAQO7h0fWpIAbRpgztZo0R7WkZbjgRyFWwAHiI5kv4Zyno57pxn4JRAXPfWgyZB1Ph4P+E+vV7yoz7fSBDNaaifBEyxX1N4qMajIz2tVrsCqjmzrrxkux0iapZSvIe9VqedVUQ3dncD6CKNECEw==;24:6m//4p86il2HfeFgmQ4xzhHAO2VeuQCvbEUqNNoHAweX9ZECJ/drony+AqFRcx8HLG+7mlMIkWybeLFB31UeHV8zPPa04kFAiUiKO1/FqN4=;20:k17Dc34Gi1eEolLw2UHyKTy5bhluLUY+QNyDodwgej5ZUNXmCM944FCmfTsUkhydX6xGo2IT2NIgiXemnWNn7FD3O8jLiHUhXn+2305t8ZXUKvKHYfvLHS0AB08d8aGxC5bzhqd2Cy7Lv2WePa1aZMT2euw7YaEN6bp4bepUJ4Z9KGSlX99U2jB5UhxnwB1w3E0qgpvg4MobTLFHw0PBjxIlwJ+ktyXDuDHpw7Yp+XcqLr5lTA4ovq90Iqb45xT/ X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Dec 2015 01:48:31.7255 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY1PR12MB0437 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch introduces gicv2m_acpi_init(), which uses information in MADT GIC MSI frames structure to initialize GICv2m driver. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 95 +++++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 3 ++ include/linux/irqchip/arm-gic.h | 4 ++ 3 files changed, 102 insertions(+) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 7e60f7e..4f52e9a 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -15,9 +15,11 @@ #define pr_fmt(fmt) "GICv2m: " fmt +#include #include #include #include +#include #include #include #include @@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, fwspec.param[0] = 0; fwspec.param[1] = hwirq - 32; fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + } else if (is_fwnode_irqchip(domain->parent->fwnode)) { + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 2; + fwspec.param[0] = hwirq; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; } else { return -EINVAL; } @@ -255,6 +262,8 @@ static void gicv2m_teardown(void) kfree(v2m->bm); iounmap(v2m->base); of_node_put(to_of_node(v2m->fwnode)); + if (is_fwnode_irqchip(v2m->fwnode)) + irq_domain_free_fwnode(v2m->fwnode); kfree(v2m); } } @@ -359,6 +368,8 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, if (to_of_node(fwnode)) name = to_of_node(fwnode)->name; + else + name = irq_domain_get_irqchip_fwnode_name(fwnode); pr_info("Frame %s: range[%#lx:%#lx], SPI[%d:%d]\n", name, (unsigned long)res->start, (unsigned long)res->end, @@ -415,3 +426,87 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) gicv2m_teardown(); return ret; } + +#ifdef CONFIG_ACPI +static int acpi_num_msi; + +static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) +{ + struct v2m_data *data; + + if (WARN_ON(acpi_num_msi <= 0)) + return NULL; + + /* We only return the fwnode of the first MSI frame. */ + data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); + if (!data) + return NULL; + + return data->fwnode; +} + +static int __init +acpi_parse_madt_msi(struct acpi_subtable_header *header, + const unsigned long end) +{ + int ret; + struct resource res; + u32 spi_start = 0, nr_spis = 0; + struct acpi_madt_generic_msi_frame *m; + struct fwnode_handle *fwnode = NULL; + + m = (struct acpi_madt_generic_msi_frame *)header; + if (BAD_MADT_ENTRY(m, end)) + return -EINVAL; + + res.start = m->base_address; + res.end = m->base_address + 0x1000; + + if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { + spi_start = m->spi_base; + nr_spis = m->spi_count; + + pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n", + spi_start, nr_spis); + } + + fwnode = irq_domain_alloc_fwnode((void *)m->base_address); + if (!fwnode) { + pr_err("Unable to allocate GICv2m domain token\n"); + return -EINVAL; + } + + ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); + if (ret) + irq_domain_free_fwnode(fwnode); + + return ret; +} + +int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + int ret; + + if (acpi_num_msi > 0) + return 0; + + acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME, + acpi_parse_madt_msi, 0); + + if (acpi_num_msi <= 0) + goto err_out; + + ret = gicv2m_allocate_domains(parent); + if (ret) + goto err_out; + + pci_msi_register_fwnode_provider(&gicv2m_get_fwnode); + + return 0; + +err_out: + gicv2m_teardown(); + return -EINVAL; +} + +#endif /* CONFIG_ACPI */ diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..e4463f7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1358,6 +1358,9 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_acpi_init(gic_data[0].domain); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..30b2ccb 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -108,6 +108,10 @@ void gic_init(unsigned int nr, int start, int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +#ifdef CONFIG_ACPI +int gicv2m_acpi_init(struct irq_domain *parent); +#endif + void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suravee Suthikulpanit Subject: [PATCH v5 5/5] gicv2m: acpi: Introducing GICv2m ACPI support Date: Tue, 8 Dec 2015 17:48:06 -0800 Message-ID: <1449625686-5594-6-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: In-Reply-To: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> Sender: linux-kernel-owner@vger.kernel.org To: marc.zyngier@arm.com, tglx@linutronix.de, jason@lakedaemon.net, rjw@rjwysocki.net Cc: Lorenzo Pieralisi , Will Deacon , Catalin Marinas , hanjun.guo@linaro.org, tomasz.nowicki@linaro.org, graeme.gregory@linaro.org, dhdang@apm.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, Suravee Suthikulpanit List-Id: linux-acpi@vger.kernel.org This patch introduces gicv2m_acpi_init(), which uses information in MADT GIC MSI frames structure to initialize GICv2m driver. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 95 +++++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 3 ++ include/linux/irqchip/arm-gic.h | 4 ++ 3 files changed, 102 insertions(+) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 7e60f7e..4f52e9a 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -15,9 +15,11 @@ #define pr_fmt(fmt) "GICv2m: " fmt +#include #include #include #include +#include #include #include #include @@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, fwspec.param[0] = 0; fwspec.param[1] = hwirq - 32; fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + } else if (is_fwnode_irqchip(domain->parent->fwnode)) { + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 2; + fwspec.param[0] = hwirq; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; } else { return -EINVAL; } @@ -255,6 +262,8 @@ static void gicv2m_teardown(void) kfree(v2m->bm); iounmap(v2m->base); of_node_put(to_of_node(v2m->fwnode)); + if (is_fwnode_irqchip(v2m->fwnode)) + irq_domain_free_fwnode(v2m->fwnode); kfree(v2m); } } @@ -359,6 +368,8 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, if (to_of_node(fwnode)) name = to_of_node(fwnode)->name; + else + name = irq_domain_get_irqchip_fwnode_name(fwnode); pr_info("Frame %s: range[%#lx:%#lx], SPI[%d:%d]\n", name, (unsigned long)res->start, (unsigned long)res->end, @@ -415,3 +426,87 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) gicv2m_teardown(); return ret; } + +#ifdef CONFIG_ACPI +static int acpi_num_msi; + +static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) +{ + struct v2m_data *data; + + if (WARN_ON(acpi_num_msi <= 0)) + return NULL; + + /* We only return the fwnode of the first MSI frame. */ + data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); + if (!data) + return NULL; + + return data->fwnode; +} + +static int __init +acpi_parse_madt_msi(struct acpi_subtable_header *header, + const unsigned long end) +{ + int ret; + struct resource res; + u32 spi_start = 0, nr_spis = 0; + struct acpi_madt_generic_msi_frame *m; + struct fwnode_handle *fwnode = NULL; + + m = (struct acpi_madt_generic_msi_frame *)header; + if (BAD_MADT_ENTRY(m, end)) + return -EINVAL; + + res.start = m->base_address; + res.end = m->base_address + 0x1000; + + if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { + spi_start = m->spi_base; + nr_spis = m->spi_count; + + pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n", + spi_start, nr_spis); + } + + fwnode = irq_domain_alloc_fwnode((void *)m->base_address); + if (!fwnode) { + pr_err("Unable to allocate GICv2m domain token\n"); + return -EINVAL; + } + + ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); + if (ret) + irq_domain_free_fwnode(fwnode); + + return ret; +} + +int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + int ret; + + if (acpi_num_msi > 0) + return 0; + + acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME, + acpi_parse_madt_msi, 0); + + if (acpi_num_msi <= 0) + goto err_out; + + ret = gicv2m_allocate_domains(parent); + if (ret) + goto err_out; + + pci_msi_register_fwnode_provider(&gicv2m_get_fwnode); + + return 0; + +err_out: + gicv2m_teardown(); + return -EINVAL; +} + +#endif /* CONFIG_ACPI */ diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..e4463f7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1358,6 +1358,9 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_acpi_init(gic_data[0].domain); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..30b2ccb 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -108,6 +108,10 @@ void gic_init(unsigned int nr, int start, int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +#ifdef CONFIG_ACPI +int gicv2m_acpi_init(struct irq_domain *parent); +#endif + void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suravee.Suthikulpanit@amd.com (Suravee Suthikulpanit) Date: Tue, 8 Dec 2015 17:48:06 -0800 Subject: [PATCH v5 5/5] gicv2m: acpi: Introducing GICv2m ACPI support In-Reply-To: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449625686-5594-1-git-send-email-Suravee.Suthikulpanit@amd.com> Message-ID: <1449625686-5594-6-git-send-email-Suravee.Suthikulpanit@amd.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org This patch introduces gicv2m_acpi_init(), which uses information in MADT GIC MSI frames structure to initialize GICv2m driver. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 95 +++++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 3 ++ include/linux/irqchip/arm-gic.h | 4 ++ 3 files changed, 102 insertions(+) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 7e60f7e..4f52e9a 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -15,9 +15,11 @@ #define pr_fmt(fmt) "GICv2m: " fmt +#include #include #include #include +#include #include #include #include @@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, fwspec.param[0] = 0; fwspec.param[1] = hwirq - 32; fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + } else if (is_fwnode_irqchip(domain->parent->fwnode)) { + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 2; + fwspec.param[0] = hwirq; + fwspec.param[1] = IRQ_TYPE_EDGE_RISING; } else { return -EINVAL; } @@ -255,6 +262,8 @@ static void gicv2m_teardown(void) kfree(v2m->bm); iounmap(v2m->base); of_node_put(to_of_node(v2m->fwnode)); + if (is_fwnode_irqchip(v2m->fwnode)) + irq_domain_free_fwnode(v2m->fwnode); kfree(v2m); } } @@ -359,6 +368,8 @@ static int __init gicv2m_init_one(struct fwnode_handle *fwnode, if (to_of_node(fwnode)) name = to_of_node(fwnode)->name; + else + name = irq_domain_get_irqchip_fwnode_name(fwnode); pr_info("Frame %s: range[%#lx:%#lx], SPI[%d:%d]\n", name, (unsigned long)res->start, (unsigned long)res->end, @@ -415,3 +426,87 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) gicv2m_teardown(); return ret; } + +#ifdef CONFIG_ACPI +static int acpi_num_msi; + +static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev) +{ + struct v2m_data *data; + + if (WARN_ON(acpi_num_msi <= 0)) + return NULL; + + /* We only return the fwnode of the first MSI frame. */ + data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); + if (!data) + return NULL; + + return data->fwnode; +} + +static int __init +acpi_parse_madt_msi(struct acpi_subtable_header *header, + const unsigned long end) +{ + int ret; + struct resource res; + u32 spi_start = 0, nr_spis = 0; + struct acpi_madt_generic_msi_frame *m; + struct fwnode_handle *fwnode = NULL; + + m = (struct acpi_madt_generic_msi_frame *)header; + if (BAD_MADT_ENTRY(m, end)) + return -EINVAL; + + res.start = m->base_address; + res.end = m->base_address + 0x1000; + + if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { + spi_start = m->spi_base; + nr_spis = m->spi_count; + + pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n", + spi_start, nr_spis); + } + + fwnode = irq_domain_alloc_fwnode((void *)m->base_address); + if (!fwnode) { + pr_err("Unable to allocate GICv2m domain token\n"); + return -EINVAL; + } + + ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res); + if (ret) + irq_domain_free_fwnode(fwnode); + + return ret; +} + +int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + int ret; + + if (acpi_num_msi > 0) + return 0; + + acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME, + acpi_parse_madt_msi, 0); + + if (acpi_num_msi <= 0) + goto err_out; + + ret = gicv2m_allocate_domains(parent); + if (ret) + goto err_out; + + pci_msi_register_fwnode_provider(&gicv2m_get_fwnode); + + return 0; + +err_out: + gicv2m_teardown(); + return -EINVAL; +} + +#endif /* CONFIG_ACPI */ diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..e4463f7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1358,6 +1358,9 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_acpi_init(gic_data[0].domain); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); return 0; } diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..30b2ccb 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -108,6 +108,10 @@ void gic_init(unsigned int nr, int start, int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +#ifdef CONFIG_ACPI +int gicv2m_acpi_init(struct irq_domain *parent); +#endif + void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); void gic_migrate_target(unsigned int new_cpu_id); -- 2.1.0