Since APLIC needs to be a platform device, probe the MADT and create platform devices for each APLIC in the system. Signed-off-by: Sunil V L <sunilvl@xxxxxxxxxxxxxxxx> --- drivers/acpi/riscv/init.c | 2 ++ drivers/acpi/riscv/init.h | 5 +++ drivers/acpi/riscv/irq.c | 74 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 drivers/acpi/riscv/init.h diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c index b5807bbdb171..e7eff7ab1474 100644 --- a/drivers/acpi/riscv/init.c +++ b/drivers/acpi/riscv/init.c @@ -6,7 +6,9 @@ */ #include <linux/acpi.h> +#include "init.h" void __init acpi_riscv_init(void) { + riscv_acpi_aplic_platform_init(); } diff --git a/drivers/acpi/riscv/init.h b/drivers/acpi/riscv/init.h new file mode 100644 index 000000000000..17bcf0baaadb --- /dev/null +++ b/drivers/acpi/riscv/init.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#include <linux/init.h> + +void __init riscv_acpi_imsic_platform_init(void); +void __init riscv_acpi_aplic_platform_init(void); diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c index 36e0525b3235..fbccecdcbf8b 100644 --- a/drivers/acpi/riscv/irq.c +++ b/drivers/acpi/riscv/irq.c @@ -6,6 +6,8 @@ */ #include <linux/acpi.h> +#include <linux/irqdomain.h> +#include <linux/platform_device.h> #include <linux/sort.h> static int irqchip_cmp_func(const void *in0, const void *in1) @@ -30,3 +32,75 @@ void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr) return; sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL); } + +static int __init irqchip_add_platform_device(char *irqchip_name, u32 irqchip_id, + resource_size_t iomem_res_start, + resource_size_t iomem_res_size, + union acpi_subtable_headers *header) +{ + struct platform_device *pdev; + struct fwnode_handle *fn; + struct resource *res; + int ret; + + fn = irq_domain_alloc_named_id_fwnode(irqchip_name, irqchip_id); + if (!fn) + return -ENOMEM; + + pdev = platform_device_alloc(irqchip_name, irqchip_id); + if (!pdev) { + irq_domain_free_fwnode(fn); + return -ENOMEM; + } + + res = kcalloc(1, sizeof(*res), GFP_KERNEL); + if (!res) { + irq_domain_free_fwnode(fn); + platform_device_put(pdev); + return -ENOMEM; + } + + res->start = iomem_res_start; + res->end = res->start + iomem_res_size - 1; + res->flags = IORESOURCE_MEM; + ret = platform_device_add_resources(pdev, res, 1); + /* + * Resources are duplicated in platform_device_add_resources, + * free their allocated memory + */ + kfree(res); + + /* + * Add copy of aplic pointer so that platform driver get aplic details. + */ + ret = platform_device_add_data(pdev, &header, sizeof(header)); + if (ret) { + irq_domain_free_fwnode(fn); + platform_device_put(pdev); + return ret; + } + + pdev->dev.fwnode = fn; + ret = platform_device_add(pdev); + if (ret) { + irq_domain_free_fwnode(fn); + platform_device_put(pdev); + return ret; + } + + return 0; +} + +static int __init aplic_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header; + + return irqchip_add_platform_device("riscv-aplic", aplic->id, aplic->base_addr, + aplic->size, header); +} + +void __init riscv_acpi_aplic_platform_init(void) +{ + acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, aplic_parse_madt, 0); +} -- 2.39.2