gicv3_acpi.c revision 1.3.6.2 1 1.3.6.2 christos /* $NetBSD: gicv3_acpi.c,v 1.3.6.2 2019/06/10 22:05:50 christos Exp $ */
2 1.3.6.2 christos
3 1.3.6.2 christos /*-
4 1.3.6.2 christos * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 1.3.6.2 christos * All rights reserved.
6 1.3.6.2 christos *
7 1.3.6.2 christos * This code is derived from software contributed to The NetBSD Foundation
8 1.3.6.2 christos * by Jared McNeill <jmcneill (at) invisible.ca>.
9 1.3.6.2 christos *
10 1.3.6.2 christos * Redistribution and use in source and binary forms, with or without
11 1.3.6.2 christos * modification, are permitted provided that the following conditions
12 1.3.6.2 christos * are met:
13 1.3.6.2 christos * 1. Redistributions of source code must retain the above copyright
14 1.3.6.2 christos * notice, this list of conditions and the following disclaimer.
15 1.3.6.2 christos * 2. Redistributions in binary form must reproduce the above copyright
16 1.3.6.2 christos * notice, this list of conditions and the following disclaimer in the
17 1.3.6.2 christos * documentation and/or other materials provided with the distribution.
18 1.3.6.2 christos *
19 1.3.6.2 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.3.6.2 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.3.6.2 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.3.6.2 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.3.6.2 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.3.6.2 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.3.6.2 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.3.6.2 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.3.6.2 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.3.6.2 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.3.6.2 christos * POSSIBILITY OF SUCH DAMAGE.
30 1.3.6.2 christos */
31 1.3.6.2 christos
32 1.3.6.2 christos #include "pci.h"
33 1.3.6.2 christos
34 1.3.6.2 christos #define _INTR_PRIVATE
35 1.3.6.2 christos
36 1.3.6.2 christos #include <sys/cdefs.h>
37 1.3.6.2 christos __KERNEL_RCSID(0, "$NetBSD: gicv3_acpi.c,v 1.3.6.2 2019/06/10 22:05:50 christos Exp $");
38 1.3.6.2 christos
39 1.3.6.2 christos #include <sys/param.h>
40 1.3.6.2 christos #include <sys/bus.h>
41 1.3.6.2 christos #include <sys/cpu.h>
42 1.3.6.2 christos #include <sys/kernel.h>
43 1.3.6.2 christos #include <sys/device.h>
44 1.3.6.2 christos #include <sys/kmem.h>
45 1.3.6.2 christos
46 1.3.6.2 christos #include <dev/acpi/acpireg.h>
47 1.3.6.2 christos #include <dev/acpi/acpivar.h>
48 1.3.6.2 christos
49 1.3.6.2 christos #include <dev/fdt/fdtvar.h>
50 1.3.6.2 christos
51 1.3.6.2 christos #include <arm/cortex/gicv3.h>
52 1.3.6.2 christos #include <arm/cortex/gicv3_its.h>
53 1.3.6.2 christos #include <arm/cortex/gic_reg.h>
54 1.3.6.2 christos
55 1.3.6.2 christos #define GICD_SIZE 0x10000
56 1.3.6.2 christos #define GICR_SIZE 0x20000
57 1.3.6.2 christos #define GITS_SIZE 0x20000
58 1.3.6.2 christos
59 1.3.6.2 christos extern struct bus_space arm_generic_bs_tag;
60 1.3.6.2 christos extern struct arm32_bus_dma_tag arm_generic_dma_tag;
61 1.3.6.2 christos
62 1.3.6.2 christos struct gicv3_acpi_softc {
63 1.3.6.2 christos struct gicv3_softc sc_gic;
64 1.3.6.2 christos
65 1.3.6.2 christos ACPI_MADT_GENERIC_DISTRIBUTOR *sc_madt_gicd;
66 1.3.6.2 christos };
67 1.3.6.2 christos
68 1.3.6.2 christos static int gicv3_acpi_match(device_t, cfdata_t, void *);
69 1.3.6.2 christos static void gicv3_acpi_attach(device_t, device_t, void *);
70 1.3.6.2 christos
71 1.3.6.2 christos static int gicv3_acpi_map_dist(struct gicv3_acpi_softc *);
72 1.3.6.2 christos static int gicv3_acpi_map_redist(struct gicv3_acpi_softc *);
73 1.3.6.2 christos #if NPCI > 0
74 1.3.6.2 christos static int gicv3_acpi_map_its(struct gicv3_acpi_softc *);
75 1.3.6.2 christos #endif
76 1.3.6.2 christos
77 1.3.6.2 christos CFATTACH_DECL_NEW(gicv3_acpi, sizeof(struct gicv3_acpi_softc), gicv3_acpi_match, gicv3_acpi_attach, NULL, NULL);
78 1.3.6.2 christos
79 1.3.6.2 christos static int
80 1.3.6.2 christos gicv3_acpi_match(device_t parent, cfdata_t cf, void *aux)
81 1.3.6.2 christos {
82 1.3.6.2 christos ACPI_SUBTABLE_HEADER *hdrp = aux;
83 1.3.6.2 christos ACPI_MADT_GENERIC_DISTRIBUTOR *gicd;
84 1.3.6.2 christos
85 1.3.6.2 christos if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR)
86 1.3.6.2 christos return 0;
87 1.3.6.2 christos
88 1.3.6.2 christos gicd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)hdrp;
89 1.3.6.2 christos
90 1.3.6.2 christos switch (gicd->Version) {
91 1.3.6.2 christos case ACPI_MADT_GIC_VERSION_NONE:
92 1.3.6.2 christos return __SHIFTOUT(reg_id_aa64pfr0_el1_read(), ID_AA64PFR0_EL1_GIC) == 1;
93 1.3.6.2 christos case ACPI_MADT_GIC_VERSION_V3:
94 1.3.6.2 christos case ACPI_MADT_GIC_VERSION_V4:
95 1.3.6.2 christos return 1;
96 1.3.6.2 christos default:
97 1.3.6.2 christos return 0;
98 1.3.6.2 christos }
99 1.3.6.2 christos }
100 1.3.6.2 christos
101 1.3.6.2 christos static void
102 1.3.6.2 christos gicv3_acpi_attach(device_t parent, device_t self, void *aux)
103 1.3.6.2 christos {
104 1.3.6.2 christos struct gicv3_acpi_softc * const sc = device_private(self);
105 1.3.6.2 christos ACPI_MADT_GENERIC_DISTRIBUTOR *gicd = aux;
106 1.3.6.2 christos int error;
107 1.3.6.2 christos
108 1.3.6.2 christos sc->sc_gic.sc_dev = self;
109 1.3.6.2 christos sc->sc_gic.sc_bst = &arm_generic_bs_tag;
110 1.3.6.2 christos sc->sc_gic.sc_dmat = &arm_generic_dma_tag;
111 1.3.6.2 christos sc->sc_madt_gicd = gicd;
112 1.3.6.2 christos
113 1.3.6.2 christos aprint_naive("\n");
114 1.3.6.2 christos aprint_normal(": GICv3\n");
115 1.3.6.2 christos
116 1.3.6.2 christos error = gicv3_acpi_map_dist(sc);
117 1.3.6.2 christos if (error) {
118 1.3.6.2 christos aprint_error_dev(self, "failed to map distributor: %d\n", error);
119 1.3.6.2 christos return;
120 1.3.6.2 christos }
121 1.3.6.2 christos
122 1.3.6.2 christos error = gicv3_acpi_map_redist(sc);
123 1.3.6.2 christos if (error) {
124 1.3.6.2 christos aprint_error_dev(self, "failed to map redistributor: %d\n", error);
125 1.3.6.2 christos return;
126 1.3.6.2 christos }
127 1.3.6.2 christos
128 1.3.6.2 christos error = gicv3_init(&sc->sc_gic);
129 1.3.6.2 christos if (error) {
130 1.3.6.2 christos aprint_error_dev(self, "failed to initialize GIC: %d\n", error);
131 1.3.6.2 christos return;
132 1.3.6.2 christos }
133 1.3.6.2 christos
134 1.3.6.2 christos #if NPCI > 0
135 1.3.6.2 christos gicv3_acpi_map_its(sc);
136 1.3.6.2 christos #endif
137 1.3.6.2 christos
138 1.3.6.2 christos arm_fdt_irq_set_handler(gicv3_irq_handler);
139 1.3.6.2 christos }
140 1.3.6.2 christos
141 1.3.6.2 christos static int
142 1.3.6.2 christos gicv3_acpi_map_dist(struct gicv3_acpi_softc *sc)
143 1.3.6.2 christos {
144 1.3.6.2 christos const bus_addr_t addr = sc->sc_madt_gicd->BaseAddress;
145 1.3.6.2 christos const bus_size_t size = GICD_SIZE;
146 1.3.6.2 christos int error;
147 1.3.6.2 christos
148 1.3.6.2 christos error = bus_space_map(sc->sc_gic.sc_bst, addr, size, 0, &sc->sc_gic.sc_bsh_d);
149 1.3.6.2 christos if (error)
150 1.3.6.2 christos return error;
151 1.3.6.2 christos
152 1.3.6.2 christos return 0;
153 1.3.6.2 christos }
154 1.3.6.2 christos
155 1.3.6.2 christos static ACPI_STATUS
156 1.3.6.2 christos gicv3_acpi_count_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
157 1.3.6.2 christos {
158 1.3.6.2 christos ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
159 1.3.6.2 christos int *count = aux;
160 1.3.6.2 christos
161 1.3.6.2 christos if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR) {
162 1.3.6.2 christos gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
163 1.3.6.2 christos *count += howmany(gicr->Length, GICR_SIZE);
164 1.3.6.2 christos }
165 1.3.6.2 christos
166 1.3.6.2 christos return AE_OK;
167 1.3.6.2 christos }
168 1.3.6.2 christos
169 1.3.6.2 christos static ACPI_STATUS
170 1.3.6.2 christos gicv3_acpi_map_gicr(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
171 1.3.6.2 christos {
172 1.3.6.2 christos struct gicv3_acpi_softc * const sc = aux;
173 1.3.6.2 christos ACPI_MADT_GENERIC_REDISTRIBUTOR *gicr;
174 1.3.6.2 christos bus_space_handle_t bsh;
175 1.3.6.2 christos bus_size_t off;
176 1.3.6.2 christos
177 1.3.6.2 christos if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR)
178 1.3.6.2 christos return AE_OK;
179 1.3.6.2 christos
180 1.3.6.2 christos gicr = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)hdrp;
181 1.3.6.2 christos
182 1.3.6.2 christos if (bus_space_map(sc->sc_gic.sc_bst, gicr->BaseAddress, gicr->Length, 0, &bsh) != 0) {
183 1.3.6.2 christos aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
184 1.3.6.2 christos gicr->BaseAddress, gicr->Length);
185 1.3.6.2 christos return AE_OK;
186 1.3.6.2 christos }
187 1.3.6.2 christos
188 1.3.6.2 christos for (off = 0; off < gicr->Length; off += GICR_SIZE) {
189 1.3.6.2 christos const int redist = sc->sc_gic.sc_bsh_r_count;
190 1.3.6.2 christos if (bus_space_subregion(sc->sc_gic.sc_bst, bsh, off, GICR_SIZE, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
191 1.3.6.2 christos aprint_error_dev(sc->sc_gic.sc_dev, "couldn't subregion redistributor registers\n");
192 1.3.6.2 christos return AE_OK;
193 1.3.6.2 christos }
194 1.3.6.2 christos
195 1.3.6.2 christos aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICR]\n", gicr->BaseAddress + off);
196 1.3.6.2 christos
197 1.3.6.2 christos sc->sc_gic.sc_bsh_r_count++;
198 1.3.6.2 christos
199 1.3.6.2 christos /* If this is the last redist in this region, skip to the next one */
200 1.3.6.2 christos const uint32_t typer = bus_space_read_4(sc->sc_gic.sc_bst, sc->sc_gic.sc_bsh_r[redist], GICR_TYPER);
201 1.3.6.2 christos if (typer & GICR_TYPER_Last)
202 1.3.6.2 christos break;
203 1.3.6.2 christos }
204 1.3.6.2 christos
205 1.3.6.2 christos return AE_OK;
206 1.3.6.2 christos }
207 1.3.6.2 christos
208 1.3.6.2 christos static ACPI_STATUS
209 1.3.6.2 christos gicv3_acpi_count_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
210 1.3.6.2 christos {
211 1.3.6.2 christos ACPI_MADT_GENERIC_INTERRUPT *gicc;
212 1.3.6.2 christos int *count = aux;
213 1.3.6.2 christos
214 1.3.6.2 christos if (hdrp->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
215 1.3.6.2 christos gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
216 1.3.6.2 christos if ((gicc->Flags & ACPI_MADT_ENABLED) != 0)
217 1.3.6.2 christos (*count)++;
218 1.3.6.2 christos }
219 1.3.6.2 christos
220 1.3.6.2 christos return AE_OK;
221 1.3.6.2 christos }
222 1.3.6.2 christos
223 1.3.6.2 christos static ACPI_STATUS
224 1.3.6.2 christos gicv3_acpi_map_gicc(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
225 1.3.6.2 christos {
226 1.3.6.2 christos struct gicv3_acpi_softc * const sc = aux;
227 1.3.6.2 christos ACPI_MADT_GENERIC_INTERRUPT *gicc;
228 1.3.6.2 christos
229 1.3.6.2 christos if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_INTERRUPT)
230 1.3.6.2 christos return AE_OK;
231 1.3.6.2 christos
232 1.3.6.2 christos gicc = (ACPI_MADT_GENERIC_INTERRUPT *)hdrp;
233 1.3.6.2 christos if ((gicc->Flags & ACPI_MADT_ENABLED) == 0)
234 1.3.6.2 christos return AE_OK;
235 1.3.6.2 christos
236 1.3.6.2 christos const int redist = sc->sc_gic.sc_bsh_r_count;
237 1.3.6.2 christos if (bus_space_map(sc->sc_gic.sc_bst, gicc->GicrBaseAddress, GICR_SIZE, 0, &sc->sc_gic.sc_bsh_r[redist]) != 0) {
238 1.3.6.2 christos aprint_error_dev(sc->sc_gic.sc_dev, "failed to map redistributor at 0x%" PRIx64 " len %#x\n",
239 1.3.6.2 christos gicc->GicrBaseAddress, GICR_SIZE);
240 1.3.6.2 christos return AE_OK;
241 1.3.6.2 christos }
242 1.3.6.2 christos
243 1.3.6.2 christos aprint_debug_dev(sc->sc_gic.sc_dev, "redist at 0x%" PRIx64 " [GICC]\n", gicc->GicrBaseAddress);
244 1.3.6.2 christos
245 1.3.6.2 christos sc->sc_gic.sc_bsh_r_count++;
246 1.3.6.2 christos
247 1.3.6.2 christos return AE_OK;
248 1.3.6.2 christos }
249 1.3.6.2 christos
250 1.3.6.2 christos static int
251 1.3.6.2 christos gicv3_acpi_map_redist(struct gicv3_acpi_softc *sc)
252 1.3.6.2 christos {
253 1.3.6.2 christos bool use_gicr = false;
254 1.3.6.2 christos int max_redist = 0;
255 1.3.6.2 christos
256 1.3.6.2 christos /*
257 1.3.6.2 christos * Try to use GICR structures to describe redistributors. If no GICR
258 1.3.6.2 christos * subtables are found, use the GICR address from the GICC subtables.
259 1.3.6.2 christos */
260 1.3.6.2 christos acpi_madt_walk(gicv3_acpi_count_gicr, &max_redist);
261 1.3.6.2 christos if (max_redist != 0)
262 1.3.6.2 christos use_gicr = true;
263 1.3.6.2 christos else
264 1.3.6.2 christos acpi_madt_walk(gicv3_acpi_count_gicc, &max_redist);
265 1.3.6.2 christos
266 1.3.6.2 christos if (max_redist == 0)
267 1.3.6.2 christos return ENODEV;
268 1.3.6.2 christos
269 1.3.6.2 christos sc->sc_gic.sc_bsh_r = kmem_alloc(sizeof(bus_space_handle_t) * max_redist, KM_SLEEP);
270 1.3.6.2 christos if (use_gicr)
271 1.3.6.2 christos acpi_madt_walk(gicv3_acpi_map_gicr, sc);
272 1.3.6.2 christos else
273 1.3.6.2 christos acpi_madt_walk(gicv3_acpi_map_gicc, sc);
274 1.3.6.2 christos
275 1.3.6.2 christos if (sc->sc_gic.sc_bsh_r_count == 0)
276 1.3.6.2 christos return ENXIO;
277 1.3.6.2 christos
278 1.3.6.2 christos return 0;
279 1.3.6.2 christos }
280 1.3.6.2 christos
281 1.3.6.2 christos #if NPCI > 0
282 1.3.6.2 christos static ACPI_STATUS
283 1.3.6.2 christos gicv3_acpi_map_gits(ACPI_SUBTABLE_HEADER *hdrp, void *aux)
284 1.3.6.2 christos {
285 1.3.6.2 christos struct gicv3_acpi_softc * const sc = aux;
286 1.3.6.2 christos ACPI_MADT_GENERIC_TRANSLATOR *gits;
287 1.3.6.2 christos bus_space_handle_t bsh;
288 1.3.6.2 christos
289 1.3.6.2 christos if (hdrp->Type != ACPI_MADT_TYPE_GENERIC_TRANSLATOR)
290 1.3.6.2 christos return AE_OK;
291 1.3.6.2 christos
292 1.3.6.2 christos gits = (ACPI_MADT_GENERIC_TRANSLATOR *)hdrp;
293 1.3.6.2 christos
294 1.3.6.2 christos if (bus_space_map(sc->sc_gic.sc_bst, gits->BaseAddress, GITS_SIZE, 0, &bsh) != 0) {
295 1.3.6.2 christos aprint_error_dev(sc->sc_gic.sc_dev, "failed to map ITS at 0x%" PRIx64 " len %#x\n",
296 1.3.6.2 christos gits->BaseAddress, GITS_SIZE);
297 1.3.6.2 christos return AE_OK;
298 1.3.6.2 christos }
299 1.3.6.2 christos
300 1.3.6.2 christos aprint_normal_dev(sc->sc_gic.sc_dev, "ITS #%#x at 0x%" PRIx64 "\n", gits->TranslationId, gits->BaseAddress);
301 1.3.6.2 christos
302 1.3.6.2 christos gicv3_its_init(&sc->sc_gic, bsh, gits->BaseAddress, gits->TranslationId);
303 1.3.6.2 christos
304 1.3.6.2 christos return AE_OK;
305 1.3.6.2 christos }
306 1.3.6.2 christos
307 1.3.6.2 christos static int
308 1.3.6.2 christos gicv3_acpi_map_its(struct gicv3_acpi_softc *sc)
309 1.3.6.2 christos {
310 1.3.6.2 christos acpi_madt_walk(gicv3_acpi_map_gits, sc);
311 1.3.6.2 christos
312 1.3.6.2 christos return 0;
313 1.3.6.2 christos }
314 1.3.6.2 christos #endif
315