1 /*- 2 * Copyright (c) 2016, Anish Gupta (anish@freebsd.org) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_acpi.h" 31 #include <sys/param.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/malloc.h> 36 37 #include <machine/vmparam.h> 38 39 #include <vm/vm.h> 40 #include <vm/pmap.h> 41 42 #include <contrib/dev/acpica/include/acpi.h> 43 #include <contrib/dev/acpica/include/accommon.h> 44 #include <dev/acpica/acpivar.h> 45 46 #include "io/iommu.h" 47 #include "amdvi_priv.h" 48 49 device_t *ivhd_devs; /* IVHD or AMD-Vi device list. */ 50 int ivhd_count; /* Number of IVHD or AMD-Vi devices. */ 51 52 extern int amdvi_ptp_level; /* Page table levels. */ 53 54 typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER * ptr, void *arg); 55 56 /* 57 * Iterate IVRS table for IVHD and IVMD device type. 58 */ 59 static void 60 ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg) 61 { 62 ACPI_TABLE_IVRS *ivrs; 63 ACPI_IVRS_HEADER *ivrs_hdr, *end; 64 ACPI_STATUS status; 65 66 status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); 67 if (ACPI_FAILURE(status)) 68 return; 69 70 if (ivrs->Header.Length == 0) { 71 return; 72 } 73 74 ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1); 75 end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length); 76 77 while (ivrs_hdr < end) { 78 if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) { 79 printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n", 80 ivrs_hdr->Length); 81 break; 82 } 83 84 switch (ivrs_hdr->Type) { 85 case ACPI_IVRS_TYPE_HARDWARE: /* Legacy */ 86 case 0x11: 87 case 0x40: /* ACPI HID */ 88 if (!iter(ivrs_hdr, arg)) 89 return; 90 break; 91 92 case ACPI_IVRS_TYPE_MEMORY1: 93 case ACPI_IVRS_TYPE_MEMORY2: 94 case ACPI_IVRS_TYPE_MEMORY3: 95 if (!iter(ivrs_hdr, arg)) 96 return; 97 98 break; 99 100 default: 101 printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type); 102 103 } 104 105 ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr + 106 ivrs_hdr->Length); 107 } 108 } 109 110 static int 111 ivrs_is_ivhd(UINT8 type) 112 { 113 114 if ((type == ACPI_IVRS_TYPE_HARDWARE) || (type == 0x11) || (type == 0x40)) 115 return (1); 116 117 return (0); 118 } 119 120 /* Count the number of AMD-Vi devices in the system. */ 121 static int 122 ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg) 123 { 124 125 if (ivrs_is_ivhd(ivrs_he->Type)) 126 ivhd_count++; 127 128 return (1); 129 } 130 131 struct find_ivrs_hdr_args { 132 int i; 133 ACPI_IVRS_HEADER *ptr; 134 }; 135 136 static int 137 ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args) 138 { 139 struct find_ivrs_hdr_args *fi; 140 141 fi = (struct find_ivrs_hdr_args *)args; 142 if (ivrs_is_ivhd(ivrs_hdr->Type)) { 143 if (fi->i == 0) { 144 fi->ptr = ivrs_hdr; 145 return (0); 146 } 147 fi->i--; 148 } 149 150 return (1); 151 } 152 153 static ACPI_IVRS_HARDWARE * 154 ivhd_find_by_index(int idx) 155 { 156 struct find_ivrs_hdr_args fi; 157 158 fi.i = idx; 159 fi.ptr = NULL; 160 161 ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi); 162 163 return ((ACPI_IVRS_HARDWARE *)fi.ptr); 164 } 165 166 static void 167 ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id, 168 uint32_t end_id, uint8_t cfg, bool ats) 169 { 170 struct ivhd_dev_cfg *dev_cfg; 171 172 /* If device doesn't have special data, don't add it. */ 173 if (!cfg) 174 return; 175 176 dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++]; 177 dev_cfg->start_id = start_id; 178 dev_cfg->end_id = end_id; 179 dev_cfg->data = cfg; 180 dev_cfg->enable_ats = ats; 181 } 182 183 /* 184 * Record device attributes as suggested by BIOS. 185 */ 186 static int 187 ivhd_dev_parse(ACPI_IVRS_HARDWARE * ivhd, struct amdvi_softc *softc) 188 { 189 ACPI_IVRS_DE_HEADER *de; 190 uint8_t *p, *end; 191 int range_start_id = 0, range_end_id = 0; 192 uint32_t *extended; 193 uint8_t all_data = 0, range_data = 0; 194 bool range_enable_ats = false, enable_ats; 195 196 softc->start_dev_rid = ~0; 197 softc->end_dev_rid = 0; 198 199 /* 200 * XXX The following actually depends on Header.Type and 201 * is only true for 0x10. 202 */ 203 p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE); 204 end = (uint8_t *)ivhd + ivhd->Header.Length; 205 206 while (p < end) { 207 de = (ACPI_IVRS_DE_HEADER *)p; 208 softc->start_dev_rid = MIN(softc->start_dev_rid, de->Id); 209 softc->end_dev_rid = MAX(softc->end_dev_rid, de->Id); 210 switch (de->Type) { 211 case ACPI_IVRS_TYPE_ALL: 212 all_data = de->DataSetting; 213 break; 214 215 case ACPI_IVRS_TYPE_SELECT: 216 case ACPI_IVRS_TYPE_ALIAS_SELECT: 217 case ACPI_IVRS_TYPE_EXT_SELECT: 218 enable_ats = false; 219 if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) { 220 extended = (uint32_t *)(de + 1); 221 enable_ats = 222 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 223 false : true; 224 } 225 ivhd_dev_add_entry(softc, de->Id, de->Id, 226 de->DataSetting | all_data, enable_ats); 227 break; 228 229 case ACPI_IVRS_TYPE_START: 230 case ACPI_IVRS_TYPE_ALIAS_START: 231 case ACPI_IVRS_TYPE_EXT_START: 232 range_start_id = de->Id; 233 range_data = de->DataSetting; 234 if (de->Type == ACPI_IVRS_TYPE_EXT_START) { 235 extended = (uint32_t *)(de + 1); 236 range_enable_ats = 237 (*extended & IVHD_DEV_EXT_ATS_DISABLE) ? 238 false : true; 239 } 240 break; 241 242 case ACPI_IVRS_TYPE_END: 243 range_end_id = de->Id; 244 ivhd_dev_add_entry(softc, range_start_id, range_end_id, 245 range_data | all_data, range_enable_ats); 246 range_start_id = range_end_id = 0; 247 range_data = 0; 248 all_data = 0; 249 break; 250 251 case ACPI_IVRS_TYPE_PAD4: 252 break; 253 254 case ACPI_IVRS_TYPE_SPECIAL: 255 /* HPET or IOAPIC */ 256 break; 257 default: 258 if ((de->Type < 5) || 259 (de->Type >= ACPI_IVRS_TYPE_PAD8)) 260 device_printf(softc->dev, 261 "Unknown dev entry:0x%x\n", de->Type); 262 } 263 264 if (softc->dev_cfg_cnt > 265 (sizeof(softc->dev_cfg) / sizeof(softc->dev_cfg[0]))) { 266 device_printf(softc->dev, 267 "WARN Too many device entries.\n"); 268 return (EINVAL); 269 } 270 if (de->Type < 0x40) 271 p += sizeof(ACPI_IVRS_DEVICE4); 272 else if (de->Type < 0x80) 273 p += sizeof(ACPI_IVRS_DEVICE8A); 274 else { 275 printf("Variable size IVHD type 0x%x not supported\n", 276 de->Type); 277 break; 278 } 279 } 280 281 KASSERT((softc->end_dev_rid >= softc->start_dev_rid), 282 ("Device end[0x%x] < start[0x%x.\n", 283 softc->end_dev_rid, softc->start_dev_rid)); 284 285 return (0); 286 } 287 288 static void 289 ivhd_identify(driver_t *driver, device_t parent) 290 { 291 ACPI_TABLE_IVRS *ivrs; 292 ACPI_IVRS_HARDWARE *ivhd; 293 ACPI_STATUS status; 294 uint32_t info; 295 int i, count = 0; 296 297 if (acpi_disabled("ivhd")) 298 return; 299 300 status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs); 301 if (ACPI_FAILURE(status)) 302 return; 303 304 if (ivrs->Header.Length == 0) { 305 return; 306 } 307 308 info = ivrs->Info; 309 printf("AMD-Vi IVRS VAsize = %d PAsize = %d GVAsize = %d flags:%b\n", 310 REG_BITS(info, 21, 15), REG_BITS(info, 14, 8), 311 REG_BITS(info, 7, 5), REG_BITS(info, 22, 22), 312 "\020\001HtAtsResv"); 313 314 ivrs_hdr_iterate_tbl(ivhd_count_iter, NULL); 315 if (!ivhd_count) 316 return; 317 318 ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF, 319 M_WAITOK | M_ZERO); 320 for (i = 0; i < ivhd_count; i++) { 321 ivhd = ivhd_find_by_index(i); 322 if (ivhd == NULL) { 323 printf("Can't find IVHD entry%d\n", i); 324 continue; 325 } 326 327 /* 328 * Use a high order to ensure that this driver is probed after 329 * the Host-PCI bridge and the root PCI bus. 330 */ 331 ivhd_devs[i] = BUS_ADD_CHILD(parent, 332 ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i); 333 334 /* 335 * XXX: In case device was not destroyed before, add will fail. 336 * locate the old device instance. 337 */ 338 if (ivhd_devs[i] == NULL) { 339 ivhd_devs[i] = device_find_child(parent, "ivhd", i); 340 if (ivhd_devs[i] == NULL) { 341 printf("AMD-Vi: cant find AMD-Vi dev%d\n", i); 342 break; 343 } 344 } 345 count++; 346 } 347 348 /* 349 * Update device count in case failed to attach. 350 */ 351 ivhd_count = count; 352 } 353 354 static int 355 ivhd_probe(device_t dev) 356 { 357 358 if (acpi_get_handle(dev) != NULL) 359 return (ENXIO); 360 device_set_desc(dev, "AMD-Vi/IOMMU or ivhd"); 361 362 return (BUS_PROBE_NOWILDCARD); 363 } 364 365 static int 366 ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE * ivhd) 367 { 368 device_t dev; 369 int max_ptp_level; 370 371 dev = softc->dev; 372 device_printf(dev, "Flag:%b\n", softc->ivhd_flag, 373 "\020\001HtTunEn\002PassPW\003ResPassPW\004Isoc\005IotlbSup" 374 "\006Coherent\007PreFSup\008PPRSup"); 375 /* 376 * If no extended feature[EFR], its rev1 with maximum paging level as 7. 377 */ 378 max_ptp_level = 7; 379 if (softc->ivhd_efr) { 380 device_printf(dev, "EFR HATS = %d GATS = %d GLXSup = %d " 381 "MsiNumPr = %d PNBanks= %d PNCounters= %d\n" 382 "max PASID = %d EFR: %b \n", 383 REG_BITS(softc->ivhd_efr, 31, 30), 384 REG_BITS(softc->ivhd_efr, 29, 28), 385 REG_BITS(softc->ivhd_efr, 4, 3), 386 REG_BITS(softc->ivhd_efr, 27, 23), 387 REG_BITS(softc->ivhd_efr, 22, 17), 388 REG_BITS(softc->ivhd_efr, 16, 13), 389 REG_BITS(softc->ivhd_efr, 12, 8), 390 softc->ivhd_efr, "\020\001XTSup\002NXSup\003GTSup\005IASup" 391 "\006GASup\007HESup\008PPRSup"); 392 393 max_ptp_level = REG_BITS(softc->ivhd_efr, 31, 30) + 4; 394 } 395 396 /* Make sure device support minimum page level as requested by user. */ 397 if (max_ptp_level < amdvi_ptp_level) { 398 device_printf(dev, "Insufficient PTP level:%d\n", 399 max_ptp_level); 400 return (EINVAL); 401 } 402 403 device_printf(softc->dev, "max supported paging level:%d restricting to: %d\n", 404 max_ptp_level, amdvi_ptp_level); 405 device_printf(softc->dev, "device supported range " 406 "[0x%x - 0x%x]\n", softc->start_dev_rid, softc->end_dev_rid); 407 408 return (0); 409 } 410 411 static int 412 ivhd_attach(device_t dev) 413 { 414 ACPI_IVRS_HARDWARE *ivhd; 415 struct amdvi_softc *softc; 416 int status, unit; 417 418 unit = device_get_unit(dev); 419 /* Make sure its same device for which attach is called. */ 420 if (ivhd_devs[unit] != dev) 421 panic("Not same device old %p new %p", ivhd_devs[unit], dev); 422 423 softc = device_get_softc(dev); 424 softc->dev = dev; 425 ivhd = ivhd_find_by_index(unit); 426 if (ivhd == NULL) 427 return (EINVAL); 428 429 softc->pci_seg = ivhd->PciSegmentGroup; 430 softc->pci_rid = ivhd->Header.DeviceId; 431 softc->ivhd_flag = ivhd->Header.Flags; 432 softc->ivhd_efr = ivhd->Reserved; 433 /* 434 * PCI capability has more capabilities that are not part of IVRS. 435 */ 436 softc->cap_off = ivhd->CapabilityOffset; 437 438 #ifdef notyet 439 /* IVHD Info bit[4:0] is event MSI/X number. */ 440 softc->event_msix = ivhd->Info & 0x1F; 441 #endif 442 softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress); 443 status = ivhd_dev_parse(ivhd, softc); 444 if (status != 0) { 445 device_printf(dev, 446 "endpoint device parsing error=%d\n", status); 447 } 448 449 status = ivhd_print_cap(softc, ivhd); 450 if (status != 0) { 451 return (status); 452 } 453 454 status = amdvi_setup_hw(softc); 455 if (status != 0) { 456 device_printf(dev, "couldn't be initialised, error=%d\n", 457 status); 458 return (status); 459 } 460 461 return (0); 462 } 463 464 static int 465 ivhd_detach(device_t dev) 466 { 467 struct amdvi_softc *softc; 468 469 softc = device_get_softc(dev); 470 471 amdvi_teardown_hw(softc); 472 473 /* 474 * XXX: delete the device. 475 * don't allow detach, return EBUSY. 476 */ 477 return (0); 478 } 479 480 static int 481 ivhd_suspend(device_t dev) 482 { 483 484 return (0); 485 } 486 487 static int 488 ivhd_resume(device_t dev) 489 { 490 491 return (0); 492 } 493 494 static device_method_t ivhd_methods[] = { 495 DEVMETHOD(device_identify, ivhd_identify), 496 DEVMETHOD(device_probe, ivhd_probe), 497 DEVMETHOD(device_attach, ivhd_attach), 498 DEVMETHOD(device_detach, ivhd_detach), 499 DEVMETHOD(device_suspend, ivhd_suspend), 500 DEVMETHOD(device_resume, ivhd_resume), 501 DEVMETHOD_END 502 }; 503 504 static driver_t ivhd_driver = { 505 "ivhd", 506 ivhd_methods, 507 sizeof(struct amdvi_softc), 508 }; 509 510 static devclass_t ivhd_devclass; 511 512 /* 513 * Load this module at the end after PCI re-probing to configure interrupt. 514 */ 515 DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0, 516 SI_ORDER_ANY); 517 MODULE_DEPEND(ivhd, acpi, 1, 1, 1); 518 MODULE_DEPEND(ivhd, pci, 1, 1, 1); 519