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 idx = 0; 552 cmn_err(CE_PANIC, "%s: Unexpected Range End Deventry", 553 amd_iommu_modname); 554 /*NOTREACHED*/ 555 break; 556 case DEVENTRY_ALIAS_SELECT: 557 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 558 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 559 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 560 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_SELECT; 561 idx = deviceid_hashfn(deventry->idev_deviceid); 562 break; 563 case DEVENTRY_ALIAS_RANGE: 564 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 565 acpi_ivhdp->ach_deviceid_end = -1; 566 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 567 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_RANGE; 568 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 569 last = acpi_ivhdp; 570 break; 571 case DEVENTRY_EXTENDED_SELECT: 572 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 573 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid; 574 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_SELECT; 575 idx = deviceid_hashfn(deventry->idev_deviceid); 576 break; 577 case DEVENTRY_EXTENDED_RANGE: 578 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid; 579 acpi_ivhdp->ach_deviceid_end = -1; 580 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_RANGE; 581 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 582 last = acpi_ivhdp; 583 break; 584 case DEVENTRY_SPECIAL_DEVICE: 585 acpi_ivhdp->ach_deviceid_start = -1; 586 acpi_ivhdp->ach_deviceid_end = -1; 587 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid; 588 acpi_ivhdp->ach_special_handle = deventry->idev_handle; 589 acpi_ivhdp->ach_special_variety = deventry->idev_variety; 590 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 591 break; 592 default: 593 idx = 0; 594 cmn_err(CE_PANIC, "%s: Unsupported deventry type", 595 amd_iommu_modname); 596 /*NOTREACHED*/ 597 } 598 599 acpi_ivhdp->ach_Lint1Pass = deventry->idev_Lint1Pass; 600 acpi_ivhdp->ach_Lint0Pass = deventry->idev_Lint0Pass; 601 acpi_ivhdp->ach_SysMgt = deventry->idev_SysMgt; 602 acpi_ivhdp->ach_NMIPass = deventry->idev_NMIPass; 603 acpi_ivhdp->ach_ExtIntPass = deventry->idev_ExtIntPass; 604 acpi_ivhdp->ach_INITPass = deventry->idev_INITPass; 605 606 607 /* extended data */ 608 if (acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_SELECT || 609 acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE) { 610 acpi_ivhdp->ach_AtsDisabled = deventry->idev_AtsDisabled; 611 } 612 613 /* 614 * Now add it to the hash 615 */ 616 ASSERT(hash[idx] != acpi_ivhdp); 617 acpi_ivhdp->ach_next = hash[idx]; 618 hash[idx] = acpi_ivhdp; 619 } 620 621 /* 622 * A device entry may be declared implicitly as a source device ID 623 * in an alias entry. This routine adds it to the hash 624 */ 625 static void 626 add_implicit_deventry(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash) 627 { 628 ivhd_deventry_t *d; 629 int deviceid; 630 631 for (d = ivhdcp->ivhdc_first_deventry; d; d = d->idev_next) { 632 633 if ((d->idev_type != DEVENTRY_ALIAS_SELECT) && 634 (d->idev_type != DEVENTRY_ALIAS_RANGE)) 635 continue; 636 637 deviceid = d->idev_src_deviceid; 638 639 if (amd_iommu_lookup_ivhd(deviceid) == NULL) { 640 ivhd_deventry_t deventry; 641 642 /* Fake a SELECT entry */ 643 deventry.idev_type = DEVENTRY_SELECT; 644 deventry.idev_len = 4; 645 deventry.idev_deviceid = deviceid; 646 deventry.idev_src_deviceid = -1; 647 648 deventry.idev_Lint1Pass = d->idev_Lint1Pass; 649 deventry.idev_Lint0Pass = d->idev_Lint0Pass; 650 deventry.idev_SysMgt = d->idev_SysMgt; 651 deventry.idev_NMIPass = d->idev_NMIPass; 652 deventry.idev_ExtIntPass = d->idev_ExtIntPass; 653 deventry.idev_INITPass = d->idev_INITPass; 654 655 add_deventry_info(ivhdcp->ivhdc_ivhd, &deventry, hash); 656 657 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 658 cmn_err(CE_NOTE, "Added implicit IVHD entry " 659 "for: deviceid = %u", deviceid); 660 } 661 } 662 } 663 } 664 665 static void 666 add_ivhdc_info(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash) 667 { 668 ivhd_deventry_t *deventry; 669 ivhd_t *ivhdp = ivhdcp->ivhdc_ivhd; 670 671 for (deventry = ivhdcp->ivhdc_first_deventry; deventry; 672 deventry = deventry->idev_next) { 673 add_deventry_info(ivhdp, deventry, hash); 674 } 675 676 add_implicit_deventry(ivhdcp, hash); 677 678 } 679 680 static void 681 add_ivhd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivhd_t **hash) 682 { 683 ivhd_container_t *ivhdcp; 684 685 for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp; 686 ivhdcp = ivhdcp->ivhdc_next) { 687 add_ivhdc_info(ivhdcp, hash); 688 } 689 } 690 691 static void 692 set_ivmd_info(ivmd_t *ivmdp, amd_iommu_acpi_ivmd_t **hash) 693 { 694 amd_iommu_acpi_ivmd_t *acpi_ivmdp; 695 uint8_t uint8_flags; 696 uint16_t idx; 697 698 uint8_flags = ivmdp->ivmd_flags; 699 700 acpi_ivmdp = kmem_zalloc(sizeof (*acpi_ivmdp), KM_SLEEP); 701 702 switch (ivmdp->ivmd_type) { 703 case 0x20: 704 acpi_ivmdp->acm_deviceid_start = 0; 705 acpi_ivmdp->acm_deviceid_end = (uint16_t)-1; 706 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_ALL; 707 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 708 break; 709 case 0x21: 710 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid; 711 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_deviceid; 712 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_SELECT; 713 idx = deviceid_hashfn(ivmdp->ivmd_deviceid); 714 break; 715 case 0x22: 716 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid; 717 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_auxdata; 718 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_RANGE; 719 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 720 break; 721 default: 722 idx = 0; 723 cmn_err(CE_PANIC, "Unknown AMD IOMMU ACPI IVMD deviceid type: " 724 "%x", ivmdp->ivmd_type); 725 /*NOTREACHED*/ 726 } 727 728 ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags, 729 AMD_IOMMU_ACPI_IVMD_RSV) == 0); 730 731 acpi_ivmdp->acm_ExclRange = AMD_IOMMU_REG_GET8(&uint8_flags, 732 AMD_IOMMU_ACPI_IVMD_EXCL_RANGE); 733 acpi_ivmdp->acm_IW = AMD_IOMMU_REG_GET8(&uint8_flags, 734 AMD_IOMMU_ACPI_IVMD_IW); 735 acpi_ivmdp->acm_IR = AMD_IOMMU_REG_GET8(&uint8_flags, 736 AMD_IOMMU_ACPI_IVMD_IR); 737 acpi_ivmdp->acm_Unity = AMD_IOMMU_REG_GET8(&uint8_flags, 738 AMD_IOMMU_ACPI_IVMD_UNITY); 739 740 acpi_ivmdp->acm_ivmd_phys_start = ivmdp->ivmd_phys_start; 741 acpi_ivmdp->acm_ivmd_phys_len = ivmdp->ivmd_phys_len; 742 743 acpi_ivmdp->acm_next = hash[idx]; 744 hash[idx] = acpi_ivmdp; 745 } 746 747 static void 748 add_ivmdc_info(ivmd_container_t *ivmdcp, amd_iommu_acpi_ivmd_t **hash) 749 { 750 set_ivmd_info(ivmdcp->ivmdc_ivmd, hash); 751 } 752 753 static void 754 add_ivmd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivmd_t **hash) 755 { 756 ivmd_container_t *ivmdcp; 757 758 for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp; 759 ivmdcp = ivmdcp->ivmdc_next) { 760 add_ivmdc_info(ivmdcp, hash); 761 } 762 } 763 764 static void 765 add_global_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_global_t *global) 766 { 767 uint32_t ivrs_ivinfo = acpi->acp_ivrs->ivrs_ivinfo; 768 769 global->acg_HtAtsResv = 770 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_HT_ATSRSV); 771 global->acg_VAsize = 772 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_VA_SIZE); 773 global->acg_PAsize = 774 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_PA_SIZE); 775 } 776 777 static int 778 create_acpi_hash(amd_iommu_acpi_t *acpi) 779 { 780 /* Last hash entry is for deviceid ranges including "all" */ 781 782 amd_iommu_acpi_global = kmem_zalloc(sizeof (amd_iommu_acpi_global_t), 783 KM_SLEEP); 784 785 amd_iommu_acpi_ivhd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivhd_t *) 786 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP); 787 788 amd_iommu_acpi_ivmd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivmd_t *) 789 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP); 790 791 add_global_info(acpi, amd_iommu_acpi_global); 792 793 add_ivhd_info(acpi, amd_iommu_acpi_ivhd_hash); 794 795 add_ivmd_info(acpi, amd_iommu_acpi_ivmd_hash); 796 797 return (DDI_SUCCESS); 798 } 799 800 static void 801 set_deventry(amd_iommu_t *iommu, int entry, amd_iommu_acpi_ivhd_t *hinfop) 802 { 803 uint64_t *dentry; 804 805 dentry = (uint64_t *)(intptr_t) 806 &iommu->aiomt_devtbl[entry * AMD_IOMMU_DEVTBL_ENTRY_SZ]; 807 808 AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SYSMGT, 809 hinfop->ach_SysMgt); 810 } 811 812 /* Initialize device table according to IVHD */ 813 int 814 amd_iommu_acpi_init_devtbl(amd_iommu_t *iommu) 815 { 816 int i, j; 817 amd_iommu_acpi_ivhd_t *hinfop; 818 819 for (i = 0; i <= AMD_IOMMU_ACPI_INFO_HASH_SZ; i++) { 820 for (hinfop = amd_iommu_acpi_ivhd_hash[i]; 821 hinfop; hinfop = hinfop->ach_next) { 822 823 if (hinfop->ach_IOMMU_deviceid != iommu->aiomt_bdf) 824 continue; 825 826 switch (hinfop->ach_dev_type) { 827 case DEVENTRY_ALL: 828 for (j = 0; j < AMD_IOMMU_MAX_DEVICEID; j++) 829 set_deventry(iommu, j, hinfop); 830 break; 831 case DEVENTRY_SELECT: 832 case DEVENTRY_EXTENDED_SELECT: 833 set_deventry(iommu, 834 hinfop->ach_deviceid_start, 835 hinfop); 836 break; 837 case DEVENTRY_RANGE: 838 case DEVENTRY_EXTENDED_RANGE: 839 for (j = hinfop->ach_deviceid_start; 840 j <= hinfop->ach_deviceid_end; 841 j++) 842 set_deventry(iommu, j, hinfop); 843 break; 844 case DEVENTRY_ALIAS_SELECT: 845 case DEVENTRY_ALIAS_RANGE: 846 case DEVENTRY_SPECIAL_DEVICE: 847 set_deventry(iommu, 848 hinfop->ach_src_deviceid, 849 hinfop); 850 break; 851 default: 852 cmn_err(CE_WARN, 853 "%s: Unknown deventry type", 854 amd_iommu_modname); 855 return (DDI_FAILURE); 856 } 857 } 858 } 859 860 return (DDI_SUCCESS); 861 } 862 863 amd_iommu_acpi_global_t * 864 amd_iommu_lookup_acpi_global(void) 865 { 866 ASSERT(amd_iommu_acpi_global); 867 868 return (amd_iommu_acpi_global); 869 } 870 871 amd_iommu_acpi_ivhd_t * 872 amd_iommu_lookup_all_ivhd(void) 873 { 874 amd_iommu_acpi_ivhd_t *hinfop; 875 876 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 877 for (; hinfop; hinfop = hinfop->ach_next) { 878 if (hinfop->ach_deviceid_start == 0 && 879 hinfop->ach_deviceid_end == (uint16_t)-1) { 880 break; 881 } 882 } 883 884 return (hinfop); 885 } 886 887 amd_iommu_acpi_ivmd_t * 888 amd_iommu_lookup_all_ivmd(void) 889 { 890 amd_iommu_acpi_ivmd_t *minfop; 891 892 minfop = amd_iommu_acpi_ivmd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 893 for (; minfop; minfop = minfop->acm_next) { 894 if (minfop->acm_deviceid_start == 0 && 895 minfop->acm_deviceid_end == (uint16_t)-1) { 896 break; 897 } 898 } 899 900 return (minfop); 901 } 902 903 amd_iommu_acpi_ivhd_t * 904 amd_iommu_lookup_any_ivhd(amd_iommu_t *iommu) 905 { 906 int i; 907 amd_iommu_acpi_ivhd_t *hinfop; 908 909 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) { 910 hinfop = amd_iommu_acpi_ivhd_hash[i]; 911 if ((hinfop != NULL) && 912 hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf) 913 break; 914 } 915 916 return (hinfop); 917 } 918 919 amd_iommu_acpi_ivmd_t * 920 amd_iommu_lookup_any_ivmd(void) 921 { 922 int i; 923 amd_iommu_acpi_ivmd_t *minfop; 924 925 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) { 926 if ((minfop = amd_iommu_acpi_ivmd_hash[i]) != NULL) 927 break; 928 } 929 930 return (minfop); 931 } 932 933 static void 934 dump_acpi_aliases(void) 935 { 936 amd_iommu_acpi_ivhd_t *hinfop; 937 uint16_t idx; 938 939 for (idx = 0; idx <= AMD_IOMMU_ACPI_INFO_HASH_SZ; idx++) { 940 hinfop = amd_iommu_acpi_ivhd_hash[idx]; 941 for (; hinfop; hinfop = hinfop->ach_next) { 942 cmn_err(CE_NOTE, "start=%d, end=%d, src_bdf=%d", 943 hinfop->ach_deviceid_start, 944 hinfop->ach_deviceid_end, 945 hinfop->ach_src_deviceid); 946 } 947 } 948 } 949 950 amd_iommu_acpi_ivhd_t * 951 amd_iommu_lookup_ivhd(int32_t deviceid) 952 { 953 amd_iommu_acpi_ivhd_t *hinfop; 954 uint16_t idx; 955 956 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 957 cmn_err(CE_NOTE, "Attempting to get ACPI IVHD info " 958 "for deviceid: %d", deviceid); 959 } 960 961 ASSERT(amd_iommu_acpi_ivhd_hash); 962 963 /* check if special device */ 964 if (deviceid == -1) { 965 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ]; 966 for (; hinfop; hinfop = hinfop->ach_next) { 967 if (hinfop->ach_deviceid_start == -1 && 968 hinfop->ach_deviceid_end == -1) { 969 break; 970 } 971 } 972 return (hinfop); 973 } 974 975 /* First search for an exact match */ 976 977 idx = deviceid_hashfn(deviceid); 978 979 980 range: 981 hinfop = amd_iommu_acpi_ivhd_hash[idx]; 982 983 for (; hinfop; hinfop = hinfop->ach_next) { 984 if (deviceid < hinfop->ach_deviceid_start || 985 deviceid > hinfop->ach_deviceid_end) 986 continue; 987 988 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 989 cmn_err(CE_NOTE, "Found ACPI IVHD match: %p, " 990 "actual deviceid = %u, start = %u, end = %u", 991 (void *)hinfop, deviceid, 992 hinfop->ach_deviceid_start, 993 hinfop->ach_deviceid_end); 994 } 995 goto out; 996 } 997 998 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) { 999 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 1000 goto range; 1001 } 1002 1003 out: 1004 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1005 cmn_err(CE_NOTE, "%u: %s ACPI IVHD %p", deviceid, 1006 hinfop ? "GOT" : "Did NOT get", (void *)hinfop); 1007 } 1008 1009 return (hinfop); 1010 } 1011 1012 amd_iommu_acpi_ivmd_t * 1013 amd_iommu_lookup_ivmd(int32_t deviceid) 1014 { 1015 amd_iommu_acpi_ivmd_t *minfop; 1016 uint16_t idx; 1017 1018 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1019 cmn_err(CE_NOTE, "Attempting to get ACPI IVMD info " 1020 "for deviceid: %u", deviceid); 1021 } 1022 1023 ASSERT(amd_iommu_acpi_ivmd_hash); 1024 1025 /* First search for an exact match */ 1026 1027 idx = deviceid_hashfn(deviceid); 1028 1029 range: 1030 minfop = amd_iommu_acpi_ivmd_hash[idx]; 1031 1032 for (; minfop; minfop = minfop->acm_next) { 1033 if (deviceid < minfop->acm_deviceid_start && 1034 deviceid > minfop->acm_deviceid_end) 1035 continue; 1036 1037 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1038 cmn_err(CE_NOTE, "Found ACPI IVMD match: %p, " 1039 "actual deviceid = %u, start = %u, end = %u", 1040 (void *)minfop, deviceid, 1041 minfop->acm_deviceid_start, 1042 minfop->acm_deviceid_end); 1043 } 1044 1045 goto out; 1046 } 1047 1048 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) { 1049 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ; 1050 goto range; 1051 } 1052 1053 out: 1054 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) { 1055 cmn_err(CE_NOTE, "%u: %s ACPI IVMD info %p", deviceid, 1056 minfop ? "GOT" : "Did NOT get", (void *)minfop); 1057 } 1058 1059 return (minfop); 1060 } 1061