]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/UsbHcMem.c
QuarkSocPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Usb / Ohci / Pei / UsbHcMem.c
1 /** @file
2 Routine procedures for memory allocate/free.
3
4 Copyright (c) 2013-2015 Intel Corporation.
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10
11 #include "OhcPeim.h"
12
13
14 /**
15 Allocate a block of memory to be used by the buffer pool.
16
17 Use Redirect memory services to allocate memmory so that USB DMA transfers do
18 not cause IMR violations on Quark.
19
20 @param Pool The buffer pool to allocate memory for.
21 @param Pages How many pages to allocate.
22
23 @return The allocated memory block or NULL if failed.
24
25 **/
26 USBHC_MEM_BLOCK *
27 UsbHcAllocMemBlock (
28 IN USBHC_MEM_POOL *Pool,
29 IN UINTN Pages
30 )
31 {
32 USBHC_MEM_BLOCK *Block;
33 VOID *BufHost;
34 VOID *Mapping;
35 EFI_PHYSICAL_ADDRESS MappedAddr;
36 EFI_STATUS Status;
37 UINTN PageNumber;
38 EFI_PHYSICAL_ADDRESS TempPtr;
39
40 Mapping = NULL;
41 PageNumber = sizeof(USBHC_MEM_BLOCK)/PAGESIZE +1;
42 Status = PeiServicesAllocatePages (
43 EfiBootServicesCode,
44 PageNumber,
45 &TempPtr
46 );
47
48 if (EFI_ERROR (Status)) {
49 return NULL;
50 }
51 ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
52
53 //
54 // each bit in the bit array represents USBHC_MEM_UNIT
55 // bytes of memory in the memory block.
56 //
57 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
58
59 Block = (USBHC_MEM_BLOCK*)(UINTN)TempPtr;
60 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
61 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
62
63 PageNumber = (Block->BitsLen)/PAGESIZE +1;
64 Status = PeiServicesAllocatePages (
65 EfiBootServicesCode,
66 PageNumber,
67 &TempPtr
68 );
69 if (EFI_ERROR (Status)) {
70 return NULL;
71 }
72 ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
73
74 Block->Bits = (UINT8 *)(UINTN)TempPtr;
75
76 Status = PeiServicesAllocatePages (
77 EfiBootServicesCode,
78 Pages,
79 &TempPtr
80 );
81 ZeroMem ((VOID *)(UINTN)TempPtr, Pages*EFI_PAGE_SIZE);
82
83 BufHost = (VOID *)(UINTN)TempPtr;
84 MappedAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) BufHost;
85 //
86 // Check whether the data structure used by the host controller
87 // should be restricted into the same 4G
88 //
89 if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
90 return NULL;
91 }
92
93 Block->BufHost = BufHost;
94 Block->Buf = (UINT8 *) ((UINTN) MappedAddr);
95 Block->Mapping = Mapping;
96 Block->Next = NULL;
97
98 return Block;
99
100 }
101
102
103 /**
104 Free the memory block from the memory pool.
105
106 @param Pool The memory pool to free the block from.
107 @param Block The memory block to free.
108
109 **/
110 VOID
111 UsbHcFreeMemBlock (
112 IN USBHC_MEM_POOL *Pool,
113 IN USBHC_MEM_BLOCK *Block
114 )
115 {
116
117 ASSERT ((Pool != NULL) && (Block != NULL));
118 }
119
120
121 /**
122 Alloc some memory from the block.
123
124 @param Block The memory block to allocate memory from.
125 @param Units Number of memory units to allocate.
126
127 @return The pointer to the allocated memory. If couldn't allocate the needed memory,
128 the return value is NULL.
129
130 **/
131 VOID *
132 UsbHcAllocMemFromBlock (
133 IN USBHC_MEM_BLOCK *Block,
134 IN UINTN Units
135 )
136 {
137 UINTN Byte;
138 UINT8 Bit;
139 UINTN StartByte;
140 UINT8 StartBit;
141 UINTN Available;
142 UINTN Count;
143
144 ASSERT ((Block != 0) && (Units != 0));
145
146 StartByte = 0;
147 StartBit = 0;
148 Available = 0;
149
150 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
151 //
152 // If current bit is zero, the corresponding memory unit is
153 // available, otherwise we need to restart our searching.
154 // Available counts the consective number of zero bit.
155 //
156 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
157 Available++;
158
159 if (Available >= Units) {
160 break;
161 }
162
163 NEXT_BIT (Byte, Bit);
164
165 } else {
166 NEXT_BIT (Byte, Bit);
167
168 Available = 0;
169 StartByte = Byte;
170 StartBit = Bit;
171 }
172 }
173
174 if (Available < Units) {
175 return NULL;
176 }
177
178 //
179 // Mark the memory as allocated
180 //
181 Byte = StartByte;
182 Bit = StartBit;
183
184 for (Count = 0; Count < Units; Count++) {
185 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
186
187 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) USB_HC_BIT (Bit));
188 NEXT_BIT (Byte, Bit);
189 }
190
191 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
192 }
193
194 /**
195 Insert the memory block to the pool's list of the blocks.
196
197 @param Head The head of the memory pool's block list.
198 @param Block The memory block to insert.
199
200 **/
201 VOID
202 UsbHcInsertMemBlockToPool (
203 IN USBHC_MEM_BLOCK *Head,
204 IN USBHC_MEM_BLOCK *Block
205 )
206 {
207 ASSERT ((Head != NULL) && (Block != NULL));
208 Block->Next = Head->Next;
209 Head->Next = Block;
210 }
211
212
213 /**
214 Is the memory block empty?
215
216 @param Block The memory block to check.
217
218 @retval TRUE The memory block is empty.
219 @retval FALSE The memory block isn't empty.
220
221 **/
222 BOOLEAN
223 UsbHcIsMemBlockEmpty (
224 IN USBHC_MEM_BLOCK *Block
225 )
226 {
227 UINTN Index;
228
229 for (Index = 0; Index < Block->BitsLen; Index++) {
230 if (Block->Bits[Index] != 0) {
231 return FALSE;
232 }
233 }
234
235 return TRUE;
236 }
237
238
239 /**
240 Unlink the memory block from the pool's list.
241
242 @param Head The block list head of the memory's pool.
243 @param BlockToUnlink The memory block to unlink.
244
245 **/
246 VOID
247 UsbHcUnlinkMemBlock (
248 IN USBHC_MEM_BLOCK *Head,
249 IN USBHC_MEM_BLOCK *BlockToUnlink
250 )
251 {
252 USBHC_MEM_BLOCK *Block;
253
254 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
255
256 for (Block = Head; Block != NULL; Block = Block->Next) {
257 if (Block->Next == BlockToUnlink) {
258 Block->Next = BlockToUnlink->Next;
259 BlockToUnlink->Next = NULL;
260 break;
261 }
262 }
263 }
264
265
266 /**
267 Initialize the memory management pool for the host controller.
268
269 @param PciIo The PciIo that can be used to access the host controller.
270 @param Check4G Whether the host controller requires allocated memory
271 from one 4G address space.
272 @param Which4G The 4G memory area each memory allocated should be from.
273
274 @retval EFI_SUCCESS The memory pool is initialized.
275 @retval EFI_OUT_OF_RESOURCE Fail to init the memory pool.
276
277 **/
278 USBHC_MEM_POOL *
279 UsbHcInitMemPool (
280 IN BOOLEAN Check4G,
281 IN UINT32 Which4G
282 )
283 {
284 USBHC_MEM_POOL *Pool;
285 UINTN PageNumber;
286 EFI_STATUS Status;
287 EFI_PHYSICAL_ADDRESS TempPtr;
288
289 PageNumber = sizeof(USBHC_MEM_POOL)/PAGESIZE +1;
290 Status = PeiServicesAllocatePages (
291 EfiBootServicesCode,
292 PageNumber,
293 &TempPtr
294 );
295 if (EFI_ERROR (Status)) {
296 return NULL;
297 }
298 ZeroMem ((VOID *)(UINTN)TempPtr, PageNumber*EFI_PAGE_SIZE);
299
300 Pool = (USBHC_MEM_POOL *) ((UINTN) TempPtr);
301 Pool->Check4G = Check4G;
302 Pool->Which4G = Which4G;
303 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
304
305 if (Pool->Head == NULL) {
306 Pool = NULL;
307 }
308
309 return Pool;
310 }
311
312
313 /**
314 Release the memory management pool.
315
316 @param Pool The USB memory pool to free.
317
318 @retval EFI_SUCCESS The memory pool is freed.
319 @retval EFI_DEVICE_ERROR Failed to free the memory pool.
320
321 **/
322 EFI_STATUS
323 UsbHcFreeMemPool (
324 IN USBHC_MEM_POOL *Pool
325 )
326 {
327 USBHC_MEM_BLOCK *Block;
328
329 ASSERT (Pool->Head != NULL);
330
331 //
332 // Unlink all the memory blocks from the pool, then free them.
333 // UsbHcUnlinkMemBlock can't be used to unlink and free the
334 // first block.
335 //
336 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
337 UsbHcFreeMemBlock (Pool, Block);
338 }
339
340 UsbHcFreeMemBlock (Pool, Pool->Head);
341
342 return EFI_SUCCESS;
343 }
344
345
346 /**
347 Allocate some memory from the host controller's memory pool
348 which can be used to communicate with host controller.
349
350 @param Pool The host controller's memory pool.
351 @param Size Size of the memory to allocate.
352
353 @return The allocated memory or NULL.
354
355 **/
356 VOID *
357 UsbHcAllocateMem (
358 IN USBHC_MEM_POOL *Pool,
359 IN UINTN Size
360 )
361 {
362 USBHC_MEM_BLOCK *Head;
363 USBHC_MEM_BLOCK *Block;
364 USBHC_MEM_BLOCK *NewBlock;
365 VOID *Mem;
366 UINTN AllocSize;
367 UINTN Pages;
368
369 Mem = NULL;
370 AllocSize = USBHC_MEM_ROUND (Size);
371 Head = Pool->Head;
372 ASSERT (Head != NULL);
373
374 //
375 // First check whether current memory blocks can satisfy the allocation.
376 //
377 for (Block = Head; Block != NULL; Block = Block->Next) {
378 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
379
380 if (Mem != NULL) {
381 ZeroMem (Mem, Size);
382 break;
383 }
384 }
385
386 if (Mem != NULL) {
387 return Mem;
388 }
389
390 //
391 // Create a new memory block if there is not enough memory
392 // in the pool. If the allocation size is larger than the
393 // default page number, just allocate a large enough memory
394 // block. Otherwise allocate default pages.
395 //
396 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
397 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
398 } else {
399 Pages = USBHC_MEM_DEFAULT_PAGES;
400 }
401
402 NewBlock = UsbHcAllocMemBlock (Pool, Pages);
403
404 if (NewBlock == NULL) {
405 DEBUG ((EFI_D_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
406 return NULL;
407 }
408
409 //
410 // Add the new memory block to the pool, then allocate memory from it
411 //
412 UsbHcInsertMemBlockToPool (Head, NewBlock);
413 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
414
415 if (Mem != NULL) {
416 ZeroMem (Mem, Size);
417 }
418
419 return Mem;
420 }
421
422
423 /**
424 Free the allocated memory back to the memory pool.
425
426 @param Pool The memory pool of the host controller.
427 @param Mem The memory to free.
428 @param Size The size of the memory to free.
429
430 **/
431 VOID
432 UsbHcFreeMem (
433 IN USBHC_MEM_POOL *Pool,
434 IN VOID *Mem,
435 IN UINTN Size
436 )
437 {
438 USBHC_MEM_BLOCK *Head;
439 USBHC_MEM_BLOCK *Block;
440 UINT8 *ToFree;
441 UINTN AllocSize;
442 UINTN Byte;
443 UINTN Bit;
444 UINTN Count;
445
446 Head = Pool->Head;
447 AllocSize = USBHC_MEM_ROUND (Size);
448 ToFree = (UINT8 *) Mem;
449
450 for (Block = Head; Block != NULL; Block = Block->Next) {
451 //
452 // scan the memory block list for the memory block that
453 // completely contains the memory to free.
454 //
455 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
456 //
457 // compute the start byte and bit in the bit array
458 //
459 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
460 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
461
462 //
463 // reset associated bits in bit arry
464 //
465 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
466 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
467
468 Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ USB_HC_BIT (Bit));
469 NEXT_BIT (Byte, Bit);
470 }
471
472 break;
473 }
474 }
475
476 //
477 // If Block == NULL, it means that the current memory isn't
478 // in the host controller's pool. This is critical because
479 // the caller has passed in a wrong memory point
480 //
481 ASSERT (Block != NULL);
482
483 //
484 // Release the current memory block if it is empty and not the head
485 //
486 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
487 UsbHcFreeMemBlock (Pool, Block);
488 }
489
490 return ;
491 }