VirtualBox

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

Last change on this file since 91968 was 85124, checked in by vboxsync, 4 years ago

*: Use DECL_HIDDEN_DATA for data, DECLHIDDEN will soon be exclusively for functions. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.3 KB
Line 
1/* $Id: VUSBUrbPool.cpp 85124 2020-07-08 21:13:30Z vboxsync $ */
2/** @file
3 * Virtual USB - URB pool.
4 */
5
6/*
7 * Copyright (C) 2016-2020 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
73DECLHIDDEN(int) vusbUrbPoolInit(PVUSBURBPOOL pUrbPool)
74{
75 int rc = RTCritSectInit(&pUrbPool->CritSectPool);
76 if (RT_SUCCESS(rc))
77 {
78 pUrbPool->cUrbsInPool = 0;
79 for (unsigned i = 0; i < RT_ELEMENTS(pUrbPool->aLstFreeUrbs); i++)
80 RTListInit(&pUrbPool->aLstFreeUrbs[i]);
81 }
82
83 return rc;
84}
85
86
87DECLHIDDEN(void) vusbUrbPoolDestroy(PVUSBURBPOOL pUrbPool)
88{
89 RTCritSectEnter(&pUrbPool->CritSectPool);
90 for (unsigned i = 0; i < RT_ELEMENTS(pUrbPool->aLstFreeUrbs); i++)
91 {
92 PVUSBURBHDR pHdr, pHdrNext;
93 RTListForEachSafe(&pUrbPool->aLstFreeUrbs[i], pHdr, pHdrNext, VUSBURBHDR, NdFree)
94 {
95 RTListNodeRemove(&pHdr->NdFree);
96
97 pHdr->cbAllocated = 0;
98 pHdr->Urb.u32Magic = 0;
99 pHdr->Urb.enmState = VUSBURBSTATE_INVALID;
100 RTMemFree(pHdr);
101 }
102 }
103 RTCritSectLeave(&pUrbPool->CritSectPool);
104 RTCritSectDelete(&pUrbPool->CritSectPool);
105}
106
107
108DECLHIDDEN(PVUSBURB) vusbUrbPoolAlloc(PVUSBURBPOOL pUrbPool, VUSBXFERTYPE enmType,
109 VUSBDIRECTION enmDir, size_t cbData, size_t cbHci,
110 size_t cbHciTd, unsigned cTds)
111{
112 Assert((uint32_t)cbData == cbData);
113 Assert((uint32_t)cbHci == cbHci);
114
115 /*
116 * Reuse or allocate a new URB.
117 */
118 /** @todo The allocations should be done by the device, at least as an option, since the devices
119 * frequently wish to associate their own stuff with the in-flight URB or need special buffering
120 * (isochronous on Darwin for instance). */
121 /* Get the required amount of additional memory to allocate the whole state. */
122 size_t cbMem = cbData + sizeof(VUSBURBVUSBINT) + cbHci + cTds * cbHciTd;
123
124 AssertReturn((size_t)enmType < RT_ELEMENTS(pUrbPool->aLstFreeUrbs), NULL);
125
126 RTCritSectEnter(&pUrbPool->CritSectPool);
127 PVUSBURBHDR pHdr = NULL;
128 PVUSBURBHDR pIt, pItNext;
129 RTListForEachSafe(&pUrbPool->aLstFreeUrbs[enmType], pIt, pItNext, VUSBURBHDR, NdFree)
130 {
131 if (pIt->cbAllocated >= cbMem)
132 {
133 RTListNodeRemove(&pIt->NdFree);
134 Assert(pIt->Urb.u32Magic == VUSBURB_MAGIC);
135 Assert(pIt->Urb.enmState == VUSBURBSTATE_FREE);
136 /*
137 * If the allocation is far too big we increase the age counter too
138 * so we don't waste memory for a lot of small transfers
139 */
140 if (pIt->cbAllocated >= 2 * cbMem)
141 pIt->cAge++;
142 else
143 pIt->cAge = 0;
144 pHdr = pIt;
145 break;
146 }
147 else
148 {
149 /* Increase age and free if it reached a threshold. */
150 pIt->cAge++;
151 if (pIt->cAge == VUSBURB_AGE_MAX)
152 {
153 RTListNodeRemove(&pIt->NdFree);
154 ASMAtomicDecU32(&pUrbPool->cUrbsInPool);
155 RTMemFree(pIt);
156 }
157 }
158 }
159
160 if (!pHdr)
161 {
162 /* allocate a new one. */
163 size_t cbDataAllocated = cbMem <= _4K ? RT_ALIGN_32(cbMem, _1K)
164 : cbMem <= _32K ? RT_ALIGN_32(cbMem, _4K)
165 : RT_ALIGN_32(cbMem, 16*_1K);
166
167 pHdr = (PVUSBURBHDR)RTMemAllocZ(RT_UOFFSETOF_DYN(VUSBURBHDR, Urb.abData[cbDataAllocated]));
168 if (RT_UNLIKELY(!pHdr))
169 {
170 RTCritSectLeave(&pUrbPool->CritSectPool);
171 AssertLogRelFailedReturn(NULL);
172 }
173
174 pHdr->cbAllocated = cbDataAllocated;
175 pHdr->cAge = 0;
176 ASMAtomicIncU32(&pUrbPool->cUrbsInPool);
177 }
178 RTCritSectLeave(&pUrbPool->CritSectPool);
179
180 Assert(pHdr->cbAllocated >= cbMem);
181
182 /*
183 * (Re)init the URB
184 */
185 uint32_t offAlloc = (uint32_t)cbData;
186 PVUSBURB pUrb = &pHdr->Urb;
187 pUrb->u32Magic = VUSBURB_MAGIC;
188 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
189 pUrb->fCompleting = false;
190 pUrb->pszDesc = NULL;
191 pUrb->pVUsb = (PVUSBURBVUSB)&pUrb->abData[offAlloc];
192 offAlloc += sizeof(VUSBURBVUSBINT);
193 pUrb->pVUsb->pUrb = pUrb;
194 pUrb->pVUsb->pvFreeCtx = NULL;
195 pUrb->pVUsb->pfnFree = NULL;
196 pUrb->pVUsb->pCtrlUrb = NULL;
197 pUrb->pVUsb->u64SubmitTS = 0;
198 pUrb->Dev.pvPrivate = NULL;
199 pUrb->Dev.pNext = NULL;
200 pUrb->EndPt = UINT8_MAX;
201 pUrb->enmType = enmType;
202 pUrb->enmDir = enmDir;
203 pUrb->fShortNotOk = false;
204 pUrb->enmStatus = VUSBSTATUS_INVALID;
205 pUrb->cbData = (uint32_t)cbData;
206 pUrb->pHci = cbHci ? (PVUSBURBHCI)&pUrb->abData[offAlloc] : NULL;
207 offAlloc += (uint32_t)cbHci;
208 pUrb->paTds = (cbHciTd && cTds) ? (PVUSBURBHCITD)&pUrb->abData[offAlloc] : NULL;
209
210 return pUrb;
211}
212
213
214DECLHIDDEN(void) vusbUrbPoolFree(PVUSBURBPOOL pUrbPool, PVUSBURB pUrb)
215{
216 PVUSBURBHDR pHdr = VUSBURBPOOL_URB_2_URBHDR(pUrb);
217
218 /* URBs which aged too much because they are too big are freed. */
219 if (pHdr->cAge == VUSBURB_AGE_MAX)
220 {
221 ASMAtomicDecU32(&pUrbPool->cUrbsInPool);
222 RTMemFree(pHdr);
223 }
224 else
225 {
226 /* Put it into the list of free URBs. */
227 VUSBXFERTYPE enmType = pUrb->enmType;
228 AssertReturnVoid((size_t)enmType < RT_ELEMENTS(pUrbPool->aLstFreeUrbs));
229 RTCritSectEnter(&pUrbPool->CritSectPool);
230 pUrb->enmState = VUSBURBSTATE_FREE;
231 RTListAppend(&pUrbPool->aLstFreeUrbs[enmType], &pHdr->NdFree);
232 RTCritSectLeave(&pUrbPool->CritSectPool);
233 }
234}
235
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