1 /*- 2 * Copyright (c) 2016 The FreeBSD Foundation 3 * Copyright (c) 2022 Arm Ltd 4 * 5 * This software was developed by Andrew Turner under 6 * the sponsorship of the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include "opt_acpi.h" 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/types.h> 36 #include <sys/systm.h> 37 #include <sys/bus.h> 38 #include <sys/kernel.h> 39 #include <sys/malloc.h> 40 #include <sys/module.h> 41 #include <sys/rman.h> 42 43 #include <machine/intr.h> 44 #include <machine/resource.h> 45 46 #include <contrib/dev/acpica/include/acpi.h> 47 #include <dev/acpica/acpivar.h> 48 49 #include "gic_v3_reg.h" 50 #include "gic_v3_var.h" 51 52 #define GICV3_PRIV_VGIC 0x80000000 53 #define GICV3_PRIV_FLAGS 0x80000000 54 #define HV_MSI_SPI_START 64 55 #define HV_MSI_SPI_LAST 0 56 57 struct gic_v3_acpi_devinfo { 58 struct gic_v3_devinfo di_gic_dinfo; 59 struct resource_list di_rl; 60 }; 61 62 static device_identify_t gic_v3_acpi_identify; 63 static device_probe_t gic_v3_acpi_probe; 64 static device_attach_t gic_v3_acpi_attach; 65 static bus_get_resource_list_t gic_v3_acpi_get_resource_list; 66 67 static void gic_v3_acpi_bus_attach(device_t); 68 69 static device_method_t gic_v3_acpi_methods[] = { 70 /* Device interface */ 71 DEVMETHOD(device_identify, gic_v3_acpi_identify), 72 DEVMETHOD(device_probe, gic_v3_acpi_probe), 73 DEVMETHOD(device_attach, gic_v3_acpi_attach), 74 75 /* Bus interface */ 76 DEVMETHOD(bus_get_resource_list, gic_v3_acpi_get_resource_list), 77 78 /* End */ 79 DEVMETHOD_END 80 }; 81 82 DEFINE_CLASS_1(gic, gic_v3_acpi_driver, gic_v3_acpi_methods, 83 sizeof(struct gic_v3_softc), gic_v3_driver); 84 85 EARLY_DRIVER_MODULE(gic_v3, acpi, gic_v3_acpi_driver, 0, 0, 86 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 87 88 struct madt_table_data { 89 device_t parent; 90 device_t dev; 91 ACPI_MADT_GENERIC_DISTRIBUTOR *dist; 92 int count; 93 bool rdist_use_gicc; 94 bool have_vgic; 95 }; 96 97 static void 98 madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg) 99 { 100 struct madt_table_data *madt_data; 101 102 madt_data = (struct madt_table_data *)arg; 103 104 switch(entry->Type) { 105 case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: 106 if (madt_data->dist != NULL) { 107 if (bootverbose) 108 device_printf(madt_data->parent, 109 "gic: Already have a distributor table"); 110 break; 111 } 112 madt_data->dist = (ACPI_MADT_GENERIC_DISTRIBUTOR *)entry; 113 break; 114 115 case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: 116 break; 117 118 default: 119 break; 120 } 121 } 122 123 static void 124 rdist_map(ACPI_SUBTABLE_HEADER *entry, void *arg) 125 { 126 ACPI_MADT_GENERIC_REDISTRIBUTOR *redist; 127 ACPI_MADT_GENERIC_INTERRUPT *intr; 128 struct madt_table_data *madt_data; 129 rman_res_t count; 130 131 madt_data = (struct madt_table_data *)arg; 132 133 switch(entry->Type) { 134 case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: 135 if (madt_data->rdist_use_gicc) 136 break; 137 redist = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)entry; 138 139 madt_data->count++; 140 BUS_SET_RESOURCE(madt_data->parent, madt_data->dev, 141 SYS_RES_MEMORY, madt_data->count, redist->BaseAddress, 142 redist->Length); 143 break; 144 145 case ACPI_MADT_TYPE_GENERIC_INTERRUPT: 146 if (!madt_data->rdist_use_gicc) 147 break; 148 149 intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry; 150 151 madt_data->count++; 152 /* 153 * Map the two 64k redistributor frames. 154 */ 155 count = GICR_RD_BASE_SIZE + GICR_SGI_BASE_SIZE; 156 if (madt_data->dist->Version == ACPI_MADT_GIC_VERSION_V4) 157 count += GICR_VLPI_BASE_SIZE + GICR_RESERVED_SIZE; 158 BUS_SET_RESOURCE(madt_data->parent, madt_data->dev, 159 SYS_RES_MEMORY, madt_data->count, intr->GicrBaseAddress, 160 count); 161 if (intr->VgicInterrupt == 0) 162 madt_data->have_vgic = false; 163 164 default: 165 break; 166 } 167 } 168 169 static void 170 gic_v3_acpi_identify(driver_t *driver, device_t parent) 171 { 172 struct madt_table_data madt_data; 173 ACPI_TABLE_MADT *madt; 174 vm_paddr_t physaddr; 175 uintptr_t private; 176 device_t dev; 177 178 physaddr = acpi_find_table(ACPI_SIG_MADT); 179 if (physaddr == 0) 180 return; 181 182 madt = acpi_map_table(physaddr, ACPI_SIG_MADT); 183 if (madt == NULL) { 184 device_printf(parent, "gic: Unable to map the MADT\n"); 185 return; 186 } 187 188 madt_data.parent = parent; 189 madt_data.dist = NULL; 190 madt_data.count = 0; 191 192 acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 193 madt_handler, &madt_data); 194 if (madt_data.dist == NULL) { 195 device_printf(parent, 196 "No gic interrupt or distributor table\n"); 197 goto out; 198 } 199 200 /* Check the GIC version is supported by thiss driver */ 201 switch(madt_data.dist->Version) { 202 case ACPI_MADT_GIC_VERSION_V3: 203 case ACPI_MADT_GIC_VERSION_V4: 204 break; 205 default: 206 goto out; 207 } 208 209 dev = BUS_ADD_CHILD(parent, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE, 210 "gic", -1); 211 if (dev == NULL) { 212 device_printf(parent, "add gic child failed\n"); 213 goto out; 214 } 215 216 /* Add the MADT data */ 217 BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0, 218 madt_data.dist->BaseAddress, 128 * 1024); 219 220 madt_data.dev = dev; 221 madt_data.rdist_use_gicc = false; 222 madt_data.have_vgic = true; 223 acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 224 rdist_map, &madt_data); 225 if (madt_data.count == 0) { 226 /* 227 * No redistributors found, fall back to use the GICR 228 * address from the GICC sub-table. 229 */ 230 madt_data.rdist_use_gicc = true; 231 acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 232 rdist_map, &madt_data); 233 } 234 235 private = madt_data.dist->Version; 236 /* Flag that the VGIC is in use */ 237 if (madt_data.have_vgic) 238 private |= GICV3_PRIV_VGIC; 239 240 acpi_set_private(dev, (void *)private); 241 242 out: 243 acpi_unmap_table(madt); 244 } 245 246 static int 247 gic_v3_acpi_probe(device_t dev) 248 { 249 250 switch((uintptr_t)acpi_get_private(dev) & ~GICV3_PRIV_FLAGS) { 251 case ACPI_MADT_GIC_VERSION_V3: 252 case ACPI_MADT_GIC_VERSION_V4: 253 break; 254 default: 255 return (ENXIO); 256 } 257 258 device_set_desc(dev, GIC_V3_DEVSTR); 259 return (BUS_PROBE_NOWILDCARD); 260 } 261 262 static void 263 madt_count_redistrib(ACPI_SUBTABLE_HEADER *entry, void *arg) 264 { 265 struct gic_v3_softc *sc = arg; 266 267 if (entry->Type == ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR) 268 sc->gic_redists.nregions++; 269 } 270 271 static void 272 madt_count_gicc_redistrib(ACPI_SUBTABLE_HEADER *entry, void *arg) 273 { 274 struct gic_v3_softc *sc = arg; 275 276 if (entry->Type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) 277 sc->gic_redists.nregions++; 278 } 279 280 static int 281 gic_v3_acpi_count_regions(device_t dev) 282 { 283 struct gic_v3_softc *sc; 284 ACPI_TABLE_MADT *madt; 285 vm_paddr_t physaddr; 286 287 sc = device_get_softc(dev); 288 289 physaddr = acpi_find_table(ACPI_SIG_MADT); 290 if (physaddr == 0) 291 return (ENXIO); 292 293 madt = acpi_map_table(physaddr, ACPI_SIG_MADT); 294 if (madt == NULL) { 295 device_printf(dev, "Unable to map the MADT\n"); 296 return (ENXIO); 297 } 298 299 acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 300 madt_count_redistrib, sc); 301 /* Fall back to use the distributor GICR base address */ 302 if (sc->gic_redists.nregions == 0) { 303 acpi_walk_subtables(madt + 1, 304 (char *)madt + madt->Header.Length, 305 madt_count_gicc_redistrib, sc); 306 } 307 acpi_unmap_table(madt); 308 309 return (sc->gic_redists.nregions > 0 ? 0 : ENXIO); 310 } 311 312 static int 313 gic_v3_acpi_attach(device_t dev) 314 { 315 struct gic_v3_softc *sc; 316 int err; 317 318 sc = device_get_softc(dev); 319 sc->dev = dev; 320 sc->gic_bus = GIC_BUS_ACPI; 321 322 err = gic_v3_acpi_count_regions(dev); 323 if (err != 0) 324 goto count_error; 325 if (vm_guest == VM_GUEST_HV) { 326 sc->gic_mbi_start = HV_MSI_SPI_START; 327 sc->gic_mbi_end = HV_MSI_SPI_LAST; 328 } 329 err = gic_v3_attach(dev); 330 if (err != 0) 331 goto error; 332 333 sc->gic_pic = intr_pic_register(dev, ACPI_INTR_XREF); 334 if (sc->gic_pic == NULL) { 335 device_printf(dev, "could not register PIC\n"); 336 err = ENXIO; 337 goto error; 338 } 339 /* 340 * Registering for MSI with SPI range, as this is 341 * required for Hyper-V GIC to work in ARM64. 342 */ 343 if (vm_guest == VM_GUEST_HV) { 344 err = intr_msi_register(dev, ACPI_MSI_XREF); 345 if (err) { 346 device_printf(dev, "could not register MSI\n"); 347 goto error; 348 } 349 } 350 351 if (intr_pic_claim_root(dev, ACPI_INTR_XREF, arm_gic_v3_intr, sc, 352 GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 353 err = ENXIO; 354 goto error; 355 } 356 357 /* 358 * Try to register the ITS driver to this GIC. The GIC will act as 359 * a bus in that case. Failure here will not affect the main GIC 360 * functionality. 361 */ 362 gic_v3_acpi_bus_attach(dev); 363 364 if (device_get_children(dev, &sc->gic_children, &sc->gic_nchildren) !=0) 365 sc->gic_nchildren = 0; 366 367 return (0); 368 369 error: 370 /* Failure so free resources */ 371 gic_v3_detach(dev); 372 count_error: 373 if (bootverbose) { 374 device_printf(dev, 375 "Failed to attach. Error %d\n", err); 376 } 377 378 return (err); 379 } 380 381 static void 382 gic_v3_add_children(ACPI_SUBTABLE_HEADER *entry, void *arg) 383 { 384 ACPI_MADT_GENERIC_TRANSLATOR *gict; 385 struct gic_v3_acpi_devinfo *di; 386 struct gic_v3_softc *sc; 387 device_t child, dev; 388 u_int xref; 389 int err, pxm; 390 391 if (entry->Type == ACPI_MADT_TYPE_GENERIC_TRANSLATOR) { 392 /* We have an ITS, add it as a child */ 393 gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry; 394 dev = arg; 395 sc = device_get_softc(dev); 396 397 di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO); 398 err = acpi_iort_its_lookup(gict->TranslationId, &xref, &pxm); 399 if (err != 0) { 400 free(di, M_GIC_V3); 401 return; 402 } 403 404 child = device_add_child(dev, "its", -1); 405 if (child == NULL) { 406 free(di, M_GIC_V3); 407 return; 408 } 409 410 di->di_gic_dinfo.gic_domain = pxm; 411 di->di_gic_dinfo.msi_xref = xref; 412 resource_list_init(&di->di_rl); 413 resource_list_add(&di->di_rl, SYS_RES_MEMORY, 0, 414 gict->BaseAddress, gict->BaseAddress + 128 * 1024 - 1, 415 128 * 1024); 416 sc->gic_nchildren++; 417 device_set_ivars(child, di); 418 } 419 } 420 421 static void 422 gic_v3_acpi_bus_attach(device_t dev) 423 { 424 struct gic_v3_acpi_devinfo *di; 425 struct gic_v3_softc *sc; 426 ACPI_TABLE_MADT *madt; 427 device_t child; 428 vm_paddr_t physaddr; 429 430 sc = device_get_softc(dev); 431 432 physaddr = acpi_find_table(ACPI_SIG_MADT); 433 if (physaddr == 0) 434 return; 435 436 madt = acpi_map_table(physaddr, ACPI_SIG_MADT); 437 if (madt == NULL) { 438 device_printf(dev, "Unable to map the MADT to add children\n"); 439 return; 440 } 441 442 acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 443 gic_v3_add_children, dev); 444 /* Add the vgic child if needed */ 445 if (((uintptr_t)acpi_get_private(dev) & GICV3_PRIV_FLAGS) != 0) { 446 child = device_add_child(dev, "vgic", -1); 447 if (child == NULL) { 448 device_printf(dev, "Could not add vgic child\n"); 449 } else { 450 di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO); 451 resource_list_init(&di->di_rl); 452 di->di_gic_dinfo.gic_domain = -1; 453 di->di_gic_dinfo.is_vgic = 1; 454 device_set_ivars(child, di); 455 sc->gic_nchildren++; 456 } 457 } 458 459 acpi_unmap_table(madt); 460 461 bus_generic_attach(dev); 462 } 463 464 static struct resource_list * 465 gic_v3_acpi_get_resource_list(device_t bus, device_t child) 466 { 467 struct gic_v3_acpi_devinfo *di; 468 469 di = device_get_ivars(child); 470 KASSERT(di != NULL, ("%s: No devinfo", __func__)); 471 472 return (&di->di_rl); 473 } 474