]> Git Repo - J-linux.git/blob - drivers/acpi/riscv/irq.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / acpi / riscv / irq.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2023-2024, Ventana Micro Systems Inc
4  *      Author: Sunil V L <[email protected]>
5  */
6
7 #include <linux/acpi.h>
8 #include <linux/sort.h>
9 #include <linux/irq.h>
10
11 #include "init.h"
12
13 struct 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
23 struct acpi_irq_dep_ctx {
24         int             rc;
25         unsigned int    index;
26         acpi_handle     handle;
27 };
28
29 LIST_HEAD(ext_intc_list);
30
31 static 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 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.
46  */
47 void 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
56 static 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
72 int 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
94 struct 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
115 static 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
132 static 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
158 static 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
167 static 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
176 void __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
188 static 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
203 static 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
239 static 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
254 static 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
305 static 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
329 u32 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 }
This page took 0.044618 seconds and 4 git commands to generate.