TianoCore EDK2 master
Loading...
Searching...
No Matches
UsbHcMem.c
Go to the documentation of this file.
1
10#include "Uhci.h"
11
23 IN USBHC_MEM_POOL *Pool,
24 IN UINTN Pages
25 )
26{
27 USBHC_MEM_BLOCK *Block;
29 VOID *BufHost;
30 VOID *Mapping;
31 EFI_PHYSICAL_ADDRESS MappedAddr;
32 UINTN Bytes;
33 EFI_STATUS Status;
34
35 PciIo = Pool->PciIo;
36
37 Block = AllocateZeroPool (sizeof (USBHC_MEM_BLOCK));
38 if (Block == NULL) {
39 return NULL;
40 }
41
42 //
43 // each bit in the bit array represents USBHC_MEM_UNIT
44 // bytes of memory in the memory block.
45 //
46 ASSERT (USBHC_MEM_UNIT * 8 <= EFI_PAGE_SIZE);
47
48 Block->BufLen = EFI_PAGES_TO_SIZE (Pages);
49 Block->BitsLen = Block->BufLen / (USBHC_MEM_UNIT * 8);
50 Block->Bits = AllocateZeroPool (Block->BitsLen);
51
52 if (Block->Bits == NULL) {
53 gBS->FreePool (Block);
54 return NULL;
55 }
56
57 //
58 // Allocate the number of Pages of memory, then map it for
59 // bus master read and write.
60 //
61 Status = PciIo->AllocateBuffer (
62 PciIo,
65 Pages,
66 &BufHost,
67 0
68 );
69
70 if (EFI_ERROR (Status)) {
71 goto FREE_BITARRAY;
72 }
73
74 Bytes = EFI_PAGES_TO_SIZE (Pages);
75 Status = PciIo->Map (
76 PciIo,
78 BufHost,
79 &Bytes,
80 &MappedAddr,
81 &Mapping
82 );
83
84 if (EFI_ERROR (Status) || (Bytes != EFI_PAGES_TO_SIZE (Pages))) {
85 goto FREE_BUFFER;
86 }
87
88 //
89 // Check whether the data structure used by the host controller
90 // should be restricted into the same 4G
91 //
92 if (Pool->Check4G && (Pool->Which4G != USB_HC_HIGH_32BIT (MappedAddr))) {
93 PciIo->Unmap (PciIo, Mapping);
94 goto FREE_BUFFER;
95 }
96
97 Block->BufHost = BufHost;
98 Block->Buf = (UINT8 *)((UINTN)MappedAddr);
99 Block->Mapping = Mapping;
100
101 return Block;
102
103FREE_BUFFER:
104 PciIo->FreeBuffer (PciIo, Pages, BufHost);
105
106FREE_BITARRAY:
107 gBS->FreePool (Block->Bits);
108 gBS->FreePool (Block);
109 return NULL;
110}
111
119VOID
121 IN USBHC_MEM_POOL *Pool,
122 IN USBHC_MEM_BLOCK *Block
123 )
124{
125 EFI_PCI_IO_PROTOCOL *PciIo;
126
127 ASSERT ((Pool != NULL) && (Block != NULL));
128
129 PciIo = Pool->PciIo;
130
131 //
132 // Unmap the common buffer then free the structures
133 //
134 PciIo->Unmap (PciIo, Block->Mapping);
135 PciIo->FreeBuffer (PciIo, EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost);
136
137 gBS->FreePool (Block->Bits);
138 gBS->FreePool (Block);
139}
140
151VOID *
153 IN USBHC_MEM_BLOCK *Block,
154 IN UINTN Units
155 )
156{
157 UINTN Byte;
158 UINT8 Bit;
159 UINTN StartByte;
160 UINT8 StartBit;
161 UINTN Available;
162 UINTN Count;
163
164 ASSERT ((Block != 0) && (Units != 0));
165
166 StartByte = 0;
167 StartBit = 0;
168 Available = 0;
169
170 for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {
171 //
172 // If current bit is zero, the corresponding memory unit is
173 // available, otherwise we need to restart our searching.
174 // Available counts the consective number of zero bit.
175 //
176 if (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit)) {
177 Available++;
178
179 if (Available >= Units) {
180 break;
181 }
182
183 NEXT_BIT (Byte, Bit);
184 } else {
185 NEXT_BIT (Byte, Bit);
186
187 Available = 0;
188 StartByte = Byte;
189 StartBit = Bit;
190 }
191 }
192
193 if (Available < Units) {
194 return NULL;
195 }
196
197 //
198 // Mark the memory as allocated
199 //
200 Byte = StartByte;
201 Bit = StartBit;
202
203 for (Count = 0; Count < Units; Count++) {
204 ASSERT (!USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
205
206 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] | (UINT8)USB_HC_BIT (Bit));
207 NEXT_BIT (Byte, Bit);
208 }
209
210 return Block->BufHost + (StartByte * 8 + StartBit) * USBHC_MEM_UNIT;
211}
212
224 IN USBHC_MEM_POOL *Pool,
225 IN VOID *Mem,
226 IN UINTN Size
227 )
228{
229 USBHC_MEM_BLOCK *Head;
230 USBHC_MEM_BLOCK *Block;
231 UINTN AllocSize;
232 EFI_PHYSICAL_ADDRESS PhyAddr;
233 UINTN Offset;
234
235 Head = Pool->Head;
236 AllocSize = USBHC_MEM_ROUND (Size);
237
238 if (Mem == NULL) {
239 return 0;
240 }
241
242 for (Block = Head; Block != NULL; Block = Block->Next) {
243 //
244 // scan the memory block list for the memory block that
245 // completely contains the allocated memory.
246 //
247 if ((Block->BufHost <= (UINT8 *)Mem) && (((UINT8 *)Mem + AllocSize) <= (Block->BufHost + Block->BufLen))) {
248 break;
249 }
250 }
251
252 ASSERT ((Block != NULL));
253
254 if (Block == NULL) {
255 return 0;
256 }
257
258 //
259 // calculate the pci memory address for host memory address.
260 //
261 Offset = (UINT8 *)Mem - Block->BufHost;
262 PhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)(Block->Buf + Offset);
263 return PhyAddr;
264}
265
273VOID
275 IN USBHC_MEM_BLOCK *Head,
276 IN USBHC_MEM_BLOCK *Block
277 )
278{
279 ASSERT ((Head != NULL) && (Block != NULL));
280 Block->Next = Head->Next;
281 Head->Next = Block;
282}
283
293BOOLEAN
295 IN USBHC_MEM_BLOCK *Block
296 )
297{
298 UINTN Index;
299
300 for (Index = 0; Index < Block->BitsLen; Index++) {
301 if (Block->Bits[Index] != 0) {
302 return FALSE;
303 }
304 }
305
306 return TRUE;
307}
308
316VOID
318 IN USBHC_MEM_BLOCK *Head,
319 IN USBHC_MEM_BLOCK *BlockToUnlink
320 )
321{
322 USBHC_MEM_BLOCK *Block;
323
324 ASSERT ((Head != NULL) && (BlockToUnlink != NULL));
325
326 for (Block = Head; Block != NULL; Block = Block->Next) {
327 if (Block->Next == BlockToUnlink) {
328 Block->Next = BlockToUnlink->Next;
329 BlockToUnlink->Next = NULL;
330 break;
331 }
332 }
333}
334
349 IN EFI_PCI_IO_PROTOCOL *PciIo,
350 IN BOOLEAN Check4G,
351 IN UINT32 Which4G
352 )
353{
354 USBHC_MEM_POOL *Pool;
355
356 Pool = AllocatePool (sizeof (USBHC_MEM_POOL));
357
358 if (Pool == NULL) {
359 return Pool;
360 }
361
362 Pool->PciIo = PciIo;
363 Pool->Check4G = Check4G;
364 Pool->Which4G = Which4G;
365 Pool->Head = UsbHcAllocMemBlock (Pool, USBHC_MEM_DEFAULT_PAGES);
366
367 if (Pool->Head == NULL) {
368 gBS->FreePool (Pool);
369 Pool = NULL;
370 }
371
372 return Pool;
373}
374
386 IN USBHC_MEM_POOL *Pool
387 )
388{
389 USBHC_MEM_BLOCK *Block;
390
391 ASSERT (Pool->Head != NULL);
392
393 //
394 // Unlink all the memory blocks from the pool, then free them.
395 // UsbHcUnlinkMemBlock can't be used to unlink and free the
396 // first block.
397 //
398 for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {
399 UsbHcUnlinkMemBlock (Pool->Head, Block);
400 UsbHcFreeMemBlock (Pool, Block);
401 }
402
403 UsbHcFreeMemBlock (Pool, Pool->Head);
404 gBS->FreePool (Pool);
405 return EFI_SUCCESS;
406}
407
418VOID *
420 IN USBHC_MEM_POOL *Pool,
421 IN UINTN Size
422 )
423{
424 USBHC_MEM_BLOCK *Head;
425 USBHC_MEM_BLOCK *Block;
426 USBHC_MEM_BLOCK *NewBlock;
427 VOID *Mem;
428 UINTN AllocSize;
429 UINTN Pages;
430
431 Mem = NULL;
432 AllocSize = USBHC_MEM_ROUND (Size);
433 Head = Pool->Head;
434 ASSERT (Head != NULL);
435
436 //
437 // First check whether current memory blocks can satisfy the allocation.
438 //
439 for (Block = Head; Block != NULL; Block = Block->Next) {
440 Mem = UsbHcAllocMemFromBlock (Block, AllocSize / USBHC_MEM_UNIT);
441
442 if (Mem != NULL) {
443 ZeroMem (Mem, Size);
444 break;
445 }
446 }
447
448 if (Mem != NULL) {
449 return Mem;
450 }
451
452 //
453 // Create a new memory block if there is not enough memory
454 // in the pool. If the allocation size is larger than the
455 // default page number, just allocate a large enough memory
456 // block. Otherwise allocate default pages.
457 //
458 if (AllocSize > EFI_PAGES_TO_SIZE (USBHC_MEM_DEFAULT_PAGES)) {
459 Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;
460 } else {
461 Pages = USBHC_MEM_DEFAULT_PAGES;
462 }
463
464 NewBlock = UsbHcAllocMemBlock (Pool, Pages);
465
466 if (NewBlock == NULL) {
467 DEBUG ((DEBUG_INFO, "UsbHcAllocateMem: failed to allocate block\n"));
468 return NULL;
469 }
470
471 //
472 // Add the new memory block to the pool, then allocate memory from it
473 //
474 UsbHcInsertMemBlockToPool (Head, NewBlock);
475 Mem = UsbHcAllocMemFromBlock (NewBlock, AllocSize / USBHC_MEM_UNIT);
476
477 if (Mem != NULL) {
478 ZeroMem (Mem, Size);
479 }
480
481 return Mem;
482}
483
492VOID
494 IN USBHC_MEM_POOL *Pool,
495 IN VOID *Mem,
496 IN UINTN Size
497 )
498{
499 USBHC_MEM_BLOCK *Head;
500 USBHC_MEM_BLOCK *Block;
501 UINT8 *ToFree;
502 UINTN AllocSize;
503 UINTN Byte;
504 UINTN Bit;
505 UINTN Count;
506
507 Head = Pool->Head;
508 AllocSize = USBHC_MEM_ROUND (Size);
509 ToFree = (UINT8 *)Mem;
510
511 for (Block = Head; Block != NULL; Block = Block->Next) {
512 //
513 // scan the memory block list for the memory block that
514 // completely contains the memory to free.
515 //
516 if ((Block->BufHost <= ToFree) && ((ToFree + AllocSize) <= (Block->BufHost + Block->BufLen))) {
517 //
518 // compute the start byte and bit in the bit array
519 //
520 Byte = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) / 8;
521 Bit = ((ToFree - Block->BufHost) / USBHC_MEM_UNIT) % 8;
522
523 //
524 // reset associated bits in bit array
525 //
526 for (Count = 0; Count < (AllocSize / USBHC_MEM_UNIT); Count++) {
527 ASSERT (USB_HC_BIT_IS_SET (Block->Bits[Byte], Bit));
528
529 Block->Bits[Byte] = (UINT8)(Block->Bits[Byte] ^ USB_HC_BIT (Bit));
530 NEXT_BIT (Byte, Bit);
531 }
532
533 break;
534 }
535 }
536
537 //
538 // If Block == NULL, it means that the current memory isn't
539 // in the host controller's pool. This is critical because
540 // the caller has passed in a wrong memory point
541 //
542 ASSERT (Block != NULL);
543
544 if (Block == NULL) {
545 return;
546 }
547
548 //
549 // Release the current memory block if it is empty and not the head
550 //
551 if ((Block != Head) && UsbHcIsMemBlockEmpty (Block)) {
552 UsbHcUnlinkMemBlock (Head, Block);
553 UsbHcFreeMemBlock (Pool, Block);
554 }
555
556 return;
557}
UINT64 UINTN
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_PHYSICAL_ADDRESS UsbHcGetPciAddressForHostMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:223
VOID * UsbHcAllocMemFromBlock(IN USBHC_MEM_BLOCK *Block, IN UINTN Units)
Definition: UsbHcMem.c:152
EFI_STATUS UsbHcFreeMemPool(IN USBHC_MEM_POOL *Pool)
Definition: UsbHcMem.c:385
VOID UsbHcFreeMemBlock(IN USBHC_MEM_POOL *Pool, IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:120
BOOLEAN UsbHcIsMemBlockEmpty(IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:294
VOID UsbHcFreeMem(IN USBHC_MEM_POOL *Pool, IN VOID *Mem, IN UINTN Size)
Definition: UsbHcMem.c:493
VOID * UsbHcAllocateMem(IN USBHC_MEM_POOL *Pool, IN UINTN Size)
Definition: UsbHcMem.c:419
USBHC_MEM_BLOCK * UsbHcAllocMemBlock(IN USBHC_MEM_POOL *Pool, IN UINTN Pages)
Definition: UsbHcMem.c:22
VOID UsbHcUnlinkMemBlock(IN USBHC_MEM_BLOCK *Head, IN USBHC_MEM_BLOCK *BlockToUnlink)
Definition: UsbHcMem.c:317
VOID UsbHcInsertMemBlockToPool(IN USBHC_MEM_BLOCK *Head, IN USBHC_MEM_BLOCK *Block)
Definition: UsbHcMem.c:274
USBHC_MEM_POOL * UsbHcInitMemPool(IN EFI_PCI_IO_PROTOCOL *PciIo, IN BOOLEAN Check4G, IN UINT32 Which4G)
Definition: UsbHcMem.c:348
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
@ EfiPciIoOperationBusMasterCommonBuffer
Definition: PciIo.h:90
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ EfiBootServicesData
@ AllocateAnyPages
Definition: UefiSpec.h:33