1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2023-2024, Ventana Micro Systems Inc
4 * Author: Sunil V L <sunilvl@ventanamicro.com>
7 #include <linux/acpi.h>
8 #include <linux/sort.h>
13 struct riscv_ext_intc_list
{
20 struct list_head list
;
23 struct acpi_irq_dep_ctx
{
29 LIST_HEAD(ext_intc_list
);
31 static int irqchip_cmp_func(const void *in0
, const void *in1
)
33 struct acpi_probe_entry
*elem0
= (struct acpi_probe_entry
*)in0
;
34 struct acpi_probe_entry
*elem1
= (struct acpi_probe_entry
*)in1
;
36 return (elem0
->type
> elem1
->type
) - (elem0
->type
< elem1
->type
);
40 * On RISC-V, RINTC structures in MADT should be probed before any other
41 * interrupt controller structures and IMSIC before APLIC. The interrupt
42 * controller subtypes in MADT of ACPI spec for RISC-V are defined in
43 * the incremental order like RINTC(24)->IMSIC(25)->APLIC(26)->PLIC(27).
44 * Hence, simply sorting the subtypes in incremental order will
45 * establish the required order.
47 void arch_sort_irqchip_probe(struct acpi_probe_entry
*ap_head
, int nr
)
49 struct acpi_probe_entry
*ape
= ap_head
;
51 if (nr
== 1 || !ACPI_COMPARE_NAMESEG(ACPI_SIG_MADT
, ape
->id
))
53 sort(ape
, nr
, sizeof(*ape
), irqchip_cmp_func
, NULL
);
56 static acpi_status
riscv_acpi_update_gsi_handle(u32 gsi_base
, acpi_handle handle
)
58 struct riscv_ext_intc_list
*ext_intc_element
;
59 struct list_head
*i
, *tmp
;
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
;
72 int riscv_acpi_get_gsi_info(struct fwnode_handle
*fwnode
, u32
*gsi_base
,
73 u32
*id
, u32
*nr_irqs
, u32
*nr_idcs
)
75 struct riscv_ext_intc_list
*ext_intc_element
;
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
;
85 *nr_idcs
= ext_intc_element
->nr_idcs
;
94 struct fwnode_handle
*riscv_acpi_get_gsi_domain_id(u32 gsi
)
96 struct riscv_ext_intc_list
*ext_intc_element
;
97 struct acpi_device
*adev
;
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
);
108 return acpi_fwnode_handle(adev
);
115 static int __init
riscv_acpi_register_ext_intc(u32 gsi_base
, u32 nr_irqs
, u32 nr_idcs
,
118 struct riscv_ext_intc_list
*ext_intc_element
;
120 ext_intc_element
= kzalloc(sizeof(*ext_intc_element
), GFP_KERNEL
);
121 if (!ext_intc_element
)
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
);
132 static acpi_status __init
riscv_acpi_create_gsi_map(acpi_handle handle
, u32 level
,
133 void *context
, void **return_value
)
138 if (!acpi_has_method(handle
, "_GSB")) {
139 acpi_handle_err(handle
, "_GSB method not found\n");
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");
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");
158 static int __init
riscv_acpi_aplic_parse_madt(union acpi_subtable_headers
*header
,
159 const unsigned long end
)
161 struct acpi_madt_aplic
*aplic
= (struct acpi_madt_aplic
*)header
;
163 return riscv_acpi_register_ext_intc(aplic
->gsi_base
, aplic
->num_sources
, aplic
->num_idcs
,
164 aplic
->id
, ACPI_RISCV_IRQCHIP_APLIC
);
167 static int __init
riscv_acpi_plic_parse_madt(union acpi_subtable_headers
*header
,
168 const unsigned long end
)
170 struct acpi_madt_plic
*plic
= (struct acpi_madt_plic
*)header
;
172 return riscv_acpi_register_ext_intc(plic
->gsi_base
, plic
->num_irqs
, 0,
173 plic
->id
, ACPI_RISCV_IRQCHIP_PLIC
);
176 void __init
riscv_acpi_init_gsi_mapping(void)
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
);
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
);
188 static acpi_handle
riscv_acpi_get_gsi_handle(u32 gsi
)
190 struct riscv_ext_intc_list
*ext_intc_element
;
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
;
203 static acpi_status
riscv_acpi_irq_get_parent(struct acpi_resource
*ares
, void *context
)
205 struct acpi_irq_dep_ctx
*ctx
= context
;
206 struct acpi_resource_irq
*irq
;
207 struct acpi_resource_extended_irq
*eirq
;
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
;
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
)
223 if (ctx
->index
>= eirq
->interrupt_count
) {
224 ctx
->index
-= eirq
->interrupt_count
;
228 /* Support GSIs only */
229 if (eirq
->resource_source
.string_length
)
232 ctx
->handle
= riscv_acpi_get_gsi_handle(eirq
->interrupts
[ctx
->index
]);
233 return AE_CTRL_TERMINATE
;
239 static int riscv_acpi_irq_get_dep(acpi_handle handle
, unsigned int index
, acpi_handle
*gsi_handle
)
241 struct acpi_irq_dep_ctx ctx
= {-EINVAL
, index
, NULL
};
246 acpi_walk_resources(handle
, METHOD_NAME__CRS
, riscv_acpi_irq_get_parent
, &ctx
);
247 *gsi_handle
= ctx
.handle
;
254 static u32
riscv_acpi_add_prt_dep(acpi_handle handle
)
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
;
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
);
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");
282 dep_devices
.handles
[0] = link_handle
;
283 count
+= acpi_scan_add_dep(handle
, &dep_devices
);
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");
293 dep_devices
.handles
[0] = gsi_handle
;
294 count
+= acpi_scan_add_dep(handle
, &dep_devices
);
297 entry
= (struct acpi_pci_routing_table
*)
298 ((unsigned long)entry
+ entry
->length
);
301 kfree(buffer
.pointer
);
305 static u32
riscv_acpi_add_irq_dep(acpi_handle handle
)
307 struct acpi_handle_list dep_devices
;
308 acpi_handle gsi_handle
;
313 riscv_acpi_irq_get_dep(handle
, i
, &gsi_handle
);
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");
322 dep_devices
.handles
[0] = gsi_handle
;
323 count
+= acpi_scan_add_dep(handle
, &dep_devices
);
329 u32
arch_acpi_add_auto_dep(acpi_handle handle
)
331 if (acpi_has_method(handle
, "_PRT"))
332 return riscv_acpi_add_prt_dep(handle
);
334 return riscv_acpi_add_irq_dep(handle
);