Changeset 88826 in vbox for trunk/src/VBox
- Timestamp:
- May 3, 2021 11:12:01 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevIoApic.cpp
r88822 r88826 502 502 uint64_t const u64Rte = pThis->au64RedirTable[idxRte]; 503 503 if (!IOAPIC_RTE_IS_MASKED(u64Rte)) 504 { 505 /* We cannot accept another level-triggered interrupt until remote IRR has been cleared. */ 506 uint8_t const u8TriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u64Rte); 507 if (u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL) 504 { /* likely */ } 505 else 506 return; 507 508 /* We cannot accept another level-triggered interrupt until remote IRR has been cleared. */ 509 uint8_t const u8TriggerMode = IOAPIC_RTE_GET_TRIGGER_MODE(u64Rte); 510 if (u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL) 511 { 512 uint8_t const u8RemoteIrr = IOAPIC_RTE_GET_REMOTE_IRR(u64Rte); 513 if (u8RemoteIrr) 508 514 { 509 uint8_t const u8RemoteIrr = IOAPIC_RTE_GET_REMOTE_IRR(u64Rte); 510 if (u8RemoteIrr) 511 { 512 STAM_COUNTER_INC(&pThis->StatSuppressedLevelIntr); 513 return; 514 } 515 } 516 517 XAPICINTR ApicIntr; 518 RT_ZERO(ApicIntr); 519 ApicIntr.u8Vector = IOAPIC_RTE_GET_VECTOR(u64Rte); 520 ApicIntr.u8Dest = IOAPIC_RTE_GET_DEST(u64Rte); 521 ApicIntr.u8DestMode = IOAPIC_RTE_GET_DEST_MODE(u64Rte); 522 ApicIntr.u8DeliveryMode = IOAPIC_RTE_GET_DELIVERY_MODE(u64Rte); 523 ApicIntr.u8Polarity = IOAPIC_RTE_GET_POLARITY(u64Rte); 524 ApicIntr.u8TriggerMode = u8TriggerMode; 525 ApicIntr.u8RedirHint = 0; 526 527 #if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL) 528 /* 529 * The interrupt may need to be remapped (or discarded) if an IOMMU is present. 530 * For line-based interrupts we must use the southbridge I/O APIC's BDF as 531 * the origin of the interrupt, see @bugref{9654#c74}. 532 */ 533 MSIMSG MsiOut; 534 MSIMSG MsiIn; 535 RT_ZERO(MsiOut); 536 RT_ZERO(MsiIn); 537 ioapicGetMsiFromApicIntr(&ApicIntr, &MsiIn); 538 int const rcRemap = pThisCC->pIoApicHlp->pfnIommuMsiRemap(pDevIns, VBOX_PCI_BDF_SB_IOAPIC, &MsiIn, &MsiOut); 539 if ( rcRemap == VERR_IOMMU_NOT_PRESENT 540 || rcRemap == VERR_IOMMU_CANNOT_CALL_SELF) 541 MsiOut = MsiIn; 542 else if (RT_SUCCESS(rcRemap)) 543 STAM_COUNTER_INC(&pThis->StatIommuRemappedIntr); 544 else 545 { 546 STAM_COUNTER_INC(&pThis->StatIommuDiscardedIntr); 515 STAM_COUNTER_INC(&pThis->StatSuppressedLevelIntr); 547 516 return; 548 517 } 549 550 ioapicGetApicIntrFromMsi(&MsiOut, &ApicIntr); 518 } 519 520 /** @todo We might be able to release the IOAPIC(PDM) lock here and re-acquire it 521 * before setting the remote IRR bit below. The APIC and IOMMU should not 522 * require the caller to hold the PDM lock. */ 523 524 XAPICINTR ApicIntr; 525 RT_ZERO(ApicIntr); 526 ApicIntr.u8Vector = IOAPIC_RTE_GET_VECTOR(u64Rte); 527 ApicIntr.u8Dest = IOAPIC_RTE_GET_DEST(u64Rte); 528 ApicIntr.u8DestMode = IOAPIC_RTE_GET_DEST_MODE(u64Rte); 529 ApicIntr.u8DeliveryMode = IOAPIC_RTE_GET_DELIVERY_MODE(u64Rte); 530 ApicIntr.u8Polarity = IOAPIC_RTE_GET_POLARITY(u64Rte); 531 ApicIntr.u8TriggerMode = u8TriggerMode; 532 //ApicIntr.u8RedirHint = 0; 533 534 #if defined(VBOX_WITH_IOMMU_AMD) || defined(VBOX_WITH_IOMMU_INTEL) 535 /* 536 * The interrupt may need to be remapped (or discarded) if an IOMMU is present. 537 * For line-based interrupts we must use the southbridge I/O APIC's BDF as 538 * the origin of the interrupt, see @bugref{9654#c74}. 539 */ 540 MSIMSG MsiOut; 541 MSIMSG MsiIn; 542 RT_ZERO(MsiOut); 543 RT_ZERO(MsiIn); 544 ioapicGetMsiFromApicIntr(&ApicIntr, &MsiIn); 545 int const rcRemap = pThisCC->pIoApicHlp->pfnIommuMsiRemap(pDevIns, VBOX_PCI_BDF_SB_IOAPIC, &MsiIn, &MsiOut); 546 if ( rcRemap == VERR_IOMMU_NOT_PRESENT 547 || rcRemap == VERR_IOMMU_CANNOT_CALL_SELF) 548 MsiOut = MsiIn; 549 else if (RT_SUCCESS(rcRemap)) 550 STAM_COUNTER_INC(&pThis->StatIommuRemappedIntr); 551 else 552 { 553 STAM_COUNTER_INC(&pThis->StatIommuDiscardedIntr); 554 return; 555 } 556 557 ioapicGetApicIntrFromMsi(&MsiOut, &ApicIntr); 551 558 552 559 # ifdef RT_STRICT 553 554 555 556 557 560 if (RT_SUCCESS(rcRemap)) 561 { 562 Assert(ApicIntr.u8Polarity == IOAPIC_RTE_GET_POLARITY(u64Rte)); /* Ensure polarity hasn't changed. */ 563 Assert(ApicIntr.u8TriggerMode == u8TriggerMode); /* Ensure trigger mode hasn't changed. */ 564 } 558 565 # endif 559 566 #endif 560 567 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 568 uint32_t const u32TagSrc = pThis->au32TagSrc[idxRte]; 569 Log2(("IOAPIC: Signaling %s-triggered interrupt. Dest=%#x DestMode=%s Vector=%#x (%u)\n", 570 ApicIntr.u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_EDGE ? "edge" : "level", ApicIntr.u8Dest, 571 ApicIntr.u8DestMode == IOAPIC_RTE_DEST_MODE_PHYSICAL ? "physical" : "logical", 572 ApicIntr.u8Vector, ApicIntr.u8Vector)); 573 574 /* 575 * Deliver to the local APIC via the system/3-wire-APIC bus. 576 */ 577 int rc = pThisCC->pIoApicHlp->pfnApicBusDeliver(pDevIns, 578 ApicIntr.u8Dest, 579 ApicIntr.u8DestMode, 580 ApicIntr.u8DeliveryMode, 581 ApicIntr.u8Vector, 582 ApicIntr.u8Polarity, 583 ApicIntr.u8TriggerMode, 584 u32TagSrc); 585 /* Can't reschedule to R3. */ 586 Assert(rc == VINF_SUCCESS || rc == VERR_APIC_INTR_DISCARDED); 580 587 #ifdef DEBUG_ramshankar 581 582 588 if (rc == VERR_APIC_INTR_DISCARDED) 589 AssertMsgFailed(("APIC: Interrupt discarded u8Vector=%#x (%u) u64Rte=%#RX64\n", u8Vector, u8Vector, u64Rte)); 583 590 #endif 584 591 585 /* 586 * For level-triggered interrupts, we set the remote IRR bit to indicate 587 * the local APIC has accepted the interrupt. 588 * 589 * For edge-triggered interrupts, we should not clear the IRR bit as it 590 * should remain intact to reflect the state of the interrupt line. 591 * The device will explicitly transition to inactive state via the 592 * ioapicSetIrq() callback. 593 */ 594 if ( u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL 595 && rc == VINF_SUCCESS) 596 { 597 Assert(u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL); 598 pThis->au64RedirTable[idxRte] |= IOAPIC_RTE_REMOTE_IRR; 599 STAM_COUNTER_INC(&pThis->StatLevelIrqSent); 600 } 592 /* 593 * For level-triggered interrupts, we set the remote IRR bit to indicate 594 * the local APIC has accepted the interrupt. 595 * 596 * For edge-triggered interrupts, we should not clear the IRR bit as it 597 * should remain intact to reflect the state of the interrupt line. 598 * The device will explicitly transition to inactive state via the 599 * ioapicSetIrq() callback. 600 */ 601 if ( u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL 602 && rc == VINF_SUCCESS) 603 { 604 Assert(u8TriggerMode == IOAPIC_RTE_TRIGGER_MODE_LEVEL); 605 pThis->au64RedirTable[idxRte] |= IOAPIC_RTE_REMOTE_IRR; 606 STAM_COUNTER_INC(&pThis->StatLevelIrqSent); 601 607 } 602 608 }
Note:
See TracChangeset
for help on using the changeset viewer.