336 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2023-2024, Ventana Micro Systems Inc4 * Author: Sunil V L <sunilvl@ventanamicro.com>5 */6 7#include <linux/acpi.h>8#include <linux/sort.h>9#include <linux/irq.h>10 11#include "init.h"12 13struct riscv_ext_intc_list {14 acpi_handle handle;15 u32 gsi_base;16 u32 nr_irqs;17 u32 nr_idcs;18 u32 id;19 u32 type;20 struct list_head list;21};22 23struct acpi_irq_dep_ctx {24 int rc;25 unsigned int index;26 acpi_handle handle;27};28 29LIST_HEAD(ext_intc_list);30 31static int irqchip_cmp_func(const void *in0, const void *in1)32{33 struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0;34 struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1;35 36 return (elem0->type > elem1->type) - (elem0->type < elem1->type);37}38 39/*40 * On RISC-V, RINTC structures in MADT should be probed before any other41 * interrupt controller structures and IMSIC before APLIC. The interrupt42 * controller subtypes in MADT of ACPI spec for RISC-V are defined in43 * the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27).44 * Hence, simply sorting the subtypes in incremental order will45 * establish the required order.46 */47void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr)48{49 struct acpi_probe_entry *ape = ap_head;50 51 if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id))52 return;53 sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL);54}55 56static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle)57{58 struct riscv_ext_intc_list *ext_intc_element;59 struct list_head *i, *tmp;60 61 list_for_each_safe(i, tmp, &ext_intc_list) {62 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);63 if (gsi_base == ext_intc_element->gsi_base) {64 ext_intc_element->handle = handle;65 return AE_OK;66 }67 }68 69 return AE_NOT_FOUND;70}71 72int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base,73 u32 *id, u32 *nr_irqs, u32 *nr_idcs)74{75 struct riscv_ext_intc_list *ext_intc_element;76 struct list_head *i;77 78 list_for_each(i, &ext_intc_list) {79 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);80 if (ext_intc_element->handle == ACPI_HANDLE_FWNODE(fwnode)) {81 *gsi_base = ext_intc_element->gsi_base;82 *id = ext_intc_element->id;83 *nr_irqs = ext_intc_element->nr_irqs;84 if (nr_idcs)85 *nr_idcs = ext_intc_element->nr_idcs;86 87 return 0;88 }89 }90 91 return -ENODEV;92}93 94struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi)95{96 struct riscv_ext_intc_list *ext_intc_element;97 struct acpi_device *adev;98 struct list_head *i;99 100 list_for_each(i, &ext_intc_list) {101 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);102 if (gsi >= ext_intc_element->gsi_base &&103 gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs)) {104 adev = acpi_fetch_acpi_dev(ext_intc_element->handle);105 if (!adev)106 return NULL;107 108 return acpi_fwnode_handle(adev);109 }110 }111 112 return NULL;113}114 115static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs,116 u32 id, u32 type)117{118 struct riscv_ext_intc_list *ext_intc_element;119 120 ext_intc_element = kzalloc(sizeof(*ext_intc_element), GFP_KERNEL);121 if (!ext_intc_element)122 return -ENOMEM;123 124 ext_intc_element->gsi_base = gsi_base;125 ext_intc_element->nr_irqs = nr_irqs;126 ext_intc_element->nr_idcs = nr_idcs;127 ext_intc_element->id = id;128 list_add_tail(&ext_intc_element->list, &ext_intc_list);129 return 0;130}131 132static acpi_status __init riscv_acpi_create_gsi_map(acpi_handle handle, u32 level,133 void *context, void **return_value)134{135 acpi_status status;136 u64 gbase;137 138 if (!acpi_has_method(handle, "_GSB")) {139 acpi_handle_err(handle, "_GSB method not found\n");140 return AE_ERROR;141 }142 143 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase);144 if (ACPI_FAILURE(status)) {145 acpi_handle_err(handle, "failed to evaluate _GSB method\n");146 return status;147 }148 149 status = riscv_acpi_update_gsi_handle((u32)gbase, handle);150 if (ACPI_FAILURE(status)) {151 acpi_handle_err(handle, "failed to find the GSI mapping entry\n");152 return status;153 }154 155 return AE_OK;156}157 158static int __init riscv_acpi_aplic_parse_madt(union acpi_subtable_headers *header,159 const unsigned long end)160{161 struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header;162 163 return riscv_acpi_register_ext_intc(aplic->gsi_base, aplic->num_sources, aplic->num_idcs,164 aplic->id, ACPI_RISCV_IRQCHIP_APLIC);165}166 167static int __init riscv_acpi_plic_parse_madt(union acpi_subtable_headers *header,168 const unsigned long end)169{170 struct acpi_madt_plic *plic = (struct acpi_madt_plic *)header;171 172 return riscv_acpi_register_ext_intc(plic->gsi_base, plic->num_irqs, 0,173 plic->id, ACPI_RISCV_IRQCHIP_PLIC);174}175 176void __init riscv_acpi_init_gsi_mapping(void)177{178 /* There can be either PLIC or APLIC */179 if (acpi_table_parse_madt(ACPI_MADT_TYPE_PLIC, riscv_acpi_plic_parse_madt, 0) > 0) {180 acpi_get_devices("RSCV0001", riscv_acpi_create_gsi_map, NULL, NULL);181 return;182 }183 184 if (acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, riscv_acpi_aplic_parse_madt, 0) > 0)185 acpi_get_devices("RSCV0002", riscv_acpi_create_gsi_map, NULL, NULL);186}187 188static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)189{190 struct riscv_ext_intc_list *ext_intc_element;191 struct list_head *i;192 193 list_for_each(i, &ext_intc_list) {194 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list);195 if (gsi >= ext_intc_element->gsi_base &&196 gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs))197 return ext_intc_element->handle;198 }199 200 return NULL;201}202 203static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)204{205 struct acpi_irq_dep_ctx *ctx = context;206 struct acpi_resource_irq *irq;207 struct acpi_resource_extended_irq *eirq;208 209 switch (ares->type) {210 case ACPI_RESOURCE_TYPE_IRQ:211 irq = &ares->data.irq;212 if (ctx->index >= irq->interrupt_count) {213 ctx->index -= irq->interrupt_count;214 return AE_OK;215 }216 ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);217 return AE_CTRL_TERMINATE;218 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:219 eirq = &ares->data.extended_irq;220 if (eirq->producer_consumer == ACPI_PRODUCER)221 return AE_OK;222 223 if (ctx->index >= eirq->interrupt_count) {224 ctx->index -= eirq->interrupt_count;225 return AE_OK;226 }227 228 /* Support GSIs only */229 if (eirq->resource_source.string_length)230 return AE_OK;231 232 ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);233 return AE_CTRL_TERMINATE;234 }235 236 return AE_OK;237}238 239static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)240{241 struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};242 243 if (!gsi_handle)244 return 0;245 246 acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);247 *gsi_handle = ctx.handle;248 if (*gsi_handle)249 return 1;250 251 return 0;252}253 254static u32 riscv_acpi_add_prt_dep(acpi_handle handle)255{256 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };257 struct acpi_pci_routing_table *entry;258 struct acpi_handle_list dep_devices;259 acpi_handle gsi_handle;260 acpi_handle link_handle;261 acpi_status status;262 u32 count = 0;263 264 status = acpi_get_irq_routing_table(handle, &buffer);265 if (ACPI_FAILURE(status)) {266 acpi_handle_err(handle, "failed to get IRQ routing table\n");267 kfree(buffer.pointer);268 return 0;269 }270 271 entry = buffer.pointer;272 while (entry && (entry->length > 0)) {273 if (entry->source[0]) {274 acpi_get_handle(handle, entry->source, &link_handle);275 dep_devices.count = 1;276 dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);277 if (!dep_devices.handles) {278 acpi_handle_err(handle, "failed to allocate memory\n");279 continue;280 }281 282 dep_devices.handles[0] = link_handle;283 count += acpi_scan_add_dep(handle, &dep_devices);284 } else {285 gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);286 dep_devices.count = 1;287 dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);288 if (!dep_devices.handles) {289 acpi_handle_err(handle, "failed to allocate memory\n");290 continue;291 }292 293 dep_devices.handles[0] = gsi_handle;294 count += acpi_scan_add_dep(handle, &dep_devices);295 }296 297 entry = (struct acpi_pci_routing_table *)298 ((unsigned long)entry + entry->length);299 }300 301 kfree(buffer.pointer);302 return count;303}304 305static u32 riscv_acpi_add_irq_dep(acpi_handle handle)306{307 struct acpi_handle_list dep_devices;308 acpi_handle gsi_handle;309 u32 count = 0;310 int i;311 312 for (i = 0;313 riscv_acpi_irq_get_dep(handle, i, &gsi_handle);314 i++) {315 dep_devices.count = 1;316 dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);317 if (!dep_devices.handles) {318 acpi_handle_err(handle, "failed to allocate memory\n");319 continue;320 }321 322 dep_devices.handles[0] = gsi_handle;323 count += acpi_scan_add_dep(handle, &dep_devices);324 }325 326 return count;327}328 329u32 arch_acpi_add_auto_dep(acpi_handle handle)330{331 if (acpi_has_method(handle, "_PRT"))332 return riscv_acpi_add_prt_dep(handle);333 334 return riscv_acpi_add_irq_dep(handle);335}336