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