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