VirtualBox

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

Last change on this file since 97441 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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