Changeset 59875 in vbox
- Timestamp:
- Feb 29, 2016 3:53:00 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
-
include/VBox/vusb.h (modified) (5 diffs)
-
src/VBox/Devices/USB/DevOHCI.cpp (modified) (15 diffs)
-
src/VBox/Devices/USB/DrvVUSBRootHub.cpp (modified) (5 diffs)
-
src/VBox/Devices/USB/VUSBInternal.h (modified) (3 diffs)
-
src/VBox/Devices/USB/VUSBUrb.cpp (modified) (1 diff)
-
src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vusb.h
r59723 r59875 29 29 #include <VBox/cdefs.h> 30 30 #include <VBox/types.h> 31 #include <iprt/assert.h> 31 32 32 33 struct PDMLED; … … 645 646 DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)); 646 647 648 /** 649 * Processes a new frame if periodic frame processing is enabled. 650 * 651 * @returns Flag whether there was activity which influences the frame rate. 652 * @param pInterface Pointer to this structure. 653 * @param u32FrameNo The frame number. 654 */ 655 DECLR3CALLBACKMEMBER(bool, pfnStartFrame, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo)); 656 657 /** 658 * Informs the callee about a change in the frame rate due to too many idle cycles or 659 * when seeing activity after some idle time. 660 * 661 * @returns nothing. 662 * @param pInterface Pointer to this structure. 663 * @param u32Framerate The new frame rate. 664 */ 665 DECLR3CALLBACKMEMBER(void, pfnFrameRateChanged, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate)); 666 647 667 /** Alignment dummy. */ 648 668 RTR3PTR Alignment; … … 650 670 } VUSBIROOTHUBPORT; 651 671 /** VUSBIROOTHUBPORT interface ID. */ 652 #define VUSBIROOTHUBPORT_IID " 79a31188-043d-432c-82ac-9485c9ab9a49"672 #define VUSBIROOTHUBPORT_IID "6571aece-6c33-4714-a8ac-9508a3b8b429" 653 673 654 674 /** Pointer to a VUSB RootHub connector interface. */ … … 789 809 DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)); 790 810 791 /** Alignment dummy. */ 792 RTR3PTR Alignment; 811 /** 812 * Sets periodic frame processing. 813 * 814 * @returns VBox status code. 815 * @param pInterface Pointer to this struct. 816 * @param uFrameRate The target frame rate in Hertz, 0 disables periodic frame processing. 817 * The real frame rate might be lower if there is no activity for a certain period or 818 * higher if there is a need for catching up with where the guest expects the device to be. 819 */ 820 DECLR3CALLBACKMEMBER(int, pfnSetPeriodicFrameProcessing, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate)); 821 822 /** 823 * Returns the current frame rate for the periodic frame processing. 824 * 825 * @returns Frame rate for periodic frame processing. 826 * @retval 0 if disabled. 827 * @param pInterface Pointer to this struct. 828 */ 829 DECLR3CALLBACKMEMBER(uint32_t, pfnGetPeriodicFrameRate, (PVUSBIROOTHUBCONNECTOR pInterface)); 793 830 794 831 } VUSBIROOTHUBCONNECTOR; 832 AssertCompileSizeAlignment(VUSBIROOTHUBCONNECTOR, 8); 795 833 /** VUSBIROOTHUBCONNECTOR interface ID. */ 796 #define VUSBIROOTHUBCONNECTOR_IID " a593cc64-a821-4e57-af2d-f86b2a052ea4"834 #define VUSBIROOTHUBCONNECTOR_IID "662d7822-b9c6-43b5-88b6-5d59f0106e46" 797 835 798 836 … … 845 883 { 846 884 return pInterface->pfnDetachDevice(pInterface, pDevice); 885 } 886 887 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */ 888 DECLINLINE(int) VUSBIRhSetPeriodicFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate) 889 { 890 return pInterface->pfnSetPeriodicFrameProcessing(pInterface, uFrameRate); 891 } 892 893 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */ 894 DECLINLINE(uint32_t) VUSBIRhGetPeriodicFrameRate(PVUSBIROOTHUBCONNECTOR pInterface) 895 { 896 return pInterface->pfnGetPeriodicFrameRate(pInterface); 847 897 } 848 898 #endif /* IN_RING3 */ -
trunk/src/VBox/Devices/USB/DevOHCI.cpp
r59704 r59875 223 223 R3PTRTYPE(POHCI) pOhci; 224 224 } OHCIROOTHUB; 225 #if HC_ARCH_BITS == 64226 AssertCompile(sizeof(OHCIROOTHUB) == 392); /* saved state */227 #endif228 225 /** Pointer to the OHCI root hub. */ 229 226 typedef OHCIROOTHUB *POHCIROOTHUB; … … 387 384 /** VM timer frequency used for frame timer calculations. */ 388 385 uint64_t u64TimerHz; 389 /** Number of USB work cycles with no transfers. */390 uint32_t cIdleCycles;391 /** Current frame timer rate (default 1000). */392 uint32_t uFrameRate;393 386 /** Idle detection flag; must be cleared at start of frame */ 394 387 bool fIdle; … … 403 396 /** Critical section synchronising interrupt handling. */ 404 397 PDMCRITSECT CsIrq; 405 406 /** The framer thread. */407 R3PTRTYPE(PPDMTHREAD) hThreadFrame;408 /** Event semaphore to interact with the framer thread. */409 R3PTRTYPE(RTSEMEVENTMULTI) hSemEventFrame;410 /** Event semaphore to release the thread waiting for the framer thread to stop. */411 R3PTRTYPE(RTSEMEVENTMULTI) hSemEventFrameStopped;412 /** Flag whether the framer thread should processing frames. */413 volatile bool fBusStarted;414 /** Alignment. */415 uint32_t Alignment5;416 /** How long to wait until the next frame. */417 uint64_t nsWait;418 398 /** Critical section to synchronize the framer and URB completion handler. */ 419 399 RTCRITSECT CritSect; … … 2193 2173 2194 2174 /** 2195 * Calculate frame timer variables given a frame rate (1,000 Hz is the full speed).2196 */2197 static void ohciCalcTimerIntervals(POHCI pThis, uint32_t u32FrameRate)2198 {2199 Assert(u32FrameRate <= OHCI_DEFAULT_TIMER_FREQ);2200 2201 pThis->cTicksPerFrame = pThis->u64TimerHz / u32FrameRate;2202 if (!pThis->cTicksPerFrame)2203 pThis->cTicksPerFrame = 1;2204 pThis->cTicksPerUsbTick = pThis->u64TimerHz >= VUSB_BUS_HZ ? pThis->u64TimerHz / VUSB_BUS_HZ : 1;2205 pThis->nsWait = RT_NS_1SEC / u32FrameRate;2206 pThis->uFrameRate = u32FrameRate;2207 }2208 2209 2210 /**2211 * Calculates the new frame rate based on the idle detection and number of idle2212 * cycles.2213 *2214 * @returns nothing.2215 * @param pThis The OHCI device data.2216 */2217 static bool ohciFramerateCalcNew(POHCI pThis)2218 {2219 uint32_t uNewFrameRate = pThis->uFrameRate;2220 2221 /*2222 * Adjust the frame timer interval based on idle detection.2223 */2224 if (pThis->fIdle)2225 {2226 pThis->cIdleCycles++;2227 /* Set the new frame rate based on how long we've been idle. Tunable. */2228 switch (pThis->cIdleCycles)2229 {2230 case 4: uNewFrameRate = 500; break; /* 2ms interval */2231 case 16:uNewFrameRate = 125; break; /* 8ms interval */2232 case 24:uNewFrameRate = 50; break; /* 20ms interval */2233 default: break;2234 }2235 /* Avoid overflow. */2236 if (pThis->cIdleCycles > 60000)2237 pThis->cIdleCycles = 20000;2238 }2239 else2240 {2241 if (pThis->cIdleCycles)2242 {2243 pThis->cIdleCycles = 0;2244 uNewFrameRate = OHCI_DEFAULT_TIMER_FREQ;2245 }2246 }2247 if (uNewFrameRate != pThis->uFrameRate)2248 {2249 LogFlow(("Frame rate changed from %u to %u\n", pThis->uFrameRate, uNewFrameRate));2250 ohciCalcTimerIntervals(pThis, uNewFrameRate);2251 return true;2252 }2253 return false;2254 }2255 2256 2257 /**2258 2175 * Returns the OHCI_CC_* corresponding to the VUSB status code. 2259 2176 * … … 2640 2557 /* finally write back the endpoint descriptor. */ 2641 2558 ohciWriteEd(pThis, pUrb->pHci->EdAddr, &Ed); 2642 2643 /* Calculate new frame rate and wakeup the framer thread if the rate was chnaged. */2644 if (ohciFramerateCalcNew(pThis))2645 RTSemEventMultiSignal(pThis->hSemEventFrame);2646 2559 2647 2560 RTCritSectLeave(&pThis->CritSect); … … 3874 3787 } 3875 3788 #endif 3876 3877 /*3878 * Adjust the frame timer interval based on idle detection.3879 */3880 ohciFramerateCalcNew(pThis);3881 3789 } 3882 3790 … … 3891 3799 } 3892 3800 3893 static DECLCALLBACK(int) ohciR3ThreadFrame(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 3894 { 3895 POHCI pThis = (POHCI)pThread->pvUser; 3896 uint64_t tsBeginServicing = 0; 3897 uint64_t cFramesProcessed = 0; 3898 3899 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 3900 return VINF_SUCCESS; 3901 3902 tsBeginServicing = RTTimeNanoTS(); 3903 cFramesProcessed = 0; 3904 3905 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 3906 { 3907 while ( !ASMAtomicReadBool(&pThis->fBusStarted) 3908 && pThread->enmState == PDMTHREADSTATE_RUNNING) 3909 { 3910 /* Signal the waiter that we are stopped now. */ 3911 int rc = RTSemEventMultiSignal(pThis->hSemEventFrameStopped); 3912 AssertRC(rc); 3913 rc = RTSemEventMultiReset(pThis->hSemEventFrame); 3914 AssertRC(rc); 3915 3916 /* 3917 * We have to check that the Bus was not started and the thread state 3918 * did not change or otherwise we risk hanging here indefinitely 3919 * if the signaller set the event semaphore before we reset it. 3920 */ 3921 if (ASMAtomicReadBool(&pThis->fBusStarted) || pThread->enmState != PDMTHREADSTATE_RUNNING) 3922 break; 3923 3924 rc = RTSemEventMultiWait(pThis->hSemEventFrame, RT_INDEFINITE_WAIT); 3925 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc), rc); 3926 tsBeginServicing = RTTimeNanoTS(); 3927 cFramesProcessed = 0; 3928 } 3929 3930 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 3931 break; 3932 3933 RTCritSectEnter(&pThis->CritSect); 3934 3935 /* Reset idle detection flag */ 3936 pThis->fIdle = true; 3937 3938 /* 3939 * Process new frames until we reached the required amount of 3940 * frames for this service period. We might need to catch up 3941 * here and process multiple frames at once due to scheduling 3942 * preempting us. This is required because isochronous transfers 3943 * have a tight timing requirement. 3944 */ 3945 uint64_t tsNow = RTTimeNanoTS(); 3946 uint64_t nsWait = 0; 3947 while (tsBeginServicing + (cFramesProcessed * RT_NS_1MS) < tsNow) 3948 { 3949 uint64_t tsNanoStart = RTTimeNanoTS(); 3950 LogFlowFunc(("Starting new frame at ts %llu\n", tsNanoStart)); 3951 3952 /* Frame boundary, so do EOF stuff here. */ 3953 bump_frame_number(pThis); 3954 if ( (pThis->dqic != 0x7) && (pThis->dqic != 0)) 3955 pThis->dqic--; 3956 3957 /* Clean up any URBs that have been removed. */ 3958 ohciCancelOrphanedURBs(pThis); 3959 3960 /* Start the next frame. */ 3961 ohciStartOfFrame(pThis); 3962 cFramesProcessed++; 3963 3964 tsNow = RTTimeNanoTS(); 3965 uint64_t tsFrameNext = tsNanoStart + pThis->nsWait; 3966 3967 if (tsFrameNext > tsNow) 3968 { 3969 nsWait = tsFrameNext - tsNow; 3970 LogFlowFunc(("Current frame took %llu nano seconds to finish, we can wait %llu ns for the next frame\n", tsNow - tsNanoStart, nsWait)); 3971 break; 3972 } 3973 else if (tsBeginServicing + (cFramesProcessed + 100) * RT_NS_1MS < tsNow) 3974 { 3975 /* If we lag to far behind stop trying to catch up. */ 3976 LogRelMax(10, ("OHCI#%u: Lagging too far behind, not trying to catch up anymore. Expect glitches with USB devices\n", 3977 pThis->pDevInsR3->iInstance)); 3978 tsBeginServicing = tsNow; 3979 cFramesProcessed = 0; 3980 } 3981 } 3982 3983 RTCritSectLeave(&pThis->CritSect); 3984 3985 /* Wait for the next round. */ 3986 if (nsWait >= 500 * RT_NS_1US) 3987 { 3988 LogFlowFunc(("Going to sleep for at least %llu ns\n", nsWait)); 3989 int rc = RTSemEventMultiWaitEx(pThis->hSemEventFrame, RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_UNINTERRUPTIBLE, 3990 nsWait); 3991 AssertLogRelMsg(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc)); 3992 RTSemEventMultiReset(pThis->hSemEventFrame); 3993 } 3994 } 3995 3996 return VINF_SUCCESS; 3997 } 3998 3999 /** 4000 * Unblock the framer thread so it can respond to a state change. 4001 * 4002 * @returns VBox status code. 4003 * @param pDevIns The device instance. 4004 * @param pThread The send thread. 4005 */ 4006 static DECLCALLBACK(int) ohciR3ThreadFrameWakeup(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 4007 { 4008 POHCI pThis = PDMINS_2_DATA(pDevIns, POHCI); 4009 return RTSemEventMultiSignal(pThis->hSemEventFrame); 3801 /** 3802 * Callback for periodic frame processing. 3803 */ 3804 static DECLCALLBACK(bool) ohciR3StartFrame(PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo) 3805 { 3806 POHCI pThis = VUSBIROOTHUBPORT_2_OHCI(pInterface); 3807 3808 RTCritSectEnter(&pThis->CritSect); 3809 3810 /* Reset idle detection flag */ 3811 pThis->fIdle = true; 3812 3813 /* Frame boundary, so do EOF stuff here. */ 3814 bump_frame_number(pThis); 3815 if ( (pThis->dqic != 0x7) && (pThis->dqic != 0)) 3816 pThis->dqic--; 3817 3818 /* Clean up any URBs that have been removed. */ 3819 ohciCancelOrphanedURBs(pThis); 3820 3821 /* Start the next frame. */ 3822 ohciStartOfFrame(pThis); 3823 3824 RTCritSectLeave(&pThis->CritSect); 3825 3826 return pThis->fIdle; 3827 } 3828 3829 /** 3830 * @copydoc VUSBIROOTHUBPORT::pfnFramerateChanged. 3831 */ 3832 static DECLCALLBACK(void) ohciR3FrameRateChanged(PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate) 3833 { 3834 POHCI pThis = VUSBIROOTHUBPORT_2_OHCI(pInterface); 3835 3836 Assert(u32FrameRate <= OHCI_DEFAULT_TIMER_FREQ); 3837 3838 pThis->cTicksPerFrame = pThis->u64TimerHz / u32FrameRate; 3839 if (!pThis->cTicksPerFrame) 3840 pThis->cTicksPerFrame = 1; 3841 pThis->cTicksPerUsbTick = pThis->u64TimerHz >= VUSB_BUS_HZ ? pThis->u64TimerHz / VUSB_BUS_HZ : 1; 4010 3842 } 4011 3843 … … 4029 3861 4030 3862 pThis->SofTime = PDMDevHlpTMTimeVirtGet(pThis->CTX_SUFF(pDevIns)); 4031 bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, true); 4032 if (!fBusActive) 4033 RTSemEventMultiSignal(pThis->hSemEventFrame); 3863 int rc = pThis->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThis->RootHub.pIRhConn, OHCI_DEFAULT_TIMER_FREQ); 3864 AssertRC(rc); 4034 3865 } 4035 3866 … … 4039 3870 static void ohciBusStop(POHCI pThis) 4040 3871 { 4041 bool fBusActive = ASMAtomicXchgBool(&pThis->fBusStarted, false); 4042 if (fBusActive) 4043 { 4044 int rc = RTSemEventMultiReset(pThis->hSemEventFrameStopped); 4045 AssertRC(rc); 4046 4047 /* Signal the frame thread to stop. */ 4048 RTSemEventMultiSignal(pThis->hSemEventFrame); 4049 4050 /* Wait for signal from the thrad that it stopped. */ 4051 rc = RTSemEventMultiWait(pThis->hSemEventFrameStopped, RT_INDEFINITE_WAIT); 4052 AssertRC(rc); 4053 } 3872 int rc = pThis->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThis->RootHub.pIRhConn, 0); 3873 AssertRC(rc); 4054 3874 VUSBIDevPowerOff(pThis->RootHub.pIDev); 4055 3875 } … … 5268 5088 */ 5269 5089 /** @todo: Do it properly for 4.4 by changing the saved state. */ 5270 if ( pThis->fBusStarted)5090 if (VUSBIRhGetPeriodicFrameRate(pRh->pIRhConn) != 0) 5271 5091 { 5272 5092 /* Calculate a new timer expiration so this saved state works with older releases. */ … … 5680 5500 AssertRC(rc); 5681 5501 5682 LogFlowFunc(("Bus was active, restart frame thread\n"));5683 ASMAtomicXchgBool(&pThis->fBusStarted, true);5684 RTSemEventMultiSignal(pThis->hSemEventFrame);5502 LogFlowFunc(("Bus was active, enable periodic frame processing\n")); 5503 rc = pThis->RootHub.pIRhConn->pfnSetPeriodicFrameProcessing(pThis->RootHub.pIRhConn, OHCI_DEFAULT_TIMER_FREQ); 5504 AssertRC(rc); 5685 5505 } 5686 5506 } … … 5772 5592 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 5773 5593 5774 /*5775 * Destroy event sempahores.5776 */5777 if (pThis->hSemEventFrame)5778 RTSemEventMultiDestroy(pThis->hSemEventFrame);5779 if (pThis->hSemEventFrameStopped)5780 RTSemEventMultiDestroy(pThis->hSemEventFrameStopped);5781 5594 if (RTCritSectIsInitialized(&pThis->CritSect)) 5782 5595 RTCritSectDelete(&pThis->CritSect); … … 5827 5640 pThis->RootHub.IRhPort.pfnXferCompletion = ohciRhXferCompletion; 5828 5641 pThis->RootHub.IRhPort.pfnXferError = ohciRhXferError; 5642 pThis->RootHub.IRhPort.pfnStartFrame = ohciR3StartFrame; 5643 pThis->RootHub.IRhPort.pfnFrameRateChanged = ohciR3FrameRateChanged; 5829 5644 5830 5645 /* USB LED */ … … 5942 5757 */ 5943 5758 pThis->u64TimerHz = TMTimerGetFreq(pThis->CTX_SUFF(pEndOfFrameTimer)); 5944 ohciCalcTimerIntervals(pThis, OHCI_DEFAULT_TIMER_FREQ);5945 Log(("ohci: cTicksPerFrame=%RU64 cTicksPerUsbTick=%RU64\n",5946 pThis->cTicksPerFrame, pThis->cTicksPerUsbTick));5947 5948 pThis->fBusStarted = false;5949 5759 5950 5760 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CsIrq, RT_SRC_POS, "OHCI#%uIrq", iInstance); … … 5953 5763 N_("OHCI: Failed to create critical section")); 5954 5764 5955 rc = RTSemEventMultiCreate(&pThis->hSemEventFrame);5956 AssertRCReturn(rc, rc);5957 5958 rc = RTSemEventMultiCreate(&pThis->hSemEventFrameStopped);5959 AssertRCReturn(rc, rc);5960 5961 5765 rc = RTCritSectInit(&pThis->CritSect); 5962 5766 if (RT_FAILURE(rc)) 5963 5767 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 5964 5768 N_("OHCI: Failed to create critical section")); 5965 5966 rc = PDMDevHlpThreadCreate(pDevIns, &pThis->hThreadFrame, pThis, ohciR3ThreadFrame,5967 ohciR3ThreadFrameWakeup, 0, RTTHREADTYPE_TIMER, "OhciFramer");5968 if (RT_FAILURE(rc))5969 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,5970 N_("OHCI: Failed to create worker thread"));5971 5769 5972 5770 /* -
trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp
r59775 r59875 415 415 416 416 417 /** 418 * Calculate frame timer variables given a frame rate. 419 */ 420 static void vusbRhR3CalcTimerIntervals(PVUSBROOTHUB pThis, uint32_t u32FrameRate) 421 { 422 pThis->nsWait = RT_NS_1SEC / u32FrameRate; 423 pThis->uFrameRate = u32FrameRate; 424 /* Inform the HCD about the new frame rate. */ 425 pThis->pIRhPort->pfnFrameRateChanged(pThis->pIRhPort, u32FrameRate); 426 } 427 428 429 /** 430 * Calculates the new frame rate based on the idle detection and number of idle 431 * cycles. 432 * 433 * @returns nothing. 434 * @param pThis The roothub instance data. 435 * @param fIdle Flag whether the last frame didn't produce any activity. 436 */ 437 static void vusbRhR3FrameRateCalcNew(PVUSBROOTHUB pThis, bool fIdle) 438 { 439 uint32_t uNewFrameRate = pThis->uFrameRate; 440 441 /* 442 * Adjust the frame timer interval based on idle detection. 443 */ 444 if (fIdle) 445 { 446 pThis->cIdleCycles++; 447 /* Set the new frame rate based on how long we've been idle. Tunable. */ 448 switch (pThis->cIdleCycles) 449 { 450 case 4: uNewFrameRate = 500; break; /* 2ms interval */ 451 case 16:uNewFrameRate = 125; break; /* 8ms interval */ 452 case 24:uNewFrameRate = 50; break; /* 20ms interval */ 453 default: break; 454 } 455 /* Avoid overflow. */ 456 if (pThis->cIdleCycles > 60000) 457 pThis->cIdleCycles = 20000; 458 } 459 else 460 { 461 if (pThis->cIdleCycles) 462 { 463 pThis->cIdleCycles = 0; 464 uNewFrameRate = pThis->uFrameRateDefault; 465 } 466 } 467 468 if (uNewFrameRate != pThis->uFrameRate) 469 { 470 LogFlow(("Frame rate changed from %u to %u\n", pThis->uFrameRate, uNewFrameRate)); 471 vusbRhR3CalcTimerIntervals(pThis, uNewFrameRate); 472 } 473 } 474 475 476 /** 477 * The core frame processing routine keeping track of the elapsed time and calling into 478 * the device emulation above us to do the work. 479 * 480 * @returns Relative timespan when to process the next frame. 481 * @param pThis The roothub instance data. 482 * @param fCallback Flag whether this method is called from the URB completion callback or 483 * from the worker thread (only used for statistics). 484 */ 485 DECLHIDDEN(uint64_t) vusbRhR3ProcessFrame(PVUSBROOTHUB pThis, bool fCallback) 486 { 487 uint64_t tsNext = 0; 488 uint64_t tsNanoStart = RTTimeNanoTS(); 489 490 /* Don't do anything if we are not supposed to process anything (EHCI and XHCI). */ 491 if (!pThis->uFrameRateDefault) 492 return 0; 493 494 if (ASMAtomicXchgBool(&pThis->fFrameProcessing, true)) 495 return pThis->nsWait; 496 497 if ( tsNanoStart > pThis->tsFrameProcessed 498 && tsNanoStart - pThis->tsFrameProcessed >= 750 * RT_NS_1US) 499 { 500 LogFlowFunc(("Starting new frame at ts %llu\n", tsNanoStart)); 501 502 bool fIdle = pThis->pIRhPort->pfnStartFrame(pThis->pIRhPort, 0 /* u32FrameNo */); 503 vusbRhR3FrameRateCalcNew(pThis, fIdle); 504 505 uint64_t tsNow = RTTimeNanoTS(); 506 tsNext = (tsNanoStart + pThis->nsWait) > tsNow ? (tsNanoStart + pThis->nsWait) - tsNow : 0; 507 pThis->tsFrameProcessed = tsNanoStart; 508 LogFlowFunc(("Current frame took %llu nano seconds to process, next frame in %llu ns\n", tsNow - tsNanoStart, tsNext)); 509 if (fCallback) 510 STAM_COUNTER_INC(&pThis->StatFramesProcessedClbk); 511 else 512 STAM_COUNTER_INC(&pThis->StatFramesProcessedThread); 513 } 514 else 515 { 516 tsNext = (pThis->tsFrameProcessed + pThis->nsWait) > tsNanoStart ? (pThis->tsFrameProcessed + pThis->nsWait) - tsNanoStart : 0; 517 LogFlowFunc(("Next frame is too far away in the future, waiting... (tsNanoStart=%llu tsFrameProcessed=%llu)\n", 518 tsNanoStart, pThis->tsFrameProcessed)); 519 } 520 521 ASMAtomicXchgBool(&pThis->fFrameProcessing, false); 522 LogFlowFunc(("returns %llu\n", tsNext)); 523 return tsNext; 524 } 525 526 527 /** 528 * Worker for processing frames periodically. 529 * 530 * @returns VBox status code. 531 * @param pDrvIns The driver instance. 532 * @param pThread The PDM thread structure for the thread this worker runs on. 533 */ 534 static DECLCALLBACK(int) vusbRhR3PeriodFrameWorker(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 535 { 536 int rc = VINF_SUCCESS; 537 PVUSBROOTHUB pThis = (PVUSBROOTHUB)pThread->pvUser; 538 539 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) 540 return VINF_SUCCESS; 541 542 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 543 { 544 while ( !ASMAtomicReadU32(&pThis->uFrameRateDefault) 545 && pThread->enmState == PDMTHREADSTATE_RUNNING) 546 { 547 /* Signal the waiter that we are stopped now. */ 548 rc = RTSemEventMultiSignal(pThis->hSemEventPeriodFrameStopped); 549 AssertRC(rc); 550 551 rc = RTSemEventMultiWait(pThis->hSemEventPeriodFrame, RT_INDEFINITE_WAIT); 552 RTSemEventMultiReset(pThis->hSemEventPeriodFrame); 553 } 554 555 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc), rc); 556 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING)) 557 break; 558 559 uint64_t tsNext = vusbRhR3ProcessFrame(pThis, false /* fCallback */); 560 561 if (tsNext >= 250 * RT_NS_1US) 562 { 563 rc = RTSemEventMultiWaitEx(pThis->hSemEventPeriodFrame, RTSEMWAIT_FLAGS_RELATIVE | RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_UNINTERRUPTIBLE, 564 tsNext); 565 AssertLogRelMsg(RT_SUCCESS(rc) || rc == VERR_TIMEOUT, ("%Rrc\n", rc)); 566 RTSemEventMultiReset(pThis->hSemEventPeriodFrame); 567 } 568 } 569 570 return VINF_SUCCESS; 571 } 572 573 574 /** 575 * Unblock the periodic frame thread so it can respond to a state change. 576 * 577 * @returns VBox status code. 578 * @param pDrvIns The driver instance. 579 * @param pThread The send thread. 580 */ 581 static DECLCALLBACK(int) vusbRhR3PeriodFrameWorkerWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) 582 { 583 PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB); 584 return RTSemEventMultiSignal(pThis->hSemEventPeriodFrame); 585 } 586 587 417 588 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */ 418 589 static DECLCALLBACK(int) vusbRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd) … … 703 874 704 875 876 /** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetFrameProcessing */ 877 static DECLCALLBACK(int) vusbRhSetFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate) 878 { 879 int rc = VINF_SUCCESS; 880 PVUSBROOTHUB pThis = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface); 881 882 /* Create the frame thread lazily. */ 883 if ( !pThis->hThreadPeriodFrame 884 && uFrameRate) 885 { 886 ASMAtomicXchgU32(&pThis->uFrameRateDefault, uFrameRate); 887 pThis->uFrameRate = uFrameRate; 888 vusbRhR3CalcTimerIntervals(pThis, uFrameRate); 889 890 rc = RTSemEventMultiCreate(&pThis->hSemEventPeriodFrame); 891 AssertRCReturn(rc, rc); 892 893 rc = RTSemEventMultiCreate(&pThis->hSemEventPeriodFrameStopped); 894 AssertRCReturn(rc, rc); 895 896 rc = PDMDrvHlpThreadCreate(pThis->pDrvIns, &pThis->hThreadPeriodFrame, pThis, vusbRhR3PeriodFrameWorker, 897 vusbRhR3PeriodFrameWorkerWakeup, 0, RTTHREADTYPE_IO, "VUsbPeriodFrm"); 898 AssertRCReturn(rc, rc); 899 900 rc = PDMR3ThreadResume(pThis->hThreadPeriodFrame); 901 AssertRCReturn(rc, rc); 902 } 903 else if ( pThis->hThreadPeriodFrame 904 && !uFrameRate) 905 { 906 /* Stop processing. */ 907 uint32_t uFrameRateOld = ASMAtomicXchgU32(&pThis->uFrameRateDefault, uFrameRate); 908 if (uFrameRateOld) 909 { 910 rc = RTSemEventMultiReset(pThis->hSemEventPeriodFrameStopped); 911 AssertRC(rc); 912 913 /* Signal the frame thread to stop. */ 914 RTSemEventMultiSignal(pThis->hSemEventPeriodFrame); 915 916 /* Wait for signal from the thread that it stopped. */ 917 rc = RTSemEventMultiWait(pThis->hSemEventPeriodFrameStopped, RT_INDEFINITE_WAIT); 918 AssertRC(rc); 919 } 920 } 921 else if ( pThis->hThreadPeriodFrame 922 && uFrameRate) 923 { 924 /* Just switch to the new frame rate and let the periodic frame thread pick it up. */ 925 ASMAtomicXchgU32(&pThis->uFrameRateDefault, uFrameRate); 926 } 927 928 return rc; 929 } 930 931 705 932 /* -=-=-=-=-=- VUSB Device methods (for the root hub) -=-=-=-=-=- */ 706 933 … … 920 1147 if (pRh->hSniffer != VUSBSNIFFER_NIL) 921 1148 VUSBSnifferDestroy(pRh->hSniffer); 1149 1150 if (pRh->hSemEventPeriodFrame) 1151 RTSemEventMultiDestroy(pRh->hSemEventPeriodFrame); 1152 1153 if (pRh->hSemEventPeriodFrameStopped) 1154 RTSemEventMultiDestroy(pRh->hSemEventPeriodFrameStopped); 1155 922 1156 RTCritSectDelete(&pRh->CritSectDevices); 923 1157 } … … 985 1219 pThis->pDrvIns = pDrvIns; 986 1220 /* the connector */ 987 pThis->IRhConnector.pfnSetUrbParams = vusbRhSetUrbParams; 988 pThis->IRhConnector.pfnNewUrb = vusbRhConnNewUrb; 989 pThis->IRhConnector.pfnFreeUrb = vusbRhConnFreeUrb; 990 pThis->IRhConnector.pfnSubmitUrb = vusbRhSubmitUrb; 991 pThis->IRhConnector.pfnReapAsyncUrbs= vusbRhReapAsyncUrbs; 992 pThis->IRhConnector.pfnCancelUrbsEp = vusbRhCancelUrbsEp; 993 pThis->IRhConnector.pfnCancelAllUrbs= vusbRhCancelAllUrbs; 994 pThis->IRhConnector.pfnAbortEp = vusbRhAbortEp; 995 pThis->IRhConnector.pfnAttachDevice = vusbRhAttachDevice; 996 pThis->IRhConnector.pfnDetachDevice = vusbRhDetachDevice; 997 pThis->hSniffer = VUSBSNIFFER_NIL; 998 pThis->cbHci = 0; 999 pThis->cbHciTd = 0; 1221 pThis->IRhConnector.pfnSetUrbParams = vusbRhSetUrbParams; 1222 pThis->IRhConnector.pfnNewUrb = vusbRhConnNewUrb; 1223 pThis->IRhConnector.pfnFreeUrb = vusbRhConnFreeUrb; 1224 pThis->IRhConnector.pfnSubmitUrb = vusbRhSubmitUrb; 1225 pThis->IRhConnector.pfnReapAsyncUrbs = vusbRhReapAsyncUrbs; 1226 pThis->IRhConnector.pfnCancelUrbsEp = vusbRhCancelUrbsEp; 1227 pThis->IRhConnector.pfnCancelAllUrbs = vusbRhCancelAllUrbs; 1228 pThis->IRhConnector.pfnAbortEp = vusbRhAbortEp; 1229 pThis->IRhConnector.pfnAttachDevice = vusbRhAttachDevice; 1230 pThis->IRhConnector.pfnDetachDevice = vusbRhDetachDevice; 1231 pThis->IRhConnector.pfnSetPeriodicFrameProcessing = vusbRhSetFrameProcessing; 1232 pThis->hSniffer = VUSBSNIFFER_NIL; 1233 pThis->cbHci = 0; 1234 pThis->cbHciTd = 0; 1235 pThis->fFrameProcessing = false; 1000 1236 #ifdef LOG_ENABLED 1001 pThis->iSerial = 0;1237 pThis->iSerial = 0; 1002 1238 #endif 1003 1239 /* … … 1168 1404 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReapAsyncUrbs, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Profiling the vusbRhReapAsyncUrbs body (omitting calls when nothing is in-flight).", "/VUSB/%d/ReapAsyncUrbs", pDrvIns->iInstance); 1169 1405 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSubmitUrb, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Profiling the vusbRhSubmitUrb body.", "/VUSB/%d/SubmitUrb", pDrvIns->iInstance); 1406 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatFramesProcessedThread, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Processed frames in the dedicated thread", "/VUSB/%d/FramesProcessedThread", pDrvIns->iInstance); 1407 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatFramesProcessedClbk, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Processed frames in the URB completion callback", "/VUSB/%d/FramesProcessedClbk", pDrvIns->iInstance); 1170 1408 #endif 1171 1409 PDMDrvHlpSTAMRegisterF(pDrvIns, (void *)&pThis->Hub.Dev.UrbPool.cUrbsInPool, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "The number of URBs in the pool.", "/VUSB/%d/cUrbsInPool", pDrvIns->iInstance); -
trunk/src/VBox/Devices/USB/VUSBInternal.h
r59775 r59875 386 386 /** The HUB. 387 387 * @todo remove this? */ 388 VUSBHUB Hub;388 VUSBHUB Hub; 389 389 /** Address hash table. */ 390 PVUSBDEV apAddrHash[VUSB_ADDR_HASHSZ];390 PVUSBDEV apAddrHash[VUSB_ADDR_HASHSZ]; 391 391 /** The default address. */ 392 PVUSBDEV pDefaultAddress;392 PVUSBDEV pDefaultAddress; 393 393 394 394 /** Pointer to the driver instance. */ 395 PPDMDRVINS pDrvIns;395 PPDMDRVINS pDrvIns; 396 396 /** Pointer to the root hub port interface we're attached to. */ 397 PVUSBIROOTHUBPORT pIRhPort;397 PVUSBIROOTHUBPORT pIRhPort; 398 398 /** Connector interface exposed upwards. */ 399 VUSBIROOTHUBCONNECTOR IRhConnector; 399 VUSBIROOTHUBCONNECTOR IRhConnector; 400 401 /** Critical section protecting the device list. */ 402 RTCRITSECT CritSectDevices; 403 /** Chain of devices attached to this hub. */ 404 PVUSBDEV pDevices; 400 405 401 406 #if HC_ARCH_BITS == 32 402 uint32_t Alignment0; 403 #endif 404 405 /** Critical section protecting the device list. */ 406 RTCRITSECT CritSectDevices; 407 /** Chain of devices attached to this hub. */ 408 PVUSBDEV pDevices; 407 uint32_t Alignment0; 408 #endif 409 410 /** Availability Bitmap. */ 411 VUSBPORTBITMAP Bitmap; 412 413 /** Sniffer instance for the root hub. */ 414 VUSBSNIFFER hSniffer; 415 /** Version of the attached Host Controller. */ 416 uint32_t fHcVersions; 417 /** Size of the HCI specific data for each URB. */ 418 size_t cbHci; 419 /** Size of the HCI specific TD. */ 420 size_t cbHciTd; 421 422 /** The periodic frame processing thread. */ 423 R3PTRTYPE(PPDMTHREAD) hThreadPeriodFrame; 424 /** Event semaphore to interact with the periodic frame processing thread. */ 425 R3PTRTYPE(RTSEMEVENTMULTI) hSemEventPeriodFrame; 426 /** Event semaphore to release the thread waiting for the periodic frame processing thread to stop. */ 427 R3PTRTYPE(RTSEMEVENTMULTI) hSemEventPeriodFrameStopped; 428 /** Current default frame rate for periodic frame processing thread. */ 429 volatile uint32_t uFrameRateDefault; 430 /** Current frame rate (can be lower than the default frame rate if there is no activity). */ 431 uint32_t uFrameRate; 432 /** How long to wait until the next frame. */ 433 uint64_t nsWait; 434 /** Timestamp when the last frame was processed. */ 435 uint64_t tsFrameProcessed; 436 /** Number of USB work cycles with no transfers. */ 437 uint32_t cIdleCycles; 438 439 /** Flag whether a frame is currently being processed. */ 440 volatile bool fFrameProcessing; 409 441 410 442 #if HC_ARCH_BITS == 32 411 uint32_t Alignment1; 412 #endif 413 414 /** Availability Bitmap. */ 415 VUSBPORTBITMAP Bitmap; 416 417 /** Sniffer instance for the root hub. */ 418 VUSBSNIFFER hSniffer; 419 /** Version of the attached Host Controller. */ 420 uint32_t fHcVersions; 421 /** Size of the HCI specific data for each URB. */ 422 size_t cbHci; 423 /** Size of the HCI specific TD. */ 424 size_t cbHciTd; 443 uint32_t Alignment1; 444 #endif 445 425 446 #ifdef LOG_ENABLED 426 447 /** A serial number for URBs submitted on the roothub instance. 427 448 * Only logging builds. */ 428 uint32_t iSerial;449 uint32_t iSerial; 429 450 /** Alignment */ 430 uint32_t Alignment2;451 uint32_t Alignment2; 431 452 #endif 432 453 #ifdef VBOX_WITH_STATISTICS … … 454 475 STAMPROFILE StatReapAsyncUrbs; 455 476 STAMPROFILE StatSubmitUrb; 477 STAMCOUNTER StatFramesProcessedClbk; 478 STAMCOUNTER StatFramesProcessedThread; 456 479 #endif 457 480 } VUSBROOTHUB; … … 501 524 DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode); 502 525 526 DECLHIDDEN(uint64_t) vusbRhR3ProcessFrame(PVUSBROOTHUB pThis, bool fCallback); 527 503 528 int vusbUrbQueueAsyncRh(PVUSBURB pUrb); 504 529 -
trunk/src/VBox/Devices/USB/VUSBUrb.cpp
r59796 r59875 376 376 pUrb->pVUsb->pfnFree(pUrb); 377 377 } 378 379 vusbRhR3ProcessFrame(pRh, true /* fCallback */); 378 380 } 379 381 -
trunk/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
r59540 r59875 1051 1051 GEN_CHECK_OFF(OHCI, StatTimer); 1052 1052 # endif 1053 GEN_CHECK_OFF(OHCI, hThreadFrame);1054 GEN_CHECK_OFF(OHCI, hSemEventFrame);1055 GEN_CHECK_OFF(OHCI, fBusStarted);1056 1053 GEN_CHECK_OFF(OHCI, CsIrq); 1057 GEN_CHECK_OFF(OHCI, nsWait);1058 1054 GEN_CHECK_OFF(OHCI, CritSect); 1059 1055
Note:
See TracChangeset
for help on using the changeset viewer.

