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