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