- Timestamp:
- Sep 9, 2019 7:57:50 PM (5 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r80658 r80683 515 515 /** True if in the process of resetting */ 516 516 bool fResetting; 517 518 /** True if in the process of suspending */519 bool fSuspending;520 521 /** True if in the process of powering off */522 bool fPoweringOff;523 517 524 518 /** True if in the process of quiescing I/O */ … … 1673 1667 } 1674 1668 1675 /** Let guest to use the queues */ 1676 static void enableQueues(PVIRTIOSCSI pThis) 1677 { 1678 for (int qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++) 1679 virtioQueueEnable(pThis->hVirtio, qIdx, true); 1680 } 1681 1682 /** Tell guest to stop using the queues */ 1683 static void disableQueues(PVIRTIOSCSI pThis) 1684 { 1685 /** Tell guest to stop sending stuff */ 1686 for (int qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++) 1687 virtioQueueEnable(pThis->hVirtio, qIdx, false); 1688 } 1689 1690 /** 1691 * Handle callback from PDM's async notification mechanism. 1692 * In this case, the callback is triggered when I/O activity is quiesced. 1693 * 1694 * @returns true if we've quiesced, false if we're still working. 1695 * @param pDevIns The device instance. 1669 /** 1670 * Is asynchronous handling of suspend or power off notification completed? 1671 * 1672 * This is called to check whether the device has quiesced. Don't deadlock. 1673 * Avoid blocking. Do NOT wait for anything. 1674 * 1675 * @returns true if done, false if more work to be done. 1676 * 1677 * @param pDevIns The device instance. 1678 * @remarks The caller will enter the device critical section. 1679 * @thread EMT(0) 1696 1680 */ 1697 1681 static DECLCALLBACK(bool) virtioScsiDeviceQuiesced(PPDMDEVINS pDevIns) 1698 1682 { 1699 LogFunc((" \n"));1683 LogFunc(("Device I/O activity quiesced.\n")); 1700 1684 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1685 1686 pThis->fQuiescing = false; 1701 1687 1702 1688 if (pThis->fResetting) … … 1707 1693 virtioResetAll(pThis->hVirtio); 1708 1694 1709 /** Reset negotiable device-specific config parameters to VirtIO-specified default values */ 1695 /** Reset locally-owned negotiable device-specific config parameters 1696 * to VirtIO spec-mandated default values */ 1710 1697 pThis->virtioScsiConfig.uSenseSize = VIRTIOSCSI_SENSE_SIZE_DEFAULT; 1711 1698 pThis->virtioScsiConfig.uCdbSize = VIRTIOSCSI_CDB_SIZE_DEFAULT; 1712 1713 pThis->fQuiescing = false; 1714 1715 /** fQuiescing and fReset flags get cleared during [re-]initialization */ 1716 } 1717 else if (pThis->fSuspending || pThis->fPoweringOff) 1718 { 1719 /* Lower-level driver (DrvVD) has already suspended any I/O on wait queue */ 1720 } 1721 return false; 1699 } 1700 return true; 1722 1701 } 1723 1702 … … 1726 1705 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1727 1706 1728 pThis->fQuiescing = true; /* inhibit worker thread's de-queing*/1729 disableQueues(pThis); /* inhibit guest use of virtq's */1707 /** Prevent worker threads from removing/processing elements from virtq's */ 1708 pThis->fQuiescing = true; 1730 1709 1731 1710 PDMDevHlpSetAsyncNotification(pDevIns, virtioScsiDeviceQuiesced); … … 1763 1742 1764 1743 /** 1765 * @ interface_method_impl{PDMDEVREG,pfnResume}1766 */ 1767 static DECLCALLBACK(void) virtioScsiRes ume(PPDMDEVINS pDevIns)1744 * @copydoc FNPDMDEVRESET 1745 */ 1746 static DECLCALLBACK(void) virtioScsiReset(PPDMDEVINS pDevIns) 1768 1747 { 1769 1748 LogFunc(("\n")); 1770 1749 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1771 pThis->fSuspending = pThis->fQuiescing = false; 1772 enableQueues(pThis); 1750 pThis->fResetting = true; 1751 virtioScsiQuiesceDevice(pDevIns); 1752 } 1753 1754 /** 1755 * @interface_method_impl{PDMDEVREG,pfnResume} 1756 */ 1757 static DECLCALLBACK(void) virtioScsiResume(PPDMDEVINS pDevIns) 1758 { 1759 LogFunc(("\n")); 1760 1761 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1762 1763 pThis->fQuiescing = false; 1764 1765 /** Wake worker threads flagged to skip pulling queue entries during quiesce 1766 * to ensure they re-check their queues. Active request queues may already 1767 * be awake due to new reqs coming in. 1768 */ 1769 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++) 1770 { 1771 PWORKER pWorker = &pThis->aWorker[qIdx]; 1772 1773 if (ASMAtomicReadBool(&pWorker->fSleeping)) 1774 { 1775 Log6Func(("waking %s worker.\n", QUEUENAME(qIdx))); 1776 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pWorker->hEvtProcess); 1777 AssertRC(rc); 1778 } 1779 } 1780 1781 /** Ensure guest is working the queues too. */ 1782 virtioPropagateResumeNotification(pThis->hVirtio); 1773 1783 } 1774 1784 … … 1776 1786 * @interface_method_impl{PDMDEVREG,pfnSuspend} 1777 1787 */ 1778 static DECLCALLBACK(void) virtioScsiSuspend (PPDMDEVINS pDevIns)1788 static DECLCALLBACK(void) virtioScsiSuspendOrPoweroff(PPDMDEVINS pDevIns) 1779 1789 { 1780 1790 LogFunc(("\n")); 1781 1791 1792 virtioScsiQuiesceDevice(pDevIns); 1793 1782 1794 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI); 1783 1795 1784 pThis->fSuspending = true; 1785 1786 virtioScsiQuiesceDevice(pDevIns); 1787 1796 /** VM is halted, thus no new I/O being dumped into queues by the guest. 1797 * Workers have been flagged to stop pulling stuff already queued-up by the guest. 1798 * Now tell lower-level to to suspend reqs (for example, DrvVD suspends all reqs 1799 * on its wait queue, and we will get a callback as the state changes to 1800 * suspended (and later, resumed) for each). 1801 */ 1788 1802 for (uint32_t i = 0; i < pThis->cTargets; i++) 1789 1803 { … … 1793 1807 pTarget->pDrvMediaEx->pfnNotifySuspend(pTarget->pDrvMediaEx); 1794 1808 } 1795 }1796 1797 /**1798 * Common worker for virtioScsiSuspend and virtioScsiPowerOff.1799 */1800 static void virtioScsiPowerOn(PPDMDEVINS pDevIns)1801 {1802 LogFunc(("\n"));1803 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);1804 pThis->fPoweringOff = pThis->fQuiescing = false;1805 enableQueues(pThis);1806 }1807 1808 /**1809 * Common worker for virtioScsiSuspend and virtioScsiPowerOff.1810 */1811 static void virtioScsiPowerOff(PPDMDEVINS pDevIns)1812 {1813 LogFunc(("\n"));1814 1815 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);1816 1817 pThis->fPoweringOff = true;1818 virtioScsiQuiesceDevice(pDevIns);1819 1820 for (uint32_t i = 0; i < pThis->cTargets; i++)1821 {1822 PVIRTIOSCSITARGET pTarget = &pThis->aTargetInstances[i];1823 if (pTarget->pDrvBase)1824 if (pTarget->pDrvMediaEx)1825 pTarget->pDrvMediaEx->pfnNotifySuspend(pTarget->pDrvMediaEx);1826 }1827 }1828 1829 /**1830 * @copydoc FNPDMDEVRESET1831 */1832 static DECLCALLBACK(void) virtioScsiReset(PPDMDEVINS pDevIns)1833 {1834 LogFunc(("\n"));1835 1836 PVIRTIOSCSI pThis = PDMINS_2_DATA(pDevIns, PVIRTIOSCSI);1837 pThis->fResetting = true;1838 1839 virtioScsiQuiesceDevice(pDevIns);1840 1809 } 1841 1810 … … 2279 2248 if (RT_FAILURE(rc)) 2280 2249 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 2281 N_(" LsiLogic: Failed to create SUP event semaphore"));2250 N_("DevVirtioSCSI: Failed to create SUP event semaphore")); 2282 2251 } 2283 2252 } … … 2421 2390 /* .pfnRelocate = */ virtioScsiRelocate, 2422 2391 /* .pfnMemSetup = */ NULL, 2423 /* .pfnPowerOn = */ virtioScsiPowerOn,2392 /* .pfnPowerOn = */ NULL, 2424 2393 /* .pfnReset = */ virtioScsiReset, 2425 /* .pfnSuspend = */ virtioScsiSuspend ,2394 /* .pfnSuspend = */ virtioScsiSuspendOrPoweroff, 2426 2395 /* .pfnResume = */ virtioScsiResume, 2427 2396 /* .pfnAttach = */ virtioScsiAttach, … … 2429 2398 /* .pfnQueryInterface = */ NULL, 2430 2399 /* .pfnInitComplete = */ NULL, 2431 /* .pfnPowerOff = */ virtioScsi PowerOff,2400 /* .pfnPowerOff = */ virtioScsiSuspendOrPoweroff, 2432 2401 /* .pfnSoftReset = */ NULL, 2433 2402 /* .pfnReserved0 = */ NULL, -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r80657 r80683 88 88 return VINF_SUCCESS; 89 89 } 90 90 91 91 92 /** … … 294 295 295 296 virtioWriteUsedRingIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx); 296 virtioNotifyGuestDriver(pVirtio, qIdx );297 virtioNotifyGuestDriver(pVirtio, qIdx, false); 297 298 298 299 return VINF_SUCCESS; … … 309 310 Log6Func(("%s\n", pVirtqProxy->szVirtqName)); 310 311 311 312 312 /** Inform client */ 313 313 pVirtio->virtioCallbacks.pfnVirtioQueueNotified((VIRTIOHANDLE)pVirtio, pVirtio->pClientContext, qIdx); 314 } 315 316 /** 317 * See API comments in header file for description 318 */ 319 void virtioPropagateResumeNotification(VIRTIOHANDLE hVirtio) 320 { 321 virtioNotifyGuestDriver((PVIRTIOSTATE)hVirtio, (uint16_t)NULL /* qIdx */, true /* fForce */); 314 322 } 315 323 … … 319 327 * and depending on negotiated and realtime constraints flagged by the guest driver. 320 328 * See VirtIO 1.0 specification (section 2.4.7). 321 */ 322 static void virtioNotifyGuestDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx) 329 * 330 * @param pVirtio - Instance state 331 * @param qIdx - Queue to check for guest interrupt handling preference 332 * @param fForce - Overrides qIdx, forcing notification, regardless of driver's 333 * notification preferences. This is a safeguard to prevent 334 * stalls upon resuming the VM. VirtIO 1.0 specification Section 4.1.5.5 335 * indicates spurious interrupts are harmless to guest driver's state, 336 * as they only cause the guest driver to scan queues for work to do. 337 */ 338 static void virtioNotifyGuestDriver(PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce) 323 339 { 324 340 PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx]; 325 341 326 AssertMsgReturnVoid(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx], 327 ("Guest driver not in ready state.\n")); 328 329 if (pVirtio->uQueueMsixVector[qIdx] == VIRTIO_MSI_NO_VECTOR) 342 AssertMsgReturnVoid(DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n")); 343 344 if (pVirtio->uMsixConfig == VIRTIO_MSI_NO_VECTOR) 330 345 { 331 346 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) … … 333 348 if (pVirtqProxy->fEventThresholdReached) 334 349 { 335 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT );350 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce); 336 351 pVirtqProxy->fEventThresholdReached = false; 337 352 return; … … 342 357 { 343 358 /** If guest driver hasn't suppressed interrupts, interrupt */ 344 if ( !(virtioReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT))359 if (fForce || !(virtioReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 345 360 { 346 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT );361 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce); 347 362 return; 348 363 } 349 364 Log6Func(("...skipping interrupt. Guest flagged VIRTQ_AVAIL_F_NO_INTERRUPT for queue\n")); 350 351 365 } 352 366 } … … 392 406 * @param uCause Interrupt cause bit mask to set in PCI ISR port. 393 407 */ 394 static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause) 395 { 408 static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause, bool fForce) 409 { 410 411 if (fForce) 412 Log6Func(("reason: resumed after suspend\n")); 413 else 396 414 if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT) 397 415 Log6Func(("reason: buffer added to 'used' ring.\n")); … … 480 498 { 481 499 pVirtio->fGenUpdatePending = true; 482 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_DEVICE_CONFIG );500 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_DEVICE_CONFIG, false /* fForce */); 483 501 } 484 502 } -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80657 r80683 289 289 void virtioResetAll(VIRTIOHANDLE hVirtio); 290 290 291 /** 292 * This sends notification ('kicks') guest driver to check queues for any new 293 * elements in the used queue to process. It should be called after resuming 294 * in case anything was added to the queues during suspend/quiescing and a 295 * notification was missed, to prevent the guest from stalling after suspend. 296 */ 297 void virtioPropagateResumeNotification(VIRTIOHANDLE hVirtio); 298 291 299 292 300 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r80647 r80683 535 535 536 536 static void virtioResetQueue (PVIRTIOSTATE pVirtio, uint16_t qIdx); 537 static void virtioNotifyGuestDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx );538 static int virtioRaiseInterrupt (PVIRTIOSTATE pVirtio, uint8_t uCause );537 static void virtioNotifyGuestDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce); 538 static int virtioRaiseInterrupt (PVIRTIOSTATE pVirtio, uint8_t uCause, bool fForce); 539 539 static void virtioLowerInterrupt (PVIRTIOSTATE pVirtio); 540 540 static void virtioQueueNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
Note:
See TracChangeset
for help on using the changeset viewer.