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 * Portions Copyright (c) 2010, Oracle and/or its affiliates. 24 * All rights reserved. 25 */ 26 27 /* 28 * Copyright (c) 2009, Intel Corporation. 29 * All rights reserved. 30 */ 31 32 33 #include <sys/apic.h> 34 #include <vm/hat_i86.h> 35 #include <sys/sysmacros.h> 36 #include <sys/smp_impldefs.h> 37 #include <sys/immu.h> 38 39 40 typedef struct intrmap_private { 41 immu_t *ir_immu; 42 uint16_t ir_idx; 43 uint32_t ir_sid_svt_sq; 44 } intrmap_private_t; 45 46 #define INTRMAP_PRIVATE(airq) ((intrmap_private_t *)airq->airq_intrmap_private) 47 #define AIRQ_PRIVATE(airq) (airq->airq_intrmap_private) 48 49 /* interrupt remapping table entry */ 50 typedef struct intrmap_rte { 51 uint64_t lo; 52 uint64_t hi; 53 } intrmap_rte_t; 54 55 #define IRTE_HIGH(sid_svt_sq) (sid_svt_sq) 56 #define IRTE_LOW(dst, vector, dlm, tm, rh, dm, fpd, p) \ 57 (((uint64_t)(dst) << 32) | \ 58 ((uint64_t)(vector) << 16) | \ 59 ((uint64_t)(dlm) << 5) | \ 60 ((uint64_t)(tm) << 4) | \ 61 ((uint64_t)(rh) << 3) | \ 62 ((uint64_t)(dm) << 2) | \ 63 ((uint64_t)(fpd) << 1) | \ 64 (p)) 65 66 typedef enum { 67 SVT_NO_VERIFY = 0, /* no verification */ 68 SVT_ALL_VERIFY, /* using sid and sq to verify */ 69 SVT_BUS_VERIFY, /* verify #startbus and #endbus */ 70 SVT_RSVD 71 } intrmap_svt_t; 72 73 typedef enum { 74 SQ_VERIFY_ALL = 0, /* verify all 16 bits */ 75 SQ_VERIFY_IGR_1, /* ignore bit 3 */ 76 SQ_VERIFY_IGR_2, /* ignore bit 2-3 */ 77 SQ_VERIFY_IGR_3 /* ignore bit 1-3 */ 78 } intrmap_sq_t; 79 80 /* 81 * S field of the Interrupt Remapping Table Address Register 82 * the size of the interrupt remapping table is 1 << (immu_intrmap_irta_s + 1) 83 */ 84 static uint_t intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE; 85 86 /* 87 * If true, arrange to suppress broadcast EOI by setting edge-triggered mode 88 * even for level-triggered interrupts in the interrupt-remapping engine. 89 * If false, broadcast EOI can still be suppressed if the CPU supports the 90 * APIC_SVR_SUPPRESS_BROADCAST_EOI bit. In both cases, the IOAPIC is still 91 * programmed with the correct trigger mode, and pcplusmp must send an EOI 92 * to the IOAPIC by writing to the IOAPIC's EOI register to make up for the 93 * missing broadcast EOI. 94 */ 95 static int intrmap_suppress_brdcst_eoi = 0; 96 97 /* 98 * whether verify the source id of interrupt request 99 */ 100 static int intrmap_enable_sid_verify = 0; 101 102 /* fault types for DVMA remapping */ 103 static char *immu_dvma_faults[] = { 104 "Reserved", 105 "The present field in root-entry is Clear", 106 "The present field in context-entry is Clear", 107 "Hardware detected invalid programming of a context-entry", 108 "The DMA request attempted to access an address beyond max support", 109 "The Write field in a page-table entry is Clear when DMA write", 110 "The Read field in a page-table entry is Clear when DMA read", 111 "Access the next level page table resulted in error", 112 "Access the root-entry table resulted in error", 113 "Access the context-entry table resulted in error", 114 "Reserved field not initialized to zero in a present root-entry", 115 "Reserved field not initialized to zero in a present context-entry", 116 "Reserved field not initialized to zero in a present page-table entry", 117 "DMA blocked due to the Translation Type field in context-entry", 118 "Incorrect fault event reason number", 119 }; 120 #define DVMA_MAX_FAULTS (sizeof (immu_dvma_faults)/(sizeof (char *))) - 1 121 122 /* fault types for interrupt remapping */ 123 static char *immu_intrmap_faults[] = { 124 "reserved field set in IRTE", 125 "interrupt_index exceed the intr-remap table size", 126 "present field in IRTE is clear", 127 "hardware access intr-remap table address resulted in error", 128 "reserved field set in IRTE, include various conditional", 129 "hardware blocked an interrupt request in Compatibility format", 130 "remappable interrupt request blocked due to verification failure" 131 }; 132 #define INTRMAP_MAX_FAULTS \ 133 (sizeof (immu_intrmap_faults) / (sizeof (char *))) - 1 134 135 /* Function prototypes */ 136 static int immu_intrmap_init(int apic_mode); 137 static void immu_intrmap_switchon(int suppress_brdcst_eoi); 138 static void immu_intrmap_alloc(apic_irq_t *irq_ptr); 139 static void immu_intrmap_map(apic_irq_t *irq_ptr, void *intrmap_data); 140 static void immu_intrmap_free(apic_irq_t *irq_ptr); 141 static void immu_intrmap_rdt(apic_irq_t *irq_ptr, ioapic_rdt_t *irdt); 142 static void immu_intrmap_msi(apic_irq_t *irq_ptr, msi_regs_t *mregs); 143 144 static struct apic_intrmap_ops intrmap_ops = { 145 immu_intrmap_init, 146 immu_intrmap_switchon, 147 immu_intrmap_alloc, 148 immu_intrmap_map, 149 immu_intrmap_free, 150 immu_intrmap_rdt, 151 immu_intrmap_msi, 152 }; 153 154 /* apic mode, APIC/X2APIC */ 155 static int intrmap_apic_mode = LOCAL_APIC; 156 157 158 /* 159 * helper functions 160 */ 161 static uint_t 162 bitset_find_free(bitset_t *b, uint_t post) 163 { 164 uint_t i; 165 uint_t cap = bitset_capacity(b); 166 167 if (post == cap) 168 post = 0; 169 170 ASSERT(post < cap); 171 172 for (i = post; i < cap; i++) { 173 if (!bitset_in_set(b, i)) 174 return (i); 175 } 176 177 for (i = 0; i < post; i++) { 178 if (!bitset_in_set(b, i)) 179 return (i); 180 } 181 182 return (INTRMAP_IDX_FULL); /* no free index */ 183 } 184 185 /* 186 * helper function to find 'count' contigous free 187 * interrupt remapping table entries 188 */ 189 static uint_t 190 bitset_find_multi_free(bitset_t *b, uint_t post, uint_t count) 191 { 192 uint_t i, j; 193 uint_t cap = bitset_capacity(b); 194 195 if (post == INTRMAP_IDX_FULL) { 196 return (INTRMAP_IDX_FULL); 197 } 198 199 if (count > cap) 200 return (INTRMAP_IDX_FULL); 201 202 ASSERT(post < cap); 203 204 for (i = post; (i + count) <= cap; i++) { 205 for (j = 0; j < count; j++) { 206 if (bitset_in_set(b, (i + j))) { 207 i = i + j; 208 break; 209 } 210 if (j == count - 1) 211 return (i); 212 } 213 } 214 215 for (i = 0; (i < post) && ((i + count) <= cap); i++) { 216 for (j = 0; j < count; j++) { 217 if (bitset_in_set(b, (i + j))) { 218 i = i + j; 219 break; 220 } 221 if (j == count - 1) 222 return (i); 223 } 224 } 225 226 return (INTRMAP_IDX_FULL); /* no free index */ 227 } 228 229 /* alloc one interrupt remapping table entry */ 230 static int 231 alloc_tbl_entry(intrmap_t *intrmap) 232 { 233 uint32_t idx; 234 235 for (;;) { 236 mutex_enter(&intrmap->intrmap_lock); 237 idx = intrmap->intrmap_free; 238 if (idx != INTRMAP_IDX_FULL) { 239 bitset_add(&intrmap->intrmap_map, idx); 240 intrmap->intrmap_free = 241 bitset_find_free(&intrmap->intrmap_map, idx + 1); 242 mutex_exit(&intrmap->intrmap_lock); 243 break; 244 } 245 246 /* no free intr entry, use compatible format intr */ 247 mutex_exit(&intrmap->intrmap_lock); 248 249 if (intrmap_apic_mode != LOCAL_X2APIC) { 250 break; 251 } 252 253 /* 254 * x2apic mode not allowed compatible 255 * interrupt 256 */ 257 delay(IMMU_ALLOC_RESOURCE_DELAY); 258 } 259 260 return (idx); 261 } 262 263 /* alloc 'cnt' contigous interrupt remapping table entries */ 264 static int 265 alloc_tbl_multi_entries(intrmap_t *intrmap, uint_t cnt) 266 { 267 uint_t idx, pos, i; 268 269 for (; ; ) { 270 mutex_enter(&intrmap->intrmap_lock); 271 pos = intrmap->intrmap_free; 272 idx = bitset_find_multi_free(&intrmap->intrmap_map, pos, cnt); 273 274 if (idx != INTRMAP_IDX_FULL) { 275 if (idx <= pos && pos < (idx + cnt)) { 276 intrmap->intrmap_free = bitset_find_free( 277 &intrmap->intrmap_map, idx + cnt); 278 } 279 for (i = 0; i < cnt; i++) { 280 bitset_add(&intrmap->intrmap_map, idx + i); 281 } 282 mutex_exit(&intrmap->intrmap_lock); 283 } 284 285 mutex_exit(&intrmap->intrmap_lock); 286 287 if (intrmap_apic_mode != LOCAL_X2APIC) { 288 break; 289 } 290 291 /* x2apic mode not allowed comapitible interrupt */ 292 delay(IMMU_ALLOC_RESOURCE_DELAY); 293 } 294 295 return (idx); 296 } 297 298 /* init interrupt remapping table */ 299 static int 300 init_unit(immu_t *immu) 301 { 302 intrmap_t *intrmap; 303 size_t size; 304 305 ddi_dma_attr_t intrmap_dma_attr = { 306 DMA_ATTR_V0, 307 0U, 308 0xffffffffU, 309 0xffffffffU, 310 MMU_PAGESIZE, /* page aligned */ 311 0x1, 312 0x1, 313 0xffffffffU, 314 0xffffffffU, 315 1, 316 4, 317 0 318 }; 319 320 ddi_device_acc_attr_t intrmap_acc_attr = { 321 DDI_DEVICE_ATTR_V0, 322 DDI_NEVERSWAP_ACC, 323 DDI_STRICTORDER_ACC 324 }; 325 326 /* 327 * Using interrupt remapping implies using the queue 328 * invalidation interface. According to Intel, 329 * hardware that supports interrupt remapping should 330 * also support QI. 331 */ 332 ASSERT(IMMU_ECAP_GET_QI(immu->immu_regs_excap)); 333 334 if (intrmap_apic_mode == LOCAL_X2APIC) { 335 if (!IMMU_ECAP_GET_EIM(immu->immu_regs_excap)) { 336 return (DDI_FAILURE); 337 } 338 } 339 340 if (intrmap_irta_s > INTRMAP_MAX_IRTA_SIZE) { 341 intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE; 342 } 343 344 intrmap = kmem_zalloc(sizeof (intrmap_t), KM_SLEEP); 345 346 if (ddi_dma_alloc_handle(immu->immu_dip, 347 &intrmap_dma_attr, 348 DDI_DMA_SLEEP, 349 NULL, 350 &(intrmap->intrmap_dma_hdl)) != DDI_SUCCESS) { 351 kmem_free(intrmap, sizeof (intrmap_t)); 352 return (DDI_FAILURE); 353 } 354 355 intrmap->intrmap_size = 1 << (intrmap_irta_s + 1); 356 size = intrmap->intrmap_size * INTRMAP_RTE_SIZE; 357 if (ddi_dma_mem_alloc(intrmap->intrmap_dma_hdl, 358 size, 359 &intrmap_acc_attr, 360 DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED, 361 DDI_DMA_SLEEP, 362 NULL, 363 &(intrmap->intrmap_vaddr), 364 &size, 365 &(intrmap->intrmap_acc_hdl)) != DDI_SUCCESS) { 366 ddi_dma_free_handle(&(intrmap->intrmap_dma_hdl)); 367 kmem_free(intrmap, sizeof (intrmap_t)); 368 return (DDI_FAILURE); 369 } 370 371 ASSERT(!((uintptr_t)intrmap->intrmap_vaddr & MMU_PAGEOFFSET)); 372 bzero(intrmap->intrmap_vaddr, size); 373 intrmap->intrmap_paddr = pfn_to_pa( 374 hat_getpfnum(kas.a_hat, intrmap->intrmap_vaddr)); 375 376 mutex_init(&(intrmap->intrmap_lock), NULL, MUTEX_DRIVER, NULL); 377 bitset_init(&intrmap->intrmap_map); 378 bitset_resize(&intrmap->intrmap_map, intrmap->intrmap_size); 379 intrmap->intrmap_free = 0; 380 381 immu->immu_intrmap = intrmap; 382 383 return (DDI_SUCCESS); 384 } 385 386 static void 387 get_immu(apic_irq_t *irq_ptr) 388 { 389 immu_t *immu = NULL; 390 391 ASSERT(INTRMAP_PRIVATE(irq_ptr)->ir_immu == NULL); 392 393 if (!APIC_IS_MSI_OR_MSIX_INDEX(irq_ptr->airq_mps_intr_index)) { 394 immu = immu_dmar_ioapic_immu(irq_ptr->airq_ioapicindex); 395 } else { 396 if (irq_ptr->airq_dip != NULL) { 397 immu = immu_dmar_get_immu(irq_ptr->airq_dip); 398 } 399 } 400 401 if (immu && (immu->immu_intrmap_running == B_TRUE)) { 402 INTRMAP_PRIVATE(irq_ptr)->ir_immu = immu; 403 } 404 } 405 406 static int 407 get_top_pcibridge(dev_info_t *dip, void *arg) 408 { 409 dev_info_t **topdipp = arg; 410 immu_devi_t *immu_devi; 411 412 mutex_enter(&(DEVI(dip)->devi_lock)); 413 immu_devi = DEVI(dip)->devi_iommu; 414 mutex_exit(&(DEVI(dip)->devi_lock)); 415 416 if (immu_devi == NULL || immu_devi->imd_pcib_type == IMMU_PCIB_BAD || 417 immu_devi->imd_pcib_type == IMMU_PCIB_ENDPOINT) { 418 return (DDI_WALK_CONTINUE); 419 } 420 421 *topdipp = dip; 422 423 return (DDI_WALK_CONTINUE); 424 } 425 426 static dev_info_t * 427 intrmap_top_pcibridge(dev_info_t *rdip) 428 { 429 dev_info_t *top_pcibridge = NULL; 430 431 if (immu_walk_ancestor(rdip, NULL, get_top_pcibridge, 432 &top_pcibridge, NULL, 0) != DDI_SUCCESS) { 433 return (NULL); 434 } 435 436 return (top_pcibridge); 437 } 438 439 /* function to get interrupt request source id */ 440 static void 441 get_sid(apic_irq_t *irq_ptr) 442 { 443 dev_info_t *dip, *pdip; 444 immu_devi_t *immu_devi; 445 uint16_t sid; 446 uchar_t svt, sq; 447 448 if (!intrmap_enable_sid_verify) { 449 return; 450 } 451 452 if (!APIC_IS_MSI_OR_MSIX_INDEX(irq_ptr->airq_mps_intr_index)) { 453 /* for interrupt through I/O APIC */ 454 sid = immu_dmar_ioapic_sid(irq_ptr->airq_ioapicindex); 455 svt = SVT_ALL_VERIFY; 456 sq = SQ_VERIFY_ALL; 457 } else { 458 /* MSI/MSI-X interrupt */ 459 dip = irq_ptr->airq_dip; 460 ASSERT(dip); 461 pdip = intrmap_top_pcibridge(dip); 462 ASSERT(pdip); 463 immu_devi = DEVI(pdip)->devi_iommu; 464 ASSERT(immu_devi); 465 if (immu_devi->imd_pcib_type == IMMU_PCIB_PCIE_PCI) { 466 /* device behind pcie to pci bridge */ 467 sid = (immu_devi->imd_bus << 8) | immu_devi->imd_sec; 468 svt = SVT_BUS_VERIFY; 469 sq = SQ_VERIFY_ALL; 470 } else { 471 /* pcie device or device behind pci to pci bridge */ 472 sid = (immu_devi->imd_bus << 8) | 473 immu_devi->imd_devfunc; 474 svt = SVT_ALL_VERIFY; 475 sq = SQ_VERIFY_ALL; 476 } 477 } 478 479 INTRMAP_PRIVATE(irq_ptr)->ir_sid_svt_sq = 480 sid | (svt << 18) | (sq << 16); 481 } 482 483 static void 484 intrmap_enable(immu_t *immu) 485 { 486 intrmap_t *intrmap; 487 uint64_t irta_reg; 488 489 intrmap = immu->immu_intrmap; 490 491 irta_reg = intrmap->intrmap_paddr | intrmap_irta_s; 492 if (intrmap_apic_mode == LOCAL_X2APIC) { 493 irta_reg |= (0x1 << 11); 494 } 495 496 immu_regs_intrmap_enable(immu, irta_reg); 497 } 498 499 /* ####################################################################### */ 500 501 /* 502 * immu_intr_handler() 503 * the fault event handler for a single immu unit 504 */ 505 int 506 immu_intr_handler(immu_t *immu) 507 { 508 uint32_t status; 509 int index, fault_reg_offset; 510 int max_fault_index; 511 boolean_t found_fault; 512 dev_info_t *idip; 513 514 mutex_enter(&(immu->immu_intr_lock)); 515 mutex_enter(&(immu->immu_regs_lock)); 516 517 /* read the fault status */ 518 status = immu_regs_get32(immu, IMMU_REG_FAULT_STS); 519 520 idip = immu->immu_dip; 521 ASSERT(idip); 522 523 /* check if we have a pending fault for this immu unit */ 524 if ((status & IMMU_FAULT_STS_PPF) == 0) { 525 mutex_exit(&(immu->immu_regs_lock)); 526 mutex_exit(&(immu->immu_intr_lock)); 527 return (DDI_INTR_UNCLAIMED); 528 } 529 530 /* 531 * handle all primary pending faults 532 */ 533 index = IMMU_FAULT_GET_INDEX(status); 534 max_fault_index = IMMU_CAP_GET_NFR(immu->immu_regs_cap) - 1; 535 fault_reg_offset = IMMU_CAP_GET_FRO(immu->immu_regs_cap); 536 537 found_fault = B_FALSE; 538 _NOTE(CONSTCOND) 539 while (1) { 540 uint64_t val; 541 uint8_t fault_reason; 542 uint8_t fault_type; 543 uint16_t sid; 544 uint64_t pg_addr; 545 uint64_t idx; 546 547 /* read the higher 64bits */ 548 val = immu_regs_get64(immu, fault_reg_offset + index * 16 + 8); 549 550 /* check if this fault register has pending fault */ 551 if (!IMMU_FRR_GET_F(val)) { 552 break; 553 } 554 555 found_fault = B_TRUE; 556 557 /* get the fault reason, fault type and sid */ 558 fault_reason = IMMU_FRR_GET_FR(val); 559 fault_type = IMMU_FRR_GET_FT(val); 560 sid = IMMU_FRR_GET_SID(val); 561 562 /* read the first 64bits */ 563 val = immu_regs_get64(immu, fault_reg_offset + index * 16); 564 pg_addr = val & IMMU_PAGEMASK; 565 idx = val >> 48; 566 567 /* clear the fault */ 568 immu_regs_put32(immu, fault_reg_offset + index * 16 + 12, 569 (((uint32_t)1) << 31)); 570 571 /* report the fault info */ 572 if (fault_reason < 0x20) { 573 /* immu-remapping fault */ 574 ddi_err(DER_WARN, idip, 575 "generated a fault event when translating DMA %s\n" 576 "\t on address 0x%" PRIx64 " for PCI(%d, %d, %d), " 577 "the reason is:\n\t %s", 578 fault_type ? "read" : "write", pg_addr, 579 (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7, 580 immu_dvma_faults[MIN(fault_reason, 581 DVMA_MAX_FAULTS)]); 582 } else if (fault_reason < 0x27) { 583 /* intr-remapping fault */ 584 ddi_err(DER_WARN, idip, 585 "generated a fault event when translating " 586 "interrupt request\n" 587 "\t on index 0x%" PRIx64 " for PCI(%d, %d, %d), " 588 "the reason is:\n\t %s", 589 idx, 590 (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7, 591 immu_intrmap_faults[MIN((fault_reason - 0x20), 592 INTRMAP_MAX_FAULTS)]); 593 } else { 594 ddi_err(DER_WARN, idip, "Unknown fault reason: 0x%x", 595 fault_reason); 596 } 597 598 index++; 599 if (index > max_fault_index) 600 index = 0; 601 } 602 603 /* Clear the fault */ 604 if (!found_fault) { 605 ddi_err(DER_MODE, idip, 606 "Fault register set but no fault present"); 607 } 608 immu_regs_put32(immu, IMMU_REG_FAULT_STS, 1); 609 mutex_exit(&(immu->immu_regs_lock)); 610 mutex_exit(&(immu->immu_intr_lock)); 611 return (DDI_INTR_CLAIMED); 612 } 613 /* ######################################################################### */ 614 615 /* 616 * Interrupt remap entry points 617 */ 618 619 /* initialize interrupt remapping */ 620 static int 621 immu_intrmap_init(int apic_mode) 622 { 623 immu_t *immu; 624 int error = DDI_FAILURE; 625 626 if (immu_intrmap_enable == B_FALSE) { 627 return (DDI_SUCCESS); 628 } 629 630 intrmap_apic_mode = apic_mode; 631 632 immu = list_head(&immu_list); 633 for (; immu; immu = list_next(&immu_list, immu)) { 634 if ((immu->immu_intrmap_running == B_TRUE) && 635 IMMU_ECAP_GET_IR(immu->immu_regs_excap)) { 636 if (init_unit(immu) == DDI_SUCCESS) { 637 error = DDI_SUCCESS; 638 } 639 } 640 } 641 642 /* 643 * if all IOMMU units disable intr remapping, 644 * return FAILURE 645 */ 646 return (error); 647 } 648 649 650 651 /* enable interrupt remapping */ 652 static void 653 immu_intrmap_switchon(int suppress_brdcst_eoi) 654 { 655 immu_t *immu; 656 657 658 intrmap_suppress_brdcst_eoi = suppress_brdcst_eoi; 659 660 immu = list_head(&immu_list); 661 for (; immu; immu = list_next(&immu_list, immu)) { 662 if (immu->immu_intrmap_setup == B_TRUE) { 663 intrmap_enable(immu); 664 } 665 } 666 } 667 668 /* alloc remapping entry for the interrupt */ 669 static void 670 immu_intrmap_alloc(apic_irq_t *irq_ptr) 671 { 672 immu_t *immu; 673 intrmap_t *intrmap; 674 uint32_t idx, cnt, i; 675 uint_t vector, irqno; 676 uint32_t sid_svt_sq; 677 678 if (AIRQ_PRIVATE(irq_ptr) == INTRMAP_DISABLE || 679 AIRQ_PRIVATE(irq_ptr) != NULL) { 680 return; 681 } 682 683 AIRQ_PRIVATE(irq_ptr) = 684 kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP); 685 686 get_immu(irq_ptr); 687 688 immu = INTRMAP_PRIVATE(irq_ptr)->ir_immu; 689 if (immu == NULL) { 690 goto intrmap_disable; 691 } 692 693 intrmap = immu->immu_intrmap; 694 695 if (irq_ptr->airq_mps_intr_index == MSI_INDEX) { 696 cnt = irq_ptr->airq_intin_no; 697 } else { 698 cnt = 1; 699 } 700 701 if (cnt == 1) { 702 idx = alloc_tbl_entry(intrmap); 703 } else { 704 idx = alloc_tbl_multi_entries(intrmap, cnt); 705 } 706 707 if (idx == INTRMAP_IDX_FULL) { 708 goto intrmap_disable; 709 } 710 711 INTRMAP_PRIVATE(irq_ptr)->ir_idx = idx; 712 713 get_sid(irq_ptr); 714 715 if (cnt == 1) { 716 if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) { 717 immu_qinv_intr_one_cache(immu, idx); 718 } else { 719 immu_regs_wbf_flush(immu); 720 } 721 return; 722 } 723 724 sid_svt_sq = INTRMAP_PRIVATE(irq_ptr)->ir_sid_svt_sq; 725 726 vector = irq_ptr->airq_vector; 727 728 for (i = 1; i < cnt; i++) { 729 irqno = apic_vector_to_irq[vector + i]; 730 irq_ptr = apic_irq_table[irqno]; 731 732 ASSERT(irq_ptr); 733 734 AIRQ_PRIVATE(irq_ptr) = 735 kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP); 736 737 INTRMAP_PRIVATE(irq_ptr)->ir_immu = immu; 738 INTRMAP_PRIVATE(irq_ptr)->ir_sid_svt_sq = sid_svt_sq; 739 INTRMAP_PRIVATE(irq_ptr)->ir_idx = idx + i; 740 } 741 742 if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) { 743 immu_qinv_intr_caches(immu, idx, cnt); 744 } else { 745 immu_regs_wbf_flush(immu); 746 } 747 748 return; 749 750 intrmap_disable: 751 kmem_free(AIRQ_PRIVATE(irq_ptr), sizeof (intrmap_private_t)); 752 AIRQ_PRIVATE(irq_ptr) = INTRMAP_DISABLE; 753 } 754 755 756 /* remapping the interrupt */ 757 static void 758 immu_intrmap_map(apic_irq_t *irq_ptr, void *intrmap_data) 759 { 760 immu_t *immu; 761 intrmap_t *intrmap; 762 ioapic_rdt_t *irdt = (ioapic_rdt_t *)intrmap_data; 763 msi_regs_t *mregs = (msi_regs_t *)intrmap_data; 764 intrmap_rte_t irte; 765 uint_t idx, i, cnt; 766 uint32_t dst, sid_svt_sq; 767 uchar_t vector, dlm, tm, rh, dm; 768 769 if (AIRQ_PRIVATE(irq_ptr) == INTRMAP_DISABLE) { 770 return; 771 } 772 773 if (irq_ptr->airq_mps_intr_index == MSI_INDEX) { 774 cnt = irq_ptr->airq_intin_no; 775 } else { 776 cnt = 1; 777 } 778 779 idx = INTRMAP_PRIVATE(irq_ptr)->ir_idx; 780 immu = INTRMAP_PRIVATE(irq_ptr)->ir_immu; 781 intrmap = immu->immu_intrmap; 782 sid_svt_sq = INTRMAP_PRIVATE(irq_ptr)->ir_sid_svt_sq; 783 vector = irq_ptr->airq_vector; 784 785 if (!APIC_IS_MSI_OR_MSIX_INDEX(irq_ptr->airq_mps_intr_index)) { 786 dm = RDT_DM(irdt->ir_lo); 787 rh = 0; 788 tm = RDT_TM(irdt->ir_lo); 789 dlm = RDT_DLM(irdt->ir_lo); 790 dst = irdt->ir_hi; 791 792 /* 793 * Mark the IRTE's TM as Edge to suppress broadcast EOI. 794 */ 795 if (intrmap_suppress_brdcst_eoi) { 796 tm = TRIGGER_MODE_EDGE; 797 } 798 } else { 799 dm = MSI_ADDR_DM_PHYSICAL; 800 rh = MSI_ADDR_RH_FIXED; 801 tm = TRIGGER_MODE_EDGE; 802 dlm = 0; 803 dst = mregs->mr_addr; 804 } 805 806 if (intrmap_apic_mode == LOCAL_APIC) 807 dst = (dst & 0xFF) << 8; 808 809 if (cnt == 1) { 810 irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1); 811 irte.hi = IRTE_HIGH(sid_svt_sq); 812 813 /* set interrupt remapping table entry */ 814 bcopy(&irte, intrmap->intrmap_vaddr + 815 idx * INTRMAP_RTE_SIZE, 816 INTRMAP_RTE_SIZE); 817 818 immu_qinv_intr_one_cache(immu, idx); 819 820 } else { 821 vector = irq_ptr->airq_vector; 822 for (i = 0; i < cnt; i++) { 823 irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1); 824 irte.hi = IRTE_HIGH(sid_svt_sq); 825 826 /* set interrupt remapping table entry */ 827 bcopy(&irte, intrmap->intrmap_vaddr + 828 idx * INTRMAP_RTE_SIZE, 829 INTRMAP_RTE_SIZE); 830 vector++; 831 idx++; 832 } 833 834 immu_qinv_intr_caches(immu, idx, cnt); 835 } 836 } 837 838 /* free the remapping entry */ 839 static void 840 immu_intrmap_free(apic_irq_t *irq_ptr) 841 { 842 immu_t *immu; 843 intrmap_t *intrmap; 844 uint32_t idx; 845 846 if (AIRQ_PRIVATE(irq_ptr) == INTRMAP_DISABLE) { 847 AIRQ_PRIVATE(irq_ptr) = NULL; 848 return; 849 } 850 851 immu = INTRMAP_PRIVATE(irq_ptr)->ir_immu; 852 intrmap = immu->immu_intrmap; 853 idx = INTRMAP_PRIVATE(irq_ptr)->ir_idx; 854 855 bzero(intrmap->intrmap_vaddr + idx * INTRMAP_RTE_SIZE, 856 INTRMAP_RTE_SIZE); 857 858 immu_qinv_intr_one_cache(immu, idx); 859 860 mutex_enter(&intrmap->intrmap_lock); 861 bitset_del(&intrmap->intrmap_map, idx); 862 if (intrmap->intrmap_free == INTRMAP_IDX_FULL) { 863 intrmap->intrmap_free = idx; 864 } 865 mutex_exit(&intrmap->intrmap_lock); 866 867 kmem_free(AIRQ_PRIVATE(irq_ptr), sizeof (intrmap_private_t)); 868 AIRQ_PRIVATE(irq_ptr) = NULL; 869 } 870 871 /* record the ioapic rdt entry */ 872 static void 873 immu_intrmap_rdt(apic_irq_t *irq_ptr, ioapic_rdt_t *irdt) 874 { 875 uint32_t rdt_entry, tm, pol, idx, vector; 876 877 rdt_entry = irdt->ir_lo; 878 879 if (INTRMAP_PRIVATE(irq_ptr) != NULL && 880 INTRMAP_PRIVATE(irq_ptr) != INTRMAP_DISABLE) { 881 idx = INTRMAP_PRIVATE(irq_ptr)->ir_idx; 882 tm = RDT_TM(rdt_entry); 883 pol = RDT_POL(rdt_entry); 884 vector = irq_ptr->airq_vector; 885 irdt->ir_lo = (tm << INTRMAP_IOAPIC_TM_SHIFT) | 886 (pol << INTRMAP_IOAPIC_POL_SHIFT) | 887 ((idx >> 15) << INTRMAP_IOAPIC_IDX15_SHIFT) | 888 vector; 889 irdt->ir_hi = (idx << INTRMAP_IOAPIC_IDX_SHIFT) | 890 (1 << INTRMAP_IOAPIC_FORMAT_SHIFT); 891 } else { 892 irdt->ir_hi <<= APIC_ID_BIT_OFFSET; 893 } 894 } 895 896 /* record the msi interrupt structure */ 897 /*ARGSUSED*/ 898 static void 899 immu_intrmap_msi(apic_irq_t *irq_ptr, msi_regs_t *mregs) 900 { 901 uint_t idx; 902 903 if (INTRMAP_PRIVATE(irq_ptr) != NULL && 904 INTRMAP_PRIVATE(irq_ptr) != INTRMAP_DISABLE) { 905 idx = INTRMAP_PRIVATE(irq_ptr)->ir_idx; 906 907 mregs->mr_data = 0; 908 mregs->mr_addr = MSI_ADDR_HDR | 909 ((idx & 0x7fff) << INTRMAP_MSI_IDX_SHIFT) | 910 (1 << INTRMAP_MSI_FORMAT_SHIFT) | 911 (1 << INTRMAP_MSI_SHV_SHIFT) | 912 ((idx >> 15) << INTRMAP_MSI_IDX15_SHIFT); 913 } else { 914 mregs->mr_addr = MSI_ADDR_HDR | 915 (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 916 (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) | 917 (mregs->mr_addr << MSI_ADDR_DEST_SHIFT); 918 mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | 919 mregs->mr_data; 920 } 921 } 922 923 /* ######################################################################### */ 924 /* 925 * Functions exported by immu_intr.c 926 */ 927 void 928 immu_intrmap_setup(list_t *listp) 929 { 930 immu_t *immu; 931 932 /* 933 * Check if ACPI DMAR tables say that 934 * interrupt remapping is supported 935 */ 936 if (immu_dmar_intrmap_supported() == B_FALSE) { 937 return; 938 } 939 940 /* 941 * Check if interrupt remapping is disabled. 942 */ 943 if (immu_intrmap_enable == B_FALSE) { 944 return; 945 } 946 947 psm_vt_ops = &intrmap_ops; 948 949 immu = list_head(listp); 950 for (; immu; immu = list_next(listp, immu)) { 951 mutex_init(&(immu->immu_intrmap_lock), NULL, 952 MUTEX_DEFAULT, NULL); 953 mutex_enter(&(immu->immu_intrmap_lock)); 954 immu->immu_intrmap_setup = B_TRUE; 955 mutex_exit(&(immu->immu_intrmap_lock)); 956 } 957 } 958 959 void 960 immu_intrmap_startup(immu_t *immu) 961 { 962 /* do nothing */ 963 mutex_enter(&(immu->immu_intrmap_lock)); 964 if (immu->immu_intrmap_setup == B_TRUE) { 965 immu->immu_intrmap_running = B_TRUE; 966 } 967 mutex_exit(&(immu->immu_intrmap_lock)); 968 } 969 970 /* 971 * Register a Intel IOMMU unit (i.e. DMAR unit's) 972 * interrupt handler 973 */ 974 void 975 immu_intr_register(immu_t *immu) 976 { 977 int irq, vect; 978 char intr_handler_name[IMMU_MAXNAMELEN]; 979 uint32_t msi_data; 980 uint32_t uaddr; 981 uint32_t msi_addr; 982 983 msi_addr = (MSI_ADDR_HDR | 984 apic_cpus[0].aci_local_id & 0xFF) << ((MSI_ADDR_DEST_SHIFT) | 985 (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 986 (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT)); 987 988 if (intrmap_apic_mode == LOCAL_X2APIC) { 989 uaddr = (apic_cpus[0].aci_local_id & 0xFFFFFF00); 990 } else { 991 uaddr = 0; 992 } 993 994 /* Dont need to hold immu_intr_lock since we are in boot */ 995 irq = psm_get_ipivect(IMMU_INTR_IPL, -1); 996 vect = apic_irq_table[irq]->airq_vector; 997 msi_data = ((MSI_DATA_DELIVERY_FIXED << 998 MSI_DATA_DELIVERY_SHIFT) | vect); 999 1000 (void) snprintf(intr_handler_name, sizeof (intr_handler_name), 1001 "%s-intr-handler", immu->immu_name); 1002 1003 (void) add_avintr((void *)NULL, IMMU_INTR_IPL, 1004 (avfunc)(immu_intr_handler), intr_handler_name, irq, 1005 (caddr_t)immu, NULL, NULL, NULL); 1006 1007 immu_regs_intr_enable(immu, msi_addr, msi_data, uaddr); 1008 1009 (void) immu_intr_handler(immu); 1010 } 1011