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