VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/VUSBUrbPool.cpp@ 78097

Last change on this file since 78097 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/* $Id: VUSBUrbPool.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * Virtual USB - URB pool.
4 */
5
6/*
7 * Copyright (C) 2016-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_VUSB
23#include <VBox/log.h>
24#include <iprt/errcore.h>
25#include <iprt/mem.h>
26#include <iprt/critsect.h>
27
28#include "VUSBInternal.h"
29
30
31/*********************************************************************************************************************************
32* Defined Constants And Macros *
33*********************************************************************************************************************************/
34
35/** Maximum age for one URB. */
36#define VUSBURB_AGE_MAX 10
37
38/** Convert from an URB to the URB header. */
39#define VUSBURBPOOL_URB_2_URBHDR(a_pUrb) RT_FROM_MEMBER(a_pUrb, VUSBURBHDR, Urb);
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45
46/**
47 * URB header not visible to the caller allocating an URB
48 * and only for internal tracking.
49 */
50typedef struct VUSBURBHDR
51{
52 /** List node for keeping the URB in the free list. */
53 RTLISTNODE NdFree;
54 /** Size of the data allocated for the URB (Only the variable part including the
55 * HCI and TDs). */
56 size_t cbAllocated;
57 /** Age of the URB waiting on the list, if it is waiting for too long without being used
58 * again it will be freed. */
59 uint32_t cAge;
60#if HC_ARCH_BITS == 64
61 uint32_t u32Alignment0;
62#endif
63 /** The embedded URB. */
64 VUSBURB Urb;
65} VUSBURBHDR;
66/** Pointer to a URB header. */
67typedef VUSBURBHDR *PVUSBURBHDR;
68
69AssertCompileSizeAlignment(VUSBURBHDR, 8);
70
71
72/*********************************************************************************************************************************
73* Static Variables *
74*********************************************************************************************************************************/
75
76
77/*********************************************************************************************************************************
78* Internal Functions *
79*********************************************************************************************************************************/
80
81DECLHIDDEN(int) vusbUrbPoolInit(PVUSBURBPOOL pUrbPool)
82{
83 int rc = RTCritSectInit(&pUrbPool->CritSectPool);
84 if (RT_SUCCESS(rc))
85 {
86 pUrbPool->cUrbsInPool = 0;
87 for (unsigned i = 0; i < RT_ELEMENTS(pUrbPool->aLstFreeUrbs); i++)
88 RTListInit(&pUrbPool->aLstFreeUrbs[i]);
89 }
90
91 return rc;
92}
93
94
95DECLHIDDEN(void) vusbUrbPoolDestroy(PVUSBURBPOOL pUrbPool)
96{
97 RTCritSectEnter(&pUrbPool->CritSectPool);
98 for (unsigned i = 0; i < RT_ELEMENTS(pUrbPool->aLstFreeUrbs); i++)
99 {
100 PVUSBURBHDR pHdr, pHdrNext;
101 RTListForEachSafe(&pUrbPool->aLstFreeUrbs[i], pHdr, pHdrNext, VUSBURBHDR, NdFree)
102 {
103 RTListNodeRemove(&pHdr->NdFree);
104
105 pHdr->cbAllocated = 0;
106 pHdr->Urb.u32Magic = 0;
107 pHdr->Urb.enmState = VUSBURBSTATE_INVALID;
108 RTMemFree(pHdr);
109 }
110 }
111 RTCritSectLeave(&pUrbPool->CritSectPool);
112 RTCritSectDelete(&pUrbPool->CritSectPool);
113}
114
115
116DECLHIDDEN(PVUSBURB) vusbUrbPoolAlloc(PVUSBURBPOOL pUrbPool, VUSBXFERTYPE enmType,
117 VUSBDIRECTION enmDir, size_t cbData, size_t cbHci,
118 size_t cbHciTd, unsigned cTds)
119{
120 Assert((uint32_t)cbData == cbData);
121 Assert((uint32_t)cbHci == cbHci);
122
123 /*
124 * Reuse or allocate a new URB.
125 */
126 /** @todo The allocations should be done by the device, at least as an option, since the devices
127 * frequently wish to associate their own stuff with the in-flight URB or need special buffering
128 * (isochronous on Darwin for instance). */
129 /* Get the required amount of additional memory to allocate the whole state. */
130 size_t cbMem = cbData + sizeof(VUSBURBVUSBINT) + cbHci + cTds * cbHciTd;
131
132 AssertReturn((size_t)enmType < RT_ELEMENTS(pUrbPool->aLstFreeUrbs), NULL);
133
134 RTCritSectEnter(&pUrbPool->CritSectPool);
135 PVUSBURBHDR pHdr = NULL;
136 PVUSBURBHDR pIt, pItNext;
137 RTListForEachSafe(&pUrbPool->aLstFreeUrbs[enmType], pIt, pItNext, VUSBURBHDR, NdFree)
138 {
139 if (pIt->cbAllocated >= cbMem)
140 {
141 RTListNodeRemove(&pIt->NdFree);
142 Assert(pIt->Urb.u32Magic == VUSBURB_MAGIC);
143 Assert(pIt->Urb.enmState == VUSBURBSTATE_FREE);
144 /*
145 * If the allocation is far too big we increase the age counter too
146 * so we don't waste memory for a lot of small transfers
147 */
148 if (pIt->cbAllocated >= 2 * cbMem)
149 pIt->cAge++;
150 else
151 pIt->cAge = 0;
152 pHdr = pIt;
153 break;
154 }
155 else
156 {
157 /* Increase age and free if it reached a threshold. */
158 pIt->cAge++;
159 if (pIt->cAge == VUSBURB_AGE_MAX)
160 {
161 RTListNodeRemove(&pIt->NdFree);
162 ASMAtomicDecU32(&pUrbPool->cUrbsInPool);
163 RTMemFree(pIt);
164 }
165 }
166 }
167
168 if (!pHdr)
169 {
170 /* allocate a new one. */
171 size_t cbDataAllocated = cbMem <= _4K ? RT_ALIGN_32(cbMem, _1K)
172 : cbMem <= _32K ? RT_ALIGN_32(cbMem, _4K)
173 : RT_ALIGN_32(cbMem, 16*_1K);
174
175 pHdr = (PVUSBURBHDR)RTMemAllocZ(RT_UOFFSETOF_DYN(VUSBURBHDR, Urb.abData[cbDataAllocated]));
176 if (RT_UNLIKELY(!pHdr))
177 {
178 RTCritSectLeave(&pUrbPool->CritSectPool);
179 AssertLogRelFailedReturn(NULL);
180 }
181
182 pHdr->cbAllocated = cbDataAllocated;
183 pHdr->cAge = 0;
184 ASMAtomicIncU32(&pUrbPool->cUrbsInPool);
185 }
186 RTCritSectLeave(&pUrbPool->CritSectPool);
187
188 Assert(pHdr->cbAllocated >= cbMem);
189
190 /*
191 * (Re)init the URB
192 */
193 uint32_t offAlloc = (uint32_t)cbData;
194 PVUSBURB pUrb = &pHdr->Urb;
195 pUrb->u32Magic = VUSBURB_MAGIC;
196 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
197 pUrb->fCompleting = false;
198 pUrb->pszDesc = NULL;
199 pUrb->pVUsb = (PVUSBURBVUSB)&pUrb->abData[offAlloc];
200 offAlloc += sizeof(VUSBURBVUSBINT);
201 pUrb->pVUsb->pUrb = pUrb;
202 pUrb->pVUsb->pvFreeCtx = NULL;
203 pUrb->pVUsb->pfnFree = NULL;
204 pUrb->pVUsb->pCtrlUrb = NULL;
205 pUrb->pVUsb->u64SubmitTS = 0;
206 pUrb->Dev.pvPrivate = NULL;
207 pUrb->Dev.pNext = NULL;
208 pUrb->EndPt = UINT8_MAX;
209 pUrb->enmType = enmType;
210 pUrb->enmDir = enmDir;
211 pUrb->fShortNotOk = false;
212 pUrb->enmStatus = VUSBSTATUS_INVALID;
213 pUrb->cbData = (uint32_t)cbData;
214 pUrb->pHci = cbHci ? (PVUSBURBHCI)&pUrb->abData[offAlloc] : NULL;
215 offAlloc += (uint32_t)cbHci;
216 pUrb->paTds = (cbHciTd && cTds) ? (PVUSBURBHCITD)&pUrb->abData[offAlloc] : NULL;
217
218 return pUrb;
219}
220
221
222DECLHIDDEN(void) vusbUrbPoolFree(PVUSBURBPOOL pUrbPool, PVUSBURB pUrb)
223{
224 PVUSBURBHDR pHdr = VUSBURBPOOL_URB_2_URBHDR(pUrb);
225
226 /* URBs which aged too much because they are too big are freed. */
227 if (pHdr->cAge == VUSBURB_AGE_MAX)
228 {
229 ASMAtomicDecU32(&pUrbPool->cUrbsInPool);
230 RTMemFree(pHdr);
231 }
232 else
233 {
234 /* Put it into the list of free URBs. */
235 VUSBXFERTYPE enmType = pUrb->enmType;
236 AssertReturnVoid((size_t)enmType < RT_ELEMENTS(pUrbPool->aLstFreeUrbs));
237 RTCritSectEnter(&pUrbPool->CritSectPool);
238 pUrb->enmState = VUSBURBSTATE_FREE;
239 RTListAppend(&pUrbPool->aLstFreeUrbs[enmType], &pHdr->NdFree);
240 RTCritSectLeave(&pUrbPool->CritSectPool);
241 }
242}
243
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette