1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include "amd_iommu_acpi.h" 27 #include "amd_iommu_impl.h" 28 29 static int create_acpi_hash(amd_iommu_acpi_t *acpi); 30 static void amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp); 31 32 static void dump_acpi_aliases(void); 33 34 35 /* 36 * Globals 37 */ 38 static amd_iommu_acpi_global_t *amd_iommu_acpi_global; 39 static amd_iommu_acpi_ivhd_t **amd_iommu_acpi_ivhd_hash; 40 static amd_iommu_acpi_ivmd_t **amd_iommu_acpi_ivmd_hash; 41 42 static int 43 type_byte_size(char *cp) 44 { 45 uint8_t type8 = *((uint8_t *)cp); 46 uint8_t len_bits; 47 48 len_bits = AMD_IOMMU_REG_GET8(&type8, AMD_IOMMU_ACPI_DEVENTRY_LEN); 49 50 switch (len_bits) { 51 case 0: 52 return (4); 53 case 1: 54 return (8); 55 case 2: 56 return (16); 57 case 3: 58 return (32); 59 default: 60 cmn_err(CE_WARN, "%s: Invalid deventry len: %d", 61 amd_iommu_modname, len_bits); 62 return (len_bits); 63 } 64 /*NOTREACHED*/ 65 } 66 67 static void 68 process_4byte_deventry(ivhd_container_t *c, char *cp) 69 { 70 int entry_type = *((uint8_t *)cp); 71 ivhd_deventry_t deventry = {0}; 72 ivhd_deventry_t *devp; 73 uint8_t datsetting8; 74 align_16_t al = {0}; 75 int i; 76 77 /* 4 byte entry */ 78 deventry.idev_len = 4; 79 deventry.idev_deviceid = -1; 80 deventry.idev_src_deviceid = -1; 81 82 for (i = 0; i < 2; i++) { 83 al.ent8[i] = *((uint8_t *)&cp[i + 1]); 84 } 85 86 switch (entry_type) { 87 case 1: 88 deventry.idev_type = DEVENTRY_ALL; 89 break; 90 case 2: 91 deventry.idev_type = DEVENTRY_SELECT; 92 deventry.idev_deviceid = al.ent16; 93 break; 94 case 3: 95 deventry.idev_type = DEVENTRY_RANGE; 96 deventry.idev_deviceid = al.ent16; 97 break; 98 case 4: 99 deventry.idev_type = DEVENTRY_RANGE_END; 100 deventry.idev_deviceid = al.ent16; 101 ASSERT(cp[3] == 0); 102 break; 103 case 0: 104 ASSERT(al.ent16 == 0); 105 ASSERT(cp[3] == 0); 106 default: 107 return; 108 } 109 110 111 devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP); 112 *devp = deventry; 113 114 if (c->ivhdc_first_deventry == NULL) 115 c->ivhdc_first_deventry = devp; 116 else 117 c->ivhdc_last_deventry->idev_next = devp; 118 119 c->ivhdc_last_deventry = devp; 120 121 if (entry_type == 4) 122 return; 123 124 datsetting8 = (*((uint8_t *)&cp[3])); 125 126 devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8, 127 AMD_IOMMU_ACPI_LINT1PASS); 128 129 devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8, 130 AMD_IOMMU_ACPI_LINT0PASS); 131 132 devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8, 133 AMD_IOMMU_ACPI_SYSMGT); 134 135 ASSERT(AMD_IOMMU_REG_GET8(&datsetting8, 136 AMD_IOMMU_ACPI_DATRSV) == 0); 137 138 devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8, 139 AMD_IOMMU_ACPI_NMIPASS); 140 141 devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8, 142 AMD_IOMMU_ACPI_EXTINTPASS); 143 144 devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8, 145 AMD_IOMMU_ACPI_INITPASS); 146 } 147 148 static void 149 process_8byte_deventry(ivhd_container_t *c, char *cp) 150 { 151 uint8_t datsetting8; 152 int entry_type = (uint8_t)*cp; 153 ivhd_deventry_t deventry = {0}; 154 ivhd_deventry_t *devp; 155 align_16_t al1 = {0}; 156 align_16_t al2 = {0}; 157 align_32_t al3 = {0}; 158 int i; 159 160 /* Length is 8 bytes */ 161 deventry.idev_len = 8; 162 deventry.idev_deviceid = -1; 163 deventry.idev_src_deviceid = -1; 164 165 for (i = 0; i < 2; i++) { 166 al1.ent8[i] = *((uint8_t *)&cp[i+1]); 167 al2.ent8[i] = *((uint8_t *)&cp[i+5]); 168 } 169 170 datsetting8 = *((uint8_t *)&cp[3]); 171 172 switch (entry_type) { 173 case 66: 174 deventry.idev_type = DEVENTRY_ALIAS_SELECT; 175 deventry.idev_deviceid = al1.ent16; 176 deventry.idev_src_deviceid = al2.ent16; 177 ASSERT(cp[4] == 0); 178 ASSERT(cp[7] == 0); 179 break; 180 case 67: 181 deventry.idev_type = DEVENTRY_ALIAS_RANGE; 182 deventry.idev_deviceid = al1.ent16; 183 deventry.idev_src_deviceid = al2.ent16; 184 ASSERT(cp[4] == 0); 185 ASSERT(cp[7] == 0); 186 break; 187 case 70: 188 deventry.idev_type = DEVENTRY_EXTENDED_SELECT; 189 deventry.idev_deviceid = al1.ent16; 190 break; 191 case 71: 192 deventry.idev_type = DEVENTRY_EXTENDED_RANGE; 193 deventry.idev_deviceid = al1.ent16; 194 break; 195 case 72: 196 deventry.idev_type = DEVENTRY_SPECIAL_DEVICE; 197 ASSERT(al1.ent16 == 0); 198 deventry.idev_deviceid = -1; 199 deventry.idev_handle = cp[4]; 200 deventry.idev_variety = cp[7]; 201 deventry.idev_src_deviceid = al2.ent16; 202 default: 203 #ifdef BROKEN_ASSERT 204 for (i = 0; i < 7; i++) { 205 ASSERT(cp[i] == 0); 206 } 207 #endif 208 return; 209 } 210 211 212 devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP); 213 *devp = deventry; 214 215 if (c->ivhdc_first_deventry == NULL) 216 c->ivhdc_first_deventry = devp; 217 else 218 c->ivhdc_last_deventry->idev_next = devp; 219 220 c->ivhdc_last_deventry = devp; 221 222 devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8, 223 AMD_IOMMU_ACPI_LINT1PASS); 224 225 devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8, 226 AMD_IOMMU_ACPI_LINT0PASS); 227 228 devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8, 229 AMD_IOMMU_ACPI_SYSMGT); 230 231 ASSERT(AMD_IOMMU_REG_GET8(&datsetting8, 232 AMD_IOMMU_ACPI_DATRSV) == 0); 233 234 devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8, 235 AMD_IOMMU_ACPI_NMIPASS); 236 237 devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8, 238 AMD_IOMMU_ACPI_EXTINTPASS); 239 240 devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8, 241 AMD_IOMMU_ACPI_INITPASS); 242 243 if (entry_type != 70 && entry_type != 71) { 244 return; 245 } 246 247 /* Type 70 and 71 */ 248 for (i = 0; i < 4; i++) { 249 al3.ent8[i] = *((uint8_t *)&cp[i+4]); 250 } 251 252 devp->idev_AtsDisabled = AMD_IOMMU_REG_GET8(&al3.ent32, 253 AMD_IOMMU_ACPI_ATSDISABLED); 254 255 ASSERT(AMD_IOMMU_REG_GET8(&al3.ent32, AMD_IOMMU_ACPI_EXTDATRSV) == 0); 256 } 257 258 static void 259 process_ivhd(amd_iommu_acpi_t *acpi, ivhd_t *ivhdp) 260 { 261 ivhd_container_t *c; 262 caddr_t ivhd_end; 263 caddr_t ivhd_tot_end; 264 caddr_t cp; 265 266 ASSERT(ivhdp->ivhd_type == 0x10); 267 268 c = kmem_zalloc(sizeof (ivhd_container_t), KM_SLEEP); 269 c->ivhdc_ivhd = kmem_alloc(sizeof (ivhd_t), KM_SLEEP); 270 *(c->ivhdc_ivhd) = *ivhdp; 271 272 if (acpi->acp_first_ivhdc == NULL) 273 acpi->acp_first_ivhdc = c; 274 else 275 acpi->acp_last_ivhdc->ivhdc_next = c; 276 277 acpi->acp_last_ivhdc = c; 278 279 ivhd_end = (caddr_t)ivhdp + sizeof (ivhd_t); 280 ivhd_tot_end = (caddr_t)ivhdp + ivhdp->ivhd_len; 281 282 for (cp = ivhd_end; cp < ivhd_tot_end; cp += type_byte_size(cp)) { 283 /* 16 byte and 32 byte size are currently reserved */ 284 switch (type_byte_size(cp)) { 285 case 4: 286 process_4byte_deventry(c, cp); 287 break; 288 case 8: 289 process_8byte_deventry(c, cp); 290 break; 291 case 16: 292 case 32: 293 /* Reserved */ 294 break; 295 default: 296 cmn_err(CE_WARN, "%s: unsupported length for device " 297 "entry in ACPI IVRS table's IVHD entry", 298 amd_iommu_modname); 299 break; 300 } 301 } 302 } 303 304 static void 305 process_ivmd(amd_iommu_acpi_t *acpi, ivmd_t *ivmdp) 306 { 307 ivmd_container_t *c; 308 309 ASSERT(ivmdp->ivmd_type != 0x10); 310 311 c = kmem_zalloc(sizeof (ivmd_container_t), KM_SLEEP); 312 c->ivmdc_ivmd = kmem_alloc(sizeof (ivmd_t), KM_SLEEP); 313 *(c->ivmdc_ivmd) = *ivmdp; 314 315 if (acpi->acp_first_ivmdc == NULL) 316 acpi->acp_first_ivmdc = c; 317 else 318 acpi->acp_last_ivmdc->ivmdc_next = c; 319 320 acpi->acp_last_ivmdc = c; 321 } 322 323 int 324 amd_iommu_acpi_init(void) 325 { 326 ivrs_t *ivrsp; 327 caddr_t ivrsp_end; 328 caddr_t table_end; 329 caddr_t cp; 330 uint8_t type8; 331 amd_iommu_acpi_t *acpi; 332 align_ivhd_t al_vhd = {0}; 333 align_ivmd_t al_vmd = {0}; 334 335 if (AcpiGetTable(IVRS_SIG, 1, (ACPI_TABLE_HEADER **)&ivrsp) != AE_OK) { 336 cmn_err(CE_NOTE, "!amd_iommu: No AMD IOMMU ACPI IVRS table"); 337 return (DDI_FAILURE); 338 } 339 340 /* 341 * Reserved field must be 0 342 */ 343 ASSERT(ivrsp->ivrs_resv == 0); 344 345 ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo, 346 AMD_IOMMU_ACPI_IVINFO_RSV1) == 0); 347 ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo, 348 AMD_IOMMU_ACPI_IVINFO_RSV2) == 0); 349 350 ivrsp_end = (caddr_t)ivrsp + sizeof (struct ivrs); 351 table_end = (caddr_t)ivrsp + ivrsp->ivrs_hdr.Length; 352 353 acpi = kmem_zalloc(sizeof (amd_iommu_acpi_t), KM_SLEEP); 354 acpi->acp_ivrs = kmem_alloc(sizeof (ivrs_t), KM_SLEEP); 355 *(acpi->acp_ivrs) = *ivrsp; 356 357 for (cp = ivrsp_end; cp < table_end; cp += (al_vhd.ivhdp)->ivhd_len) { 358 al_vhd.cp = cp; 359 if (al_vhd.ivhdp->ivhd_type == 0x10) 360 process_ivhd(acpi, al_vhd.ivhdp); 361 } 362 363 for (cp = ivrsp_end; cp < table_end; cp += (al_vmd.ivmdp)->ivmd_len) { 364 al_vmd.cp = cp; 365 type8 = al_vmd.ivmdp->ivmd_type; 366 if (type8 == 0x20 || type8 == 0x21 || type8 == 0x22) 367 process_ivmd(acpi, al_vmd.ivmdp); 368 } 369 370 if (create_acpi_hash(acpi) != DDI_SUCCESS) { 371 return (DDI_FAILURE); 372 } 373 374 amd_iommu_acpi_table_fini(&acpi); 375 376 ASSERT(acpi == NULL); 377 378 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 379 dump_acpi_aliases(); 380 debug_enter("dump"); 381 } 382 383 return (DDI_SUCCESS); 384 } 385 386 static ivhd_deventry_t * 387 free_ivhd_deventry(ivhd_deventry_t *devp) 388 { 389 ivhd_deventry_t *next = devp->idev_next; 390 391 kmem_free(devp, sizeof (ivhd_deventry_t)); 392 393 return (next); 394 } 395 396 static ivhd_container_t * 397 free_ivhd_container(ivhd_container_t *ivhdcp) 398 { 399 ivhd_container_t *next = ivhdcp->ivhdc_next; 400 ivhd_deventry_t *devp; 401 402 for (devp = ivhdcp->ivhdc_first_deventry; devp; ) { 403 devp = free_ivhd_deventry(devp); 404 } 405 406 kmem_free(ivhdcp->ivhdc_ivhd, sizeof (ivhd_t)); 407 kmem_free(ivhdcp, sizeof (ivhd_container_t)); 408 409 return (next); 410 } 411 412 static ivmd_container_t * 413 free_ivmd_container(ivmd_container_t *ivmdcp) 414 { 415 ivmd_container_t *next = ivmdcp->ivmdc_next; 416 417 kmem_free(ivmdcp->ivmdc_ivmd, sizeof (ivmd_t)); 418 kmem_free(ivmdcp, sizeof (ivmd_container_t)); 419 420 return (next); 421 } 422 423 void 424 amd_iommu_acpi_fini(void) 425 { 426 } 427 428 /* 429 * TODO: Do we need to free the ACPI table for om GetFirmwareTable() 430 */ 431 static void 432 amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp) 433 { 434 amd_iommu_acpi_t *acpi = *acpipp; 435 ivhd_container_t *ivhdcp; 436 ivmd_container_t *ivmdcp; 437 438 ASSERT(acpi); 439 440 for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp; ) { 441 ivhdcp = free_ivhd_container(ivhdcp); 442 } 443 for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp; ) { 444 ivmdcp = free_ivmd_container(ivmdcp); 445 } 446 447 kmem_free(acpi->acp_ivrs, sizeof (struct ivrs)); 448 kmem_free(acpi, sizeof (amd_iommu_acpi_t)); 449 450 *acpipp = NULL; 451 } 452 453 static uint16_t 454 deviceid_hashfn(uint16_t deviceid) 455 { 456 return (deviceid % AMD_IOMMU_ACPI_INFO_HASH_SZ); 457 } 458 459 static void 460 add_deventry_info(ivhd_t *ivhdp, ivhd_deventry_t *deventry, 461 amd_iommu_acpi_ivhd_t **hash) 462 { 463 static amd_iommu_acpi_ivhd_t *last; 464 amd_iommu_acpi_ivhd_t *acpi_ivhdp; 465 uint8_t uint8_flags; 466 uint16_t uint16_info; 467 uint16_t idx; 468 469 if (deventry->idev_type == DEVENTRY_RANGE_END) { 470 ASSERT(last); 471 acpi_ivhdp = last; 472 last = NULL; 473 ASSERT(acpi_ivhdp->ach_dev_type == DEVENTRY_RANGE || 474 acpi_ivhdp->ach_dev_type == DEVENTRY_ALIAS_RANGE || 475 acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE); 476 ASSERT(acpi_ivhdp->ach_deviceid_end == -1); 477 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 478 /* TODO ASSERT data is 0 */ 479 return; 480 } 481 482 ASSERT(last == NULL); 483 acpi_ivhdp = kmem_zalloc(sizeof (*acpi_ivhdp), KM_SLEEP); 484 485 uint8_flags = ivhdp->ivhd_flags; 486 487 #ifdef BROKEN_ASSERT 488 ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags, 489 AMD_IOMMU_ACPI_IVHD_FLAGS_RSV) == 0); 490 #endif 491 492 acpi_ivhdp->ach_IotlbSup = AMD_IOMMU_REG_GET8(&uint8_flags, 493 AMD_IOMMU_ACPI_IVHD_FLAGS_IOTLBSUP); 494 acpi_ivhdp->ach_Isoc = AMD_IOMMU_REG_GET8(&uint8_flags, 495 AMD_IOMMU_ACPI_IVHD_FLAGS_ISOC); 496 acpi_ivhdp->ach_ResPassPW = AMD_IOMMU_REG_GET8(&uint8_flags, 497 AMD_IOMMU_ACPI_IVHD_FLAGS_RESPASSPW); 498 acpi_ivhdp->ach_PassPW = AMD_IOMMU_REG_GET8(&uint8_flags, 499 AMD_IOMMU_ACPI_IVHD_FLAGS_PASSPW); 500 acpi_ivhdp->ach_HtTunEn = AMD_IOMMU_REG_GET8(&uint8_flags, 501 AMD_IOMMU_ACPI_IVHD_FLAGS_HTTUNEN); 502 503 /* IVHD fields */ 504 acpi_ivhdp->ach_IOMMU_deviceid = ivhdp->ivhd_deviceid; 505 acpi_ivhdp->ach_IOMMU_cap_off = ivhdp->ivhd_cap_off; 506 acpi_ivhdp->ach_IOMMU_reg_base = ivhdp->ivhd_reg_base; 507 acpi_ivhdp->ach_IOMMU_pci_seg = ivhdp->ivhd_pci_seg; 508 509 /* IVHD IOMMU info fields */ 510 uint16_info = ivhdp->ivhd_iommu_info; 511 512 #ifdef BROKEN_ASSERT 513 ASSERT(AMD_IOMMU_REG_GET16(&uint16_info, 514 AMD_IOMMU_ACPI_IOMMU_INFO_RSV1) == 0); 515 #endif 516 517 acpi_ivhdp->ach_IOMMU_UnitID = AMD_IOMMU_REG_GET16(&uint16_info, 518 AMD_IOMMU_ACPI_IOMMU_INFO_UNITID); 519 ASSERT(AMD_IOMMU_REG_GET16(&uint16_info, 520 AMD_IOMMU_ACPI_IOMMU_INFO_RSV2) == 0); 521 acpi_ivhdp->ach_IOMMU_MSInum = AMD_IOMMU_REG_GET16(&uint16_info, 522 AMD_IOMMU_ACPI_IOMMU_INFO_MSINUM); 523 524 /* Initialize deviceids to -1 */ 525 acpi_ivhdp->ach_deviceid_start = -1; 526 acpi_ivhdp->ach_deviceid_end = -1; 527 acpi_ivhdp->ach_src_deviceid = -1; 528 529 /* All range type entries are put on hash entry 0 */ 530 switch (deventry->idev_type) { 531 case DEVENTRY_ALL: 532 acpi_ivhdp->ach_deviceid_start = 0; 533 acpi_ivhdp->ach_deviceid_end = (uint16_t)-1; 534 acpi_ivhdp->ach_dev_type = DEVENTRY_ALL; 535 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 536 break; 537 case DEVENTRY_SELECT: 538 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 539 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 540 acpi_ivhdp->ach_dev_type = DEVENTRY_SELECT; 541 idx = deviceid_hashfn(deventry->idev_deviceid); 542 break; 543 case DEVENTRY_RANGE: 544 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 545 acpi_ivhdp->ach_deviceid_end = -1; 546 acpi_ivhdp->ach_dev_type = DEVENTRY_RANGE; 547 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 548 last = acpi_ivhdp; 549 break; 550 case DEVENTRY_RANGE_END: 551 cmn_err(CE_PANIC, "%s: Unexpected Range End Deventry", 552 amd_iommu_modname); 553 /*NOTREACHED*/ 554 case DEVENTRY_ALIAS_SELECT: 555 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 556 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 557 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 558 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_SELECT; 559 idx = deviceid_hashfn(deventry->idev_deviceid); 560 break; 561 case DEVENTRY_ALIAS_RANGE: 562 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 563 acpi_ivhdp->ach_deviceid_end = -1; 564 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 565 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_RANGE; 566 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 567 last = acpi_ivhdp; 568 break; 569 case DEVENTRY_EXTENDED_SELECT: 570 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 571 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 572 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_SELECT; 573 idx = deviceid_hashfn(deventry->idev_deviceid); 574 break; 575 case DEVENTRY_EXTENDED_RANGE: 576 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 577 acpi_ivhdp->ach_deviceid_end = -1; 578 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_RANGE; 579 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 580 last = acpi_ivhdp; 581 break; 582 case DEVENTRY_SPECIAL_DEVICE: 583 acpi_ivhdp->ach_deviceid_start = -1; 584 acpi_ivhdp->ach_deviceid_end = -1; 585 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 586 acpi_ivhdp->ach_special_handle = deventry->idev_handle; 587 acpi_ivhdp->ach_special_variety = deventry->idev_variety; 588 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 589 default: 590 cmn_err(CE_PANIC, "%s: Unsupported deventry type", 591 amd_iommu_modname); 592 /*NOTREACHED*/ 593 } 594 595 acpi_ivhdp->ach_Lint1Pass = deventry->idev_Lint1Pass; 596 acpi_ivhdp->ach_Lint0Pass = deventry->idev_Lint0Pass; 597 acpi_ivhdp->ach_SysMgt = deventry->idev_SysMgt; 598 acpi_ivhdp->ach_NMIPass = deventry->idev_NMIPass; 599 acpi_ivhdp->ach_ExtIntPass = deventry->idev_ExtIntPass; 600 acpi_ivhdp->ach_INITPass = deventry->idev_INITPass; 601 602 603 /* extended data */ 604 if (acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_SELECT || 605 acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE) { 606 acpi_ivhdp->ach_AtsDisabled = deventry->idev_AtsDisabled; 607 } 608 609 /* 610 * Now add it to the hash 611 */ 612 ASSERT(hash[idx] != acpi_ivhdp); 613 acpi_ivhdp->ach_next = hash[idx]; 614 hash[idx] = acpi_ivhdp; 615 } 616 617 /* 618 * A device entry may be declared implicitly as a source device ID 619 * in an alias entry. This routine adds it to the hash 620 */ 621 static void 622 add_implicit_deventry(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash) 623 { 624 ivhd_deventry_t *d; 625 int deviceid; 626 627 for (d = ivhdcp->ivhdc_first_deventry; d; d = d->idev_next) { 628 629 if ((d->idev_type != DEVENTRY_ALIAS_SELECT) && 630 (d->idev_type != DEVENTRY_ALIAS_RANGE)) 631 continue; 632 633 deviceid = d->idev_src_deviceid; 634 635 if (amd_iommu_lookup_ivhd(deviceid) == NULL) { 636 ivhd_deventry_t deventry; 637 638 /* Fake a SELECT entry */ 639 deventry.idev_type = DEVENTRY_SELECT; 640 deventry.idev_len = 4; 641 deventry.idev_deviceid = deviceid; 642 deventry.idev_src_deviceid = -1; 643 644 deventry.idev_Lint1Pass = d->idev_Lint1Pass; 645 deventry.idev_Lint0Pass = d->idev_Lint0Pass; 646 deventry.idev_SysMgt = d->idev_SysMgt; 647 deventry.idev_NMIPass = d->idev_NMIPass; 648 deventry.idev_ExtIntPass = d->idev_ExtIntPass; 649 deventry.idev_INITPass = d->idev_INITPass; 650 651 add_deventry_info(ivhdcp->ivhdc_ivhd, &deventry, hash); 652 653 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 654 cmn_err(CE_NOTE, "Added implicit IVHD entry " 655 "for: deviceid = %u", deviceid); 656 } 657 } 658 } 659 } 660 661 static void 662 add_ivhdc_info(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash) 663 { 664 ivhd_deventry_t *deventry; 665 ivhd_t *ivhdp = ivhdcp->ivhdc_ivhd; 666 667 for (deventry = ivhdcp->ivhdc_first_deventry; deventry; 668 deventry = deventry->idev_next) { 669 add_deventry_info(ivhdp, deventry, hash); 670 } 671 672 add_implicit_deventry(ivhdcp, hash); 673 674 } 675 676 static void 677 add_ivhd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivhd_t **hash) 678 { 679 ivhd_container_t *ivhdcp; 680 681 for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp; 682 ivhdcp = ivhdcp->ivhdc_next) { 683 add_ivhdc_info(ivhdcp, hash); 684 } 685 } 686 687 static void 688 set_ivmd_info(ivmd_t *ivmdp, amd_iommu_acpi_ivmd_t **hash) 689 { 690 amd_iommu_acpi_ivmd_t *acpi_ivmdp; 691 uint8_t uint8_flags; 692 uint16_t idx; 693 694 uint8_flags = ivmdp->ivmd_flags; 695 696 acpi_ivmdp = kmem_zalloc(sizeof (*acpi_ivmdp), KM_SLEEP); 697 698 switch (ivmdp->ivmd_type) { 699 case 0x20: 700 acpi_ivmdp->acm_deviceid_start = 0; 701 acpi_ivmdp->acm_deviceid_end = (uint16_t)-1; 702 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_ALL; 703 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 704 break; 705 case 0x21: 706 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid; 707 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_deviceid; 708 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_SELECT; 709 idx = deviceid_hashfn(ivmdp->ivmd_deviceid); 710 break; 711 case 0x22: 712 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid; 713 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_auxdata; 714 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_RANGE; 715 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 716 break; 717 default: 718 cmn_err(CE_PANIC, "Unknown AMD IOMMU ACPI IVMD deviceid type: " 719 "%x", ivmdp->ivmd_type); 720 /*NOTREACHED*/ 721 } 722 723 ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags, 724 AMD_IOMMU_ACPI_IVMD_RSV) == 0); 725 726 acpi_ivmdp->acm_ExclRange = AMD_IOMMU_REG_GET8(&uint8_flags, 727 AMD_IOMMU_ACPI_IVMD_EXCL_RANGE); 728 acpi_ivmdp->acm_IW = AMD_IOMMU_REG_GET8(&uint8_flags, 729 AMD_IOMMU_ACPI_IVMD_IW); 730 acpi_ivmdp->acm_IR = AMD_IOMMU_REG_GET8(&uint8_flags, 731 AMD_IOMMU_ACPI_IVMD_IR); 732 acpi_ivmdp->acm_Unity = AMD_IOMMU_REG_GET8(&uint8_flags, 733 AMD_IOMMU_ACPI_IVMD_UNITY); 734 735 acpi_ivmdp->acm_ivmd_phys_start = ivmdp->ivmd_phys_start; 736 acpi_ivmdp->acm_ivmd_phys_len = ivmdp->ivmd_phys_len; 737 738 acpi_ivmdp->acm_next = hash[idx]; 739 hash[idx] = acpi_ivmdp; 740 } 741 742 static void 743 add_ivmdc_info(ivmd_container_t *ivmdcp, amd_iommu_acpi_ivmd_t **hash) 744 { 745 set_ivmd_info(ivmdcp->ivmdc_ivmd, hash); 746 } 747 748 static void 749 add_ivmd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivmd_t **hash) 750 { 751 ivmd_container_t *ivmdcp; 752 753 for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp; 754 ivmdcp = ivmdcp->ivmdc_next) { 755 add_ivmdc_info(ivmdcp, hash); 756 } 757 } 758 759 static void 760 add_global_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_global_t *global) 761 { 762 uint32_t ivrs_ivinfo = acpi->acp_ivrs->ivrs_ivinfo; 763 764 global->acg_HtAtsResv = 765 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_HT_ATSRSV); 766 global->acg_VAsize = 767 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_VA_SIZE); 768 global->acg_PAsize = 769 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_PA_SIZE); 770 } 771 772 static int 773 create_acpi_hash(amd_iommu_acpi_t *acpi) 774 { 775 /* Last hash entry is for deviceid ranges including "all" */ 776 777 amd_iommu_acpi_global = kmem_zalloc(sizeof (amd_iommu_acpi_global_t), 778 KM_SLEEP); 779 780 amd_iommu_acpi_ivhd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivhd_t *) 781 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP); 782 783 amd_iommu_acpi_ivmd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivmd_t *) 784 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP); 785 786 add_global_info(acpi, amd_iommu_acpi_global); 787 788 add_ivhd_info(acpi, amd_iommu_acpi_ivhd_hash); 789 790 add_ivmd_info(acpi, amd_iommu_acpi_ivmd_hash); 791 792 return (DDI_SUCCESS); 793 } 794 795 static void 796 set_deventry(amd_iommu_t *iommu, int entry, amd_iommu_acpi_ivhd_t *hinfop) 797 { 798 uint64_t *dentry; 799 800 dentry = (uint64_t *)(intptr_t) 801 &iommu->aiomt_devtbl[entry * AMD_IOMMU_DEVTBL_ENTRY_SZ]; 802 803 AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SYSMGT, 804 hinfop->ach_SysMgt); 805 } 806 807 /* Initialize device table according to IVHD */ 808 int 809 amd_iommu_acpi_init_devtbl(amd_iommu_t *iommu) 810 { 811 int i, j; 812 amd_iommu_acpi_ivhd_t *hinfop; 813 814 for (i = 0; i <= AMD_IOMMU_ACPI_INFO_HASH_SZ; i++) { 815 for (hinfop = amd_iommu_acpi_ivhd_hash[i]; 816 hinfop; hinfop = hinfop->ach_next) { 817 818 if (hinfop->ach_IOMMU_deviceid != iommu->aiomt_bdf) 819 continue; 820 821 switch (hinfop->ach_dev_type) { 822 case DEVENTRY_ALL: 823 for (j = 0; j < AMD_IOMMU_MAX_DEVICEID; j++) 824 set_deventry(iommu, j, hinfop); 825 break; 826 case DEVENTRY_SELECT: 827 case DEVENTRY_EXTENDED_SELECT: 828 set_deventry(iommu, 829 hinfop->ach_deviceid_start, 830 hinfop); 831 break; 832 case DEVENTRY_RANGE: 833 case DEVENTRY_EXTENDED_RANGE: 834 for (j = hinfop->ach_deviceid_start; 835 j <= hinfop->ach_deviceid_end; 836 j++) 837 set_deventry(iommu, j, hinfop); 838 break; 839 case DEVENTRY_ALIAS_SELECT: 840 case DEVENTRY_ALIAS_RANGE: 841 case DEVENTRY_SPECIAL_DEVICE: 842 set_deventry(iommu, 843 hinfop->ach_src_deviceid, 844 hinfop); 845 break; 846 default: 847 cmn_err(CE_WARN, 848 "%s: Unknown deventry type", 849 amd_iommu_modname); 850 return (DDI_FAILURE); 851 } 852 } 853 } 854 855 return (DDI_SUCCESS); 856 } 857 858 amd_iommu_acpi_global_t * 859 amd_iommu_lookup_acpi_global(void) 860 { 861 ASSERT(amd_iommu_acpi_global); 862 863 return (amd_iommu_acpi_global); 864 } 865 866 amd_iommu_acpi_ivhd_t * 867 amd_iommu_lookup_all_ivhd(void) 868 { 869 amd_iommu_acpi_ivhd_t *hinfop; 870 871 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 872 for (; hinfop; hinfop = hinfop->ach_next) { 873 if (hinfop->ach_deviceid_start == 0 && 874 hinfop->ach_deviceid_end == (uint16_t)-1) { 875 break; 876 } 877 } 878 879 return (hinfop); 880 } 881 882 amd_iommu_acpi_ivmd_t * 883 amd_iommu_lookup_all_ivmd(void) 884 { 885 amd_iommu_acpi_ivmd_t *minfop; 886 887 minfop = amd_iommu_acpi_ivmd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 888 for (; minfop; minfop = minfop->acm_next) { 889 if (minfop->acm_deviceid_start == 0 && 890 minfop->acm_deviceid_end == (uint16_t)-1) { 891 break; 892 } 893 } 894 895 return (minfop); 896 } 897 898 amd_iommu_acpi_ivhd_t * 899 amd_iommu_lookup_any_ivhd(amd_iommu_t *iommu) 900 { 901 int i; 902 amd_iommu_acpi_ivhd_t *hinfop; 903 904 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) { 905 hinfop = amd_iommu_acpi_ivhd_hash[i]; 906 if ((hinfop != NULL) && 907 hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf) 908 break; 909 } 910 911 return (hinfop); 912 } 913 914 amd_iommu_acpi_ivmd_t * 915 amd_iommu_lookup_any_ivmd(void) 916 { 917 int i; 918 amd_iommu_acpi_ivmd_t *minfop; 919 920 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) { 921 if ((minfop = amd_iommu_acpi_ivmd_hash[i]) != NULL) 922 break; 923 } 924 925 return (minfop); 926 } 927 928 static void 929 dump_acpi_aliases(void) 930 { 931 amd_iommu_acpi_ivhd_t *hinfop; 932 uint16_t idx; 933 934 for (idx = 0; idx <= AMD_IOMMU_ACPI_INFO_HASH_SZ; idx++) { 935 hinfop = amd_iommu_acpi_ivhd_hash[idx]; 936 for (; hinfop; hinfop = hinfop->ach_next) { 937 cmn_err(CE_NOTE, "start=%d, end=%d, src_bdf=%d", 938 hinfop->ach_deviceid_start, 939 hinfop->ach_deviceid_end, 940 hinfop->ach_src_deviceid); 941 } 942 } 943 } 944 945 amd_iommu_acpi_ivhd_t * 946 amd_iommu_lookup_ivhd(int32_t deviceid) 947 { 948 amd_iommu_acpi_ivhd_t *hinfop; 949 uint16_t idx; 950 951 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 952 cmn_err(CE_NOTE, "Attempting to get ACPI IVHD info " 953 "for deviceid: %d", deviceid); 954 } 955 956 ASSERT(amd_iommu_acpi_ivhd_hash); 957 958 /* check if special device */ 959 if (deviceid == -1) { 960 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 961 for (; hinfop; hinfop = hinfop->ach_next) { 962 if (hinfop->ach_deviceid_start == -1 && 963 hinfop->ach_deviceid_end == -1) { 964 break; 965 } 966 } 967 return (hinfop); 968 } 969 970 /* First search for an exact match */ 971 972 idx = deviceid_hashfn(deviceid); 973 974 975 range: 976 hinfop = amd_iommu_acpi_ivhd_hash[idx]; 977 978 for (; hinfop; hinfop = hinfop->ach_next) { 979 if (deviceid < hinfop->ach_deviceid_start || 980 deviceid > hinfop->ach_deviceid_end) 981 continue; 982 983 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 984 cmn_err(CE_NOTE, "Found ACPI IVHD match: %p, " 985 "actual deviceid = %u, start = %u, end = %u", 986 (void *)hinfop, deviceid, 987 hinfop->ach_deviceid_start, 988 hinfop->ach_deviceid_end); 989 } 990 goto out; 991 } 992 993 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) { 994 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 995 goto range; 996 } 997 998 out: 999 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1000 cmn_err(CE_NOTE, "%u: %s ACPI IVHD %p", deviceid, 1001 hinfop ? "GOT" : "Did NOT get", (void *)hinfop); 1002 } 1003 1004 return (hinfop); 1005 } 1006 1007 amd_iommu_acpi_ivmd_t * 1008 amd_iommu_lookup_ivmd(int32_t deviceid) 1009 { 1010 amd_iommu_acpi_ivmd_t *minfop; 1011 uint16_t idx; 1012 1013 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1014 cmn_err(CE_NOTE, "Attempting to get ACPI IVMD info " 1015 "for deviceid: %u", deviceid); 1016 } 1017 1018 ASSERT(amd_iommu_acpi_ivmd_hash); 1019 1020 /* First search for an exact match */ 1021 1022 idx = deviceid_hashfn(deviceid); 1023 1024 range: 1025 minfop = amd_iommu_acpi_ivmd_hash[idx]; 1026 1027 for (; minfop; minfop = minfop->acm_next) { 1028 if (deviceid < minfop->acm_deviceid_start && 1029 deviceid > minfop->acm_deviceid_end) 1030 continue; 1031 1032 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1033 cmn_err(CE_NOTE, "Found ACPI IVMD match: %p, " 1034 "actual deviceid = %u, start = %u, end = %u", 1035 (void *)minfop, deviceid, 1036 minfop->acm_deviceid_start, 1037 minfop->acm_deviceid_end); 1038 } 1039 1040 goto out; 1041 } 1042 1043 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) { 1044 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 1045 goto range; 1046 } 1047 1048 out: 1049 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1050 cmn_err(CE_NOTE, "%u: %s ACPI IVMD info %p", deviceid, 1051 minfop ? "GOT" : "Did NOT get", (void *)minfop); 1052 } 1053 1054 return (minfop); 1055 } 1056