From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suravee Suthikulpanit Subject: [PATCH v6 4/4] gicv2m: acpi: Introducing GICv2m ACPI support Date: Wed, 9 Dec 2015 11:24:34 -0800 Message-ID: <1449689074-30609-5-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449689074-30609-1-git-send-email-Suravee.Suthikulpanit@amd.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: In-Reply-To: <1449689074-30609-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. It also exposes gicv2m_init() function, which simplifies callers to a single GICv2m init function. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 114 +++++++++++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 6 ++- include/linux/irqchip/arm-gic.h | 3 +- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 779c390..e01a495 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); } } @@ -373,11 +382,16 @@ static struct of_device_id gicv2m_device_id[] = { {}, }; -int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) +static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) { int ret = 0; + struct device_node *node = to_of_node(parent_handle); struct device_node *child; + if (!node) + return -EINVAL; + for (child = of_find_matching_node(node, gicv2m_device_id); child; child = of_find_matching_node(child, gicv2m_device_id)) { u32 spi_start = 0, nr_spis = 0; @@ -411,3 +425,101 @@ 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; + + 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 + SZ_4K; + + 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; +} + +static 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; +} +#else /* CONFIG_ACPI */ +static int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +int __init gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) +{ + int ret = gicv2m_of_init(parent_handle, parent); + + if (ret) + ret = gicv2m_acpi_init(parent); + return ret; +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..644e8bb 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) } if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) - gicv2m_of_init(node, gic_data[gic_cnt].domain); + gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain); gic_cnt++; return 0; @@ -1359,6 +1359,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); + + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_init(NULL, gic_data[0].domain); + return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..febc6c3 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -106,7 +106,8 @@ int gic_cpu_if_down(unsigned int gic_nr); void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu); -int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +int gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent); void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754111AbbLITZL (ORCPT ); Wed, 9 Dec 2015 14:25:11 -0500 Received: from mail-bn1on0082.outbound.protection.outlook.com ([157.56.110.82]:8736 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753961AbbLITZG (ORCPT ); Wed, 9 Dec 2015 14:25:06 -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 v6 4/4] gicv2m: acpi: Introducing GICv2m ACPI support Date: Wed, 9 Dec 2015 11:24:34 -0800 Message-ID: <1449689074-30609-5-git-send-email-Suravee.Suthikulpanit@amd.com> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1449689074-30609-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449689074-30609-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: CY1PR20CA0108.namprd20.prod.outlook.com (25.164.213.162) To BLUPR12MB0433.namprd12.prod.outlook.com (25.162.92.139) X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0433;2:AX9LSOmN2B7mVy7ERVLk/nl5OibniNyYWnSlczRoDpAwpLEb5ExBFPVLXVEl+vB53nKRfUBKCHPnomaYU/OSmb7/9LiOIxoSvdT0sgyhpDIck7t176l46EmymMY6/gi3jCFiHlXBxNkkPRZH4pUfiA==;3:vRfHQ78JU5r6rcZothujvnXlbTIykCTQpLWV03XxnFZLkOe5sgqDDBWuxs+/orMF9PG/es8L41xUA6/Mdp2buvBLdeKBkOOF34bYOfNoD87ZllXe4Bey/OEXIbIwVWE/;25:pgcEOfc9sLIG/8NtnxZb2r2igtDOEI6wVjd8GGNh2xJYXj6iOqNi4eGu4YNvlOkufJsVcyk+KaBJTyC6Z/yd3MsYjbgppJ8b/8KIP4aehHyFTcjSELl2Pg5V7ww/wF3o/OcBEFn9mYSeSw5364U8Fz1JLArh2Y8RcUENZLVOWcCnEd7wnKCd/p6P8QI5UUVh0th2iKM90iBWd6oA06owaINd1VZ9Gghj4w7Z0tCgbOut3HID2sUtNEY9EIx2NjkV3jcTKJ9BF6lYZPtt7IDbEw== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0433; X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0433;20:NDUF5SKhNAvyTDX60dSUiFYpVV+I545qkGAxiaTy2546Wg81UytysKbCxd1cgyAPYPoYnlHkzYE5FWxF3ubnYjpZYun5nWh+MFlLROzRYKOunO5fE66WGTYsgLyV/yyZRKvZ272ZKVTaCd9zZ3PonifhBrmn3DbMR0KUJ6IzIEw63FFE3iijsc7taodkuHtRBDelTD07dG4yKDCglvHrso6VRMeLYeNZXpR/qsQo9z0W3GnSY04cGF6UfOJIlwNCcEVlkKpnaLy1Xc7azeyJXJx9BhgMuTLL6ZmKKdILe5GqDRKKUfbgtPNAsGdAhezT3Mp1fTDkePf6z0FhJfefsJcRMVnvaoS8lkMSWXs9BEDL8puGZJIgDmLgGlRflcmlr0lDobKgU8b/H1cdEHFvYn4GhbBtWQ1eNL1wQMgBdTOx+nMf15tBHcWDeuNR3TX+xdbRRs5O8drG2O38ujQEQNMuB/eVDao3xkWquhGaBlB3DpA5GhYR4vJ4eDIuz9MI;4:tvkyjdyyPa/dW6+FNTw/7wND0yyxo8DylnLbpyXWn/xpNAIcyxNX4nW2XHT/XnuIRZswakXzRYpnx4srzMKiRWZ0H2hTQVJx9QfxiftjUh+4hrIb59xBXchJI8vkbwhjhaG65SfZVLiwnQmwoGAvYvX/GORAVlfw79RWzNEkLih1h0dIlqkuDiK4CQhvzv3Ro8+4obMMPKt3xToc/PBb8w9R2IgTYQw+HNO0Dp8YH+YJECKmHZKPPwheSu6GaXOnp9DIYvxJU5hSqElKErm401fmOPFd77G4Qz2GNSlBYy8XdB3s0a1Dcn87zu4zUUMLTBqEVpGNuyb9TultX2oQS1e0oEUhWwZPGchR5UM+T8/g/i6mZw0T61dNKBXqHXVBeC8maNvukN1eZrMk6YoL/YwDgWY/WjPjk7DPZo7jGgs= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(8121501046)(5005006)(520078)(3002001)(10201501046);SRVR:BLUPR12MB0433;BCL:0;PCL:0;RULEID:;SRVR:BLUPR12MB0433; X-Forefront-PRVS: 0785459C39 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(6009001)(199003)(189002)(5001770100001)(50226001)(122386002)(229853001)(36756003)(42186005)(106356001)(105586002)(5004730100002)(86362001)(5003940100001)(2201001)(66066001)(47776003)(53416004)(92566002)(76176999)(97736004)(586003)(189998001)(101416001)(5008740100001)(1096002)(50986999)(50466002)(40100003)(3846002)(2950100001)(77096005)(6116002)(48376002)(87976001)(19580395003)(19580405001);DIR:OUT;SFP:1101;SCL:1;SRVR:BLUPR12MB0433;H:ssuthiku-fedora-lt.amd.com;FPR:;SPF:None;PTR:InfoNoRecords;A:1;MX:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BLUPR12MB0433;23:5WRyjBZZ0CioMIsK0w1JZobUjXm3McmQqSHjN1cLT?= =?us-ascii?Q?fSHWjMb2f2TprBlXdXl7FcZBxV61sKqf/lHYc83WJU1bIFTxp1ap3iVvqgK2?= =?us-ascii?Q?asVUMtjdD2cWBVnnGw3nEFre9WnCpAZSWPQplxelGk+6OPI2SUFe6OfZVcL4?= =?us-ascii?Q?iGUWx/9zPRQYHPKnliynjzFvwSnm8wf8lmrvcmGe4OmNfemToq4uSqD1Duap?= =?us-ascii?Q?7HqLCOD5bUCIatYar2pnU84kH8zdI7yxA63I0Div5N761p6AyRMW5O86PWf1?= =?us-ascii?Q?LuTaU01IYzEVJZgrDN4dCSezuH1BCBcnQgEWzD6o/9JcrIj63VAFkABjn66y?= =?us-ascii?Q?2OLRv4FGnL5DaiXpHY7MGgmnoaV9EutJVUBgPeMHZecDevIm2tYKEldVNF4u?= =?us-ascii?Q?IwMh9TFCmQf17LmNfZ1PNdd9/KNuR1DBehuWxKFw1HZFr/aQ9BqbRCogP375?= =?us-ascii?Q?d5SxDj5p6gIL2SZNMQLATGF9we5V9k32NiPPfoBukuW5tAS3UmsqyzS+gEGP?= =?us-ascii?Q?2tNpTILGmTVua7USBPqd1DGkQ/CSMsWHZKGdXoRYGTJpZ94DI53TN0lB+NH3?= =?us-ascii?Q?hEqueioagsPYZGpSa4MkWHewRUiSJ8Qn50Yls7r5lJLEm9tCExF0BIe1FRKY?= =?us-ascii?Q?Gw1SrtQI2Srj6hLciBV/CPG9PeOJjpbes9uHJ5Oe+mylB9vk+3Bl4Eq+5LzL?= =?us-ascii?Q?j0yPXKFytxT4ev9ATX+Gpzh8TMWJ9KyFxdGGprTBNhXlrVicY5Kq4G/jbO8W?= =?us-ascii?Q?LtzH/BxRc3nAu6fXzP2+KIhVTkpB3PHXmDYqx6yGQtgHoTjQq4GMwSPAH8LF?= =?us-ascii?Q?MqTTWFuzOxL2anVR5HQB/c7tPBsd6I3PaLXPJscR4YIIAC48SrHv1q12dMbM?= =?us-ascii?Q?hF47iBJZwDFM8pH2T20BsCkmdl3an6jIs4JGHwLgkK6FFwV08wNC/cGXSsny?= =?us-ascii?Q?pkVqr6c/OLJJuGndbMqEHBBARzrRLE4FhW/t/eUmiPDxvy7tjB9rQ8cuYSL2?= =?us-ascii?Q?+Q=3D?= X-Microsoft-Exchange-Diagnostics: 1;BLUPR12MB0433;5:z6gNmpTtTn41rJ4mMrON5Bbom7y4cDs0wWc5Ckl8qM8RDcLtjXZs7QcDK/83YBksD9ddXCbWEWil4Z62bypqEkZ+THXgdRHJIhf9P8Q7jD7+yJ/8iUXFEHVARb+DCRD2llat+twS6TQbV/3XXCaYDQ==;24:3T6AiHyHd2bSynsGAxMO88m1jl3SLdtfEoIyAPSd6S2qCToh7IxSwdVOmtu+iIq4IXVlhseQIPbaoUH+PqCamaP+40qXdPYlmX56ZTAOtMg=;20:ghg2Hm0Ni9RZG4c2pXxe5QlvrBxeAVKTzi7nvx5eUujqB4U5qqJup0BRgI18thsIn74+WW1n1VGTkwQVlaz+Wnn9hRR3fRI+vdXcKEEpsJL8cc2JvQ15Q/vPGWHHsQJM6p+OW8nLZeJbqePct622xIlPpSXr8oUh6tFjJJeYv5yqYTOs7i0NUnsB26oVhaqpbF+1YPqlTdN/cSw4+EHdfPoUeH8uwhKgE7GzRKRNJqRap8P+WH6BM+rdJZoBMGkh X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Dec 2015 19:24:58.8758 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BLUPR12MB0433 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. It also exposes gicv2m_init() function, which simplifies callers to a single GICv2m init function. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 114 +++++++++++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 6 ++- include/linux/irqchip/arm-gic.h | 3 +- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 779c390..e01a495 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); } } @@ -373,11 +382,16 @@ static struct of_device_id gicv2m_device_id[] = { {}, }; -int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) +static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) { int ret = 0; + struct device_node *node = to_of_node(parent_handle); struct device_node *child; + if (!node) + return -EINVAL; + for (child = of_find_matching_node(node, gicv2m_device_id); child; child = of_find_matching_node(child, gicv2m_device_id)) { u32 spi_start = 0, nr_spis = 0; @@ -411,3 +425,101 @@ 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; + + 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 + SZ_4K; + + 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; +} + +static 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; +} +#else /* CONFIG_ACPI */ +static int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +int __init gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) +{ + int ret = gicv2m_of_init(parent_handle, parent); + + if (ret) + ret = gicv2m_acpi_init(parent); + return ret; +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..644e8bb 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) } if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) - gicv2m_of_init(node, gic_data[gic_cnt].domain); + gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain); gic_cnt++; return 0; @@ -1359,6 +1359,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); + + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_init(NULL, gic_data[0].domain); + return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..febc6c3 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -106,7 +106,8 @@ int gic_cpu_if_down(unsigned int gic_nr); void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu); -int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +int gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent); void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); -- 2.1.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Suravee.Suthikulpanit@amd.com (Suravee Suthikulpanit) Date: Wed, 9 Dec 2015 11:24:34 -0800 Subject: [PATCH v6 4/4] gicv2m: acpi: Introducing GICv2m ACPI support In-Reply-To: <1449689074-30609-1-git-send-email-Suravee.Suthikulpanit@amd.com> References: <1449689074-30609-1-git-send-email-Suravee.Suthikulpanit@amd.com> Message-ID: <1449689074-30609-5-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. It also exposes gicv2m_init() function, which simplifies callers to a single GICv2m init function. Signed-off-by: Suravee Suthikulpanit Signed-off-by: Hanjun Guo --- drivers/irqchip/irq-gic-v2m.c | 114 +++++++++++++++++++++++++++++++++++++++- drivers/irqchip/irq-gic.c | 6 ++- include/linux/irqchip/arm-gic.h | 3 +- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index 779c390..e01a495 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); } } @@ -373,11 +382,16 @@ static struct of_device_id gicv2m_device_id[] = { {}, }; -int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) +static int __init gicv2m_of_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) { int ret = 0; + struct device_node *node = to_of_node(parent_handle); struct device_node *child; + if (!node) + return -EINVAL; + for (child = of_find_matching_node(node, gicv2m_device_id); child; child = of_find_matching_node(child, gicv2m_device_id)) { u32 spi_start = 0, nr_spis = 0; @@ -411,3 +425,101 @@ 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; + + 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 + SZ_4K; + + 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; +} + +static 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; +} +#else /* CONFIG_ACPI */ +static int __init gicv2m_acpi_init(struct irq_domain *parent) +{ + return -EINVAL; +} +#endif /* CONFIG_ACPI */ + +int __init gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent) +{ + int ret = gicv2m_of_init(parent_handle, parent); + + if (ret) + ret = gicv2m_acpi_init(parent); + return ret; +} diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index fcd327f..644e8bb 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) } if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) - gicv2m_of_init(node, gic_data[gic_cnt].domain); + gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain); gic_cnt++; return 0; @@ -1359,6 +1359,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); + + if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) + gicv2m_init(NULL, gic_data[0].domain); + return 0; } IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index bae69e5..febc6c3 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -106,7 +106,8 @@ int gic_cpu_if_down(unsigned int gic_nr); void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu); -int gicv2m_of_init(struct device_node *node, struct irq_domain *parent); +int gicv2m_init(struct fwnode_handle *parent_handle, + struct irq_domain *parent); void gic_send_sgi(unsigned int cpu_id, unsigned int irq); int gic_get_cpu_id(unsigned int cpu); -- 2.1.0