]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/gic_acpi.c
MFV r324198: 8081 Compiler warnings in zdb
[FreeBSD/FreeBSD.git] / sys / arm / arm / gic_acpi.c
1 /*-
2  * Copyright (c) 2011,2016 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Andrew Turner under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Developed by Damjan Marion <damjan.marion@gmail.com>
9  *
10  * Based on OMAP4 GIC code by Ben Gray
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of the company nor the name of the author may be used to
21  *    endorse or promote products derived from this software without specific
22  *    prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #include "opt_platform.h"
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/bus.h>
45 #include <sys/kernel.h>
46 #include <sys/module.h>
47
48 #include <machine/intr.h>
49
50 #include <contrib/dev/acpica/include/acpi.h>
51 #include <dev/acpica/acpivar.h>
52
53 #include <arm/arm/gic.h>
54 #include <arm/arm/gic_common.h>
55
56 struct gic_acpi_devinfo {
57         struct resource_list    rl;
58 };
59
60 static device_identify_t gic_acpi_identify;
61 static device_probe_t gic_acpi_probe;
62 static device_attach_t gic_acpi_attach;
63 static bus_get_resource_list_t gic_acpi_get_resource_list;
64 static bool arm_gic_add_children(device_t);
65
66 static device_method_t gic_acpi_methods[] = {
67         /* Device interface */
68         DEVMETHOD(device_identify,      gic_acpi_identify),
69         DEVMETHOD(device_probe,         gic_acpi_probe),
70         DEVMETHOD(device_attach,        gic_acpi_attach),
71
72         /* Bus interface */
73         DEVMETHOD(bus_get_resource_list, gic_acpi_get_resource_list),
74
75         DEVMETHOD_END,
76 };
77
78 DEFINE_CLASS_1(gic, gic_acpi_driver, gic_acpi_methods,
79     sizeof(struct arm_gic_softc), arm_gic_driver);
80
81 static devclass_t gic_acpi_devclass;
82
83 EARLY_DRIVER_MODULE(gic, acpi, gic_acpi_driver, gic_acpi_devclass, 0, 0,
84     BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
85
86 struct madt_table_data {
87         device_t parent;
88         ACPI_MADT_GENERIC_DISTRIBUTOR *dist;
89         ACPI_MADT_GENERIC_INTERRUPT *intr[MAXCPU];
90 };
91
92 static void
93 madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
94 {
95         struct madt_table_data *madt_data;
96         ACPI_MADT_GENERIC_INTERRUPT *intr;
97
98         madt_data = (struct madt_table_data *)arg;
99
100         switch(entry->Type) {
101         case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR:
102                 if (madt_data->dist != NULL) {
103                         if (bootverbose)
104                                 device_printf(madt_data->parent,
105                                     "gic: Already have a distributor table");
106                 } else
107                         madt_data->dist =
108                             (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry;
109                 break;
110         case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
111                 intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
112                 if (intr->CpuInterfaceNumber < MAXCPU)
113                         madt_data->intr[intr->CpuInterfaceNumber] = intr;
114                 break;
115         }
116 }
117
118 static void
119 gic_acpi_identify(driver_t *driver, device_t parent)
120 {
121         struct madt_table_data madt_data;
122         ACPI_MADT_GENERIC_INTERRUPT *intr;
123         ACPI_TABLE_MADT *madt;
124         vm_paddr_t physaddr;
125         device_t dev;
126         int i;
127
128         physaddr = acpi_find_table(ACPI_SIG_MADT);
129         if (physaddr == 0)
130                 return;
131
132         madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
133         if (madt == NULL) {
134                 device_printf(parent, "gic: Unable to map the MADT\n");
135                 return;
136         }
137
138         bzero(&madt_data, sizeof(madt_data));
139         madt_data.parent = parent;
140         madt_data.dist = NULL;
141
142         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
143             madt_handler, &madt_data);
144
145         /* Check the version of the GIC we have */
146         switch (madt_data.dist->Version) {
147         case ACPI_MADT_GIC_VERSION_NONE:
148         case ACPI_MADT_GIC_VERSION_V1:
149         case ACPI_MADT_GIC_VERSION_V2:
150                 break;
151         default:
152                 goto out;
153         }
154
155         intr = NULL;
156         for (i = 0; i < MAXCPU; i++) {
157                 if (madt_data.intr[i] != NULL) {
158                         if (intr == NULL) {
159                                 intr = madt_data.intr[i];
160                         } else if (intr->BaseAddress !=
161                             madt_data.intr[i]->BaseAddress) {
162                                 device_printf(parent,
163 "gic: Not all CPU interfaces at the same address, this may fail\n");
164                         }
165                 }
166         }
167         if (intr == NULL) {
168                 device_printf(parent, "gic: No CPU interfaces found\n");
169                 goto out;
170         }
171
172         dev = BUS_ADD_CHILD(parent, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE,
173             "gic", -1);
174         if (dev == NULL) {
175                 device_printf(parent, "add gic child failed\n");
176                 goto out;
177         }
178
179         BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0,
180             madt_data.dist->BaseAddress, 4 * 1024);
181         BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 1,
182             intr->BaseAddress, 4 * 1024);
183
184         acpi_set_private(dev, (void *)(uintptr_t)madt_data.dist->Version);
185 out:
186         acpi_unmap_table(madt);
187 }
188
189 static int
190 gic_acpi_probe(device_t dev)
191 {
192
193         switch((uintptr_t)acpi_get_private(dev)) {
194         case ACPI_MADT_GIC_VERSION_NONE:
195         case ACPI_MADT_GIC_VERSION_V1:
196         case ACPI_MADT_GIC_VERSION_V2:
197                 break;
198         default:
199                 return (ENXIO);
200         }
201
202         device_set_desc(dev, "ARM Generic Interrupt Controller");
203         return (BUS_PROBE_NOWILDCARD);
204 }
205
206 static int
207 gic_acpi_attach(device_t dev)
208 {
209         struct arm_gic_softc *sc = device_get_softc(dev);
210         intptr_t xref;
211         int err;
212
213         sc->gic_bus = GIC_BUS_ACPI;
214
215         err = arm_gic_attach(dev);
216         if (err != 0)
217                 return (err);
218
219         xref = 0;
220
221         /*
222          * Now, when everything is initialized, it's right time to
223          * register interrupt controller to interrupt framefork.
224          */
225         if (intr_pic_register(dev, xref) == NULL) {
226                 device_printf(dev, "could not register PIC\n");
227                 goto cleanup;
228         }
229
230         /*
231          * Controller is root:
232          */
233         if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc,
234             GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) {
235                 device_printf(dev, "could not set PIC as a root\n");
236                 intr_pic_deregister(dev, xref);
237                 goto cleanup;
238         }
239         /* If we have children probe and attach them */
240         if (arm_gic_add_children(dev)) {
241                 bus_generic_probe(dev);
242                 return (bus_generic_attach(dev));
243         }
244
245         return (0);
246
247 cleanup:
248         arm_gic_detach(dev);
249         return(ENXIO);
250 }
251
252 static struct resource_list *
253 gic_acpi_get_resource_list(device_t bus, device_t child)
254 {
255         struct gic_acpi_devinfo *di;
256
257         di = device_get_ivars(child);
258         KASSERT(di != NULL, ("gic_acpi_get_resource_list: No devinfo"));
259
260         return (&di->rl);
261 }
262
263 static void
264 madt_gicv2m_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
265 {
266         struct arm_gic_softc *sc;
267         ACPI_MADT_GENERIC_MSI_FRAME *msi;
268         struct gic_acpi_devinfo *dinfo;
269         device_t dev, cdev;
270
271         if (entry->Type == ACPI_MADT_TYPE_GENERIC_MSI_FRAME) {
272                 sc = arg;
273                 dev = sc->gic_dev;
274                 msi = (ACPI_MADT_GENERIC_MSI_FRAME *)entry;
275
276                 device_printf(dev, "frame: %x %lx %x %u %u\n", msi->MsiFrameId,
277                     msi->BaseAddress, msi->Flags, msi->SpiCount, msi->SpiBase);
278
279                 cdev = device_add_child(dev, NULL, -1);
280                 if (cdev == NULL)
281                         return;
282
283                 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
284                 resource_list_init(&dinfo->rl);
285                 resource_list_add(&dinfo->rl, SYS_RES_MEMORY, 0,
286                     msi->BaseAddress, msi->BaseAddress + PAGE_SIZE - 1,
287                     PAGE_SIZE);
288                 device_set_ivars(cdev, dinfo);
289         }
290 }
291
292 static bool
293 arm_gic_add_children(device_t dev)
294 {
295         struct arm_gic_softc *sc = device_get_softc(dev);
296         ACPI_TABLE_MADT *madt;
297         vm_paddr_t physaddr;
298
299         /* This should return a valid address as it did in gic_acpi_identify */
300         physaddr = acpi_find_table(ACPI_SIG_MADT);
301         if (physaddr == 0)
302                 return (false);
303
304         madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
305         if (madt == NULL) {
306                 device_printf(dev, "gic: Unable to map the MADT\n");
307                 return (false);
308         }
309
310         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
311             madt_gicv2m_handler, sc);
312
313         acpi_unmap_table(madt);
314
315         return (true);
316 }
317
318 static int
319 arm_gicv2m_acpi_probe(device_t dev)
320 {
321
322         if (gic_get_bus(dev) != GIC_BUS_ACPI)
323                 return (EINVAL);
324
325         if (gic_get_hw_rev(dev) > 2)
326                 return (EINVAL);
327
328         device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX");
329         return (BUS_PROBE_DEFAULT);
330 }
331
332 static device_method_t arm_gicv2m_acpi_methods[] = {
333         /* Device interface */
334         DEVMETHOD(device_probe,         arm_gicv2m_acpi_probe),
335
336         /* End */
337         DEVMETHOD_END
338 };
339
340 DEFINE_CLASS_1(gicv2m, arm_gicv2m_acpi_driver, arm_gicv2m_acpi_methods,
341     sizeof(struct arm_gicv2m_softc), arm_gicv2m_driver);
342
343 static devclass_t arm_gicv2m_acpi_devclass;
344
345 EARLY_DRIVER_MODULE(gicv2m_acpi, gic, arm_gicv2m_acpi_driver,
346     arm_gicv2m_acpi_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);