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