1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2023-2024, Ventana Micro Systems Inc 4 * 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 13 #define RISCV_ACPI_INTC_FLAG_PENDING BIT(0) 14 15 struct riscv_ext_intc_list { 16 acpi_handle handle; 17 u32 gsi_base; 18 u32 nr_irqs; 19 u32 nr_idcs; 20 u32 id; 21 u32 type; 22 u32 flag; 23 struct list_head list; 24 }; 25 26 LIST_HEAD(ext_intc_list); 27 28 static int irqchip_cmp_func(const void *in0, const void *in1) 29 { 30 struct acpi_probe_entry *elem0 = (struct acpi_probe_entry *)in0; 31 struct acpi_probe_entry *elem1 = (struct acpi_probe_entry *)in1; 32 33 return (elem0->type > elem1->type) - (elem0->type < elem1->type); 34 } 35 36 /* 37 * On RISC-V, RINTC structures in MADT should be probed before any other 38 * interrupt controller structures and IMSIC before APLIC. The interrupt 39 * controller subtypes in MADT of ACPI spec for RISC-V are defined in 40 * the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27). 41 * Hence, simply sorting the subtypes in incremental order will 42 * establish the required order. 43 */ 44 void arch_sort_irqchip_probe(struct acpi_probe_entry *ap_head, int nr) 45 { 46 struct acpi_probe_entry *ape = ap_head; 47 48 if (nr == 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT, ape->id)) 49 return; 50 sort(ape, nr, sizeof(*ape), irqchip_cmp_func, NULL); 51 } 52 53 static acpi_status riscv_acpi_update_gsi_handle(u32 gsi_base, acpi_handle handle) 54 { 55 struct riscv_ext_intc_list *ext_intc_element; 56 struct list_head *i, *tmp; 57 58 list_for_each_safe(i, tmp, &ext_intc_list) { 59 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list); 60 if (gsi_base == ext_intc_element->gsi_base) { 61 ext_intc_element->handle = handle; 62 return AE_OK; 63 } 64 } 65 66 return AE_NOT_FOUND; 67 } 68 69 int riscv_acpi_update_gsi_range(u32 gsi_base, u32 nr_irqs) 70 { 71 struct riscv_ext_intc_list *ext_intc_element; 72 73 list_for_each_entry(ext_intc_element, &ext_intc_list, list) { 74 if (gsi_base == ext_intc_element->gsi_base && 75 (ext_intc_element->flag & RISCV_ACPI_INTC_FLAG_PENDING)) { 76 ext_intc_element->nr_irqs = nr_irqs; 77 ext_intc_element->flag &= ~RISCV_ACPI_INTC_FLAG_PENDING; 78 return 0; 79 } 80 } 81 82 return -ENODEV; 83 } 84 85 int riscv_acpi_get_gsi_info(struct fwnode_handle *fwnode, u32 *gsi_base, 86 u32 *id, u32 *nr_irqs, u32 *nr_idcs) 87 { 88 struct riscv_ext_intc_list *ext_intc_element; 89 struct list_head *i; 90 91 list_for_each(i, &ext_intc_list) { 92 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list); 93 if (ext_intc_element->handle == ACPI_HANDLE_FWNODE(fwnode)) { 94 *gsi_base = ext_intc_element->gsi_base; 95 *id = ext_intc_element->id; 96 *nr_irqs = ext_intc_element->nr_irqs; 97 if (nr_idcs) 98 *nr_idcs = ext_intc_element->nr_idcs; 99 100 return 0; 101 } 102 } 103 104 return -ENODEV; 105 } 106 107 struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi) 108 { 109 struct riscv_ext_intc_list *ext_intc_element; 110 struct acpi_device *adev; 111 struct list_head *i; 112 113 list_for_each(i, &ext_intc_list) { 114 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list); 115 if (gsi >= ext_intc_element->gsi_base && 116 gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs)) { 117 adev = acpi_fetch_acpi_dev(ext_intc_element->handle); 118 if (!adev) 119 return NULL; 120 121 return acpi_fwnode_handle(adev); 122 } 123 } 124 125 return NULL; 126 } 127 128 static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs, 129 u32 id, u32 type) 130 { 131 struct riscv_ext_intc_list *ext_intc_element, *node, *prev; 132 133 ext_intc_element = kzalloc_obj(*ext_intc_element); 134 if (!ext_intc_element) 135 return -ENOMEM; 136 137 ext_intc_element->gsi_base = gsi_base; 138 139 /* If nr_irqs is zero, indicate it in flag and set to max range possible */ 140 if (nr_irqs) { 141 ext_intc_element->nr_irqs = nr_irqs; 142 } else { 143 ext_intc_element->flag |= RISCV_ACPI_INTC_FLAG_PENDING; 144 ext_intc_element->nr_irqs = U32_MAX - ext_intc_element->gsi_base; 145 } 146 147 ext_intc_element->nr_idcs = nr_idcs; 148 ext_intc_element->id = id; 149 list_for_each_entry(node, &ext_intc_list, list) { 150 if (node->gsi_base < ext_intc_element->gsi_base) 151 break; 152 } 153 154 /* Adjust the previous node's GSI range if that has pending registration */ 155 prev = list_prev_entry(node, list); 156 if (!list_entry_is_head(prev, &ext_intc_list, list)) { 157 if (prev->flag & RISCV_ACPI_INTC_FLAG_PENDING) 158 prev->nr_irqs = ext_intc_element->gsi_base - prev->gsi_base; 159 } 160 161 list_add_tail(&ext_intc_element->list, &node->list); 162 return 0; 163 } 164 165 static acpi_status __init riscv_acpi_create_gsi_map_smsi(acpi_handle handle, u32 level, 166 void *context, void **return_value) 167 { 168 acpi_status status; 169 u64 gbase; 170 171 if (!acpi_has_method(handle, "_GSB")) { 172 acpi_handle_err(handle, "_GSB method not found\n"); 173 return AE_ERROR; 174 } 175 176 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase); 177 if (ACPI_FAILURE(status)) { 178 acpi_handle_err(handle, "failed to evaluate _GSB method\n"); 179 return status; 180 } 181 182 riscv_acpi_register_ext_intc(gbase, 0, 0, 0, ACPI_RISCV_IRQCHIP_SMSI); 183 status = riscv_acpi_update_gsi_handle((u32)gbase, handle); 184 if (ACPI_FAILURE(status)) { 185 acpi_handle_err(handle, "failed to find the GSI mapping entry\n"); 186 return status; 187 } 188 189 return AE_OK; 190 } 191 192 static acpi_status __init riscv_acpi_create_gsi_map(acpi_handle handle, u32 level, 193 void *context, void **return_value) 194 { 195 acpi_status status; 196 u64 gbase; 197 198 if (!acpi_has_method(handle, "_GSB")) { 199 acpi_handle_err(handle, "_GSB method not found\n"); 200 return AE_ERROR; 201 } 202 203 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gbase); 204 if (ACPI_FAILURE(status)) { 205 acpi_handle_err(handle, "failed to evaluate _GSB method\n"); 206 return status; 207 } 208 209 status = riscv_acpi_update_gsi_handle((u32)gbase, handle); 210 if (ACPI_FAILURE(status)) { 211 acpi_handle_err(handle, "failed to find the GSI mapping entry\n"); 212 return status; 213 } 214 215 return AE_OK; 216 } 217 218 static int __init riscv_acpi_aplic_parse_madt(union acpi_subtable_headers *header, 219 const unsigned long end) 220 { 221 struct acpi_madt_aplic *aplic = (struct acpi_madt_aplic *)header; 222 223 return riscv_acpi_register_ext_intc(aplic->gsi_base, aplic->num_sources, aplic->num_idcs, 224 aplic->id, ACPI_RISCV_IRQCHIP_APLIC); 225 } 226 227 static int __init riscv_acpi_plic_parse_madt(union acpi_subtable_headers *header, 228 const unsigned long end) 229 { 230 struct acpi_madt_plic *plic = (struct acpi_madt_plic *)header; 231 232 return riscv_acpi_register_ext_intc(plic->gsi_base, plic->num_irqs, 0, 233 plic->id, ACPI_RISCV_IRQCHIP_PLIC); 234 } 235 236 void __init riscv_acpi_init_gsi_mapping(void) 237 { 238 /* There can be either PLIC or APLIC */ 239 if (acpi_table_parse_madt(ACPI_MADT_TYPE_PLIC, riscv_acpi_plic_parse_madt, 0) > 0) { 240 acpi_get_devices("RSCV0001", riscv_acpi_create_gsi_map, NULL, NULL); 241 return; 242 } 243 244 if (acpi_table_parse_madt(ACPI_MADT_TYPE_APLIC, riscv_acpi_aplic_parse_madt, 0) > 0) 245 acpi_get_devices("RSCV0002", riscv_acpi_create_gsi_map, NULL, NULL); 246 247 /* Unlike PLIC/APLIC, SYSMSI doesn't have MADT */ 248 acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL); 249 } 250 251 acpi_handle acpi_get_riscv_gsi_handle(u32 gsi) 252 { 253 struct riscv_ext_intc_list *ext_intc_element; 254 struct list_head *i; 255 256 list_for_each(i, &ext_intc_list) { 257 ext_intc_element = list_entry(i, struct riscv_ext_intc_list, list); 258 if (gsi >= ext_intc_element->gsi_base && 259 gsi < (ext_intc_element->gsi_base + ext_intc_element->nr_irqs)) 260 return ext_intc_element->handle; 261 } 262 263 return NULL; 264 } 265 266 u32 arch_acpi_add_auto_dep(acpi_handle handle) 267 { 268 return acpi_irq_add_auto_dep(handle); 269 } 270