]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciMem.c
Some library instance's PCD is missing in FPD file for a module, it break single...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Ehci / Dxe / EhciMem.c
1 /*++
2
3 Copyright (c) 2006, 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 #include "Ehci.h"
23
24
25 EFI_STATUS
26 CreateMemoryBlock (
27 IN USB2_HC_DEV *HcDev,
28 OUT MEMORY_MANAGE_HEADER **MemoryHeader,
29 IN UINTN MemoryBlockSizeInPages
30 )
31 /*++
32
33 Routine Description:
34
35 Use PciIo->AllocateBuffer to allocate common buffer for the memory block,
36 and use PciIo->Map to map the common buffer for Bus Master Read/Write.
37
38 Arguments:
39
40 HcDev - USB2_HC_DEV
41 MemoryHeader - MEMORY_MANAGE_HEADER to output
42 MemoryBlockSizeInPages - MemoryBlockSizeInPages
43
44 Returns:
45
46 EFI_SUCCESS Success
47 EFI_OUT_OF_RESOURCES Fail for no resources
48 EFI_UNSUPPORTED Unsupported currently
49
50 --*/
51 {
52 EFI_STATUS Status;
53 VOID *CommonBuffer;
54 EFI_PHYSICAL_ADDRESS MappedAddress;
55 UINTN MemoryBlockSizeInBytes;
56 VOID *Mapping;
57
58 //
59 // Allocate memory for MemoryHeader
60 //
61 *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));
62 if (*MemoryHeader == NULL) {
63 return EFI_OUT_OF_RESOURCES;
64 }
65
66 (*MemoryHeader)->Next = NULL;
67
68 //
69 // set Memory block size
70 //
71 (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
72
73 //
74 // each bit in Bit Array will manage 32 bytes memory in memory block
75 //
76 (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
77
78 //
79 // Allocate memory for BitArray
80 //
81 (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);
82 if ((*MemoryHeader)->BitArrayPtr == NULL) {
83 gBS->FreePool (*MemoryHeader);
84 return EFI_OUT_OF_RESOURCES;
85 }
86
87 //
88 // Memory Block uses MemoryBlockSizeInPages pages,
89 // and it is allocated as common buffer use.
90 //
91 Status = HcDev->PciIo->AllocateBuffer (
92 HcDev->PciIo,
93 AllocateAnyPages,
94 EfiBootServicesData,
95 MemoryBlockSizeInPages,
96 &CommonBuffer,
97 0
98 );
99 if (EFI_ERROR (Status)) {
100 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
101 gBS->FreePool (*MemoryHeader);
102 return EFI_OUT_OF_RESOURCES;
103 }
104
105 MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
106 Status = HcDev->PciIo->Map (
107 HcDev->PciIo,
108 EfiPciIoOperationBusMasterCommonBuffer,
109 CommonBuffer,
110 &MemoryBlockSizeInBytes,
111 &MappedAddress,
112 &Mapping
113 );
114 //
115 // If returned Mapped size is less than the size
116 // we request,do not support.
117 //
118 if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {
119 HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);
120 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
121 gBS->FreePool (*MemoryHeader);
122 return EFI_UNSUPPORTED;
123 }
124
125 //
126 // Data structure involved by host controller
127 // should be restricted into the same 4G
128 //
129 if (HcDev->Is64BitCapable != 0) {
130 if (HcDev->High32BitAddr != GET_32B_TO_63B (MappedAddress)) {
131 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
132 HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);
133 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
134 gBS->FreePool (*MemoryHeader);
135 return EFI_UNSUPPORTED;
136 }
137 }
138
139 //
140 // Set Memory block initial address
141 //
142 (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);
143 (*MemoryHeader)->Mapping = Mapping;
144
145 ZeroMem (
146 (*MemoryHeader)->MemoryBlockPtr,
147 EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)
148 );
149
150 return EFI_SUCCESS;
151 }
152
153 EFI_STATUS
154 FreeMemoryHeader (
155 IN USB2_HC_DEV *HcDev,
156 IN MEMORY_MANAGE_HEADER *MemoryHeader
157 )
158 /*++
159
160 Routine Description:
161
162 Free Memory Header
163
164 Arguments:
165
166 HcDev - USB2_HC_DEV
167 MemoryHeader - MemoryHeader to be freed
168
169 Returns:
170
171 EFI_SUCCESS Success
172 EFI_INVALID_PARAMETER Parameter is error
173
174 --*/
175 {
176 if ((MemoryHeader == NULL) || (HcDev == NULL)) {
177 return EFI_INVALID_PARAMETER;
178 }
179 //
180 // unmap the common buffer used by the memory block
181 //
182 HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);
183
184 //
185 // free common buffer
186 //
187 HcDev->PciIo->FreeBuffer (
188 HcDev->PciIo,
189 EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),
190 MemoryHeader->MemoryBlockPtr
191 );
192 //
193 // free bit array
194 //
195 gBS->FreePool (MemoryHeader->BitArrayPtr);
196 //
197 // free memory header
198 //
199 gBS->FreePool (MemoryHeader);
200
201 return EFI_SUCCESS;
202 }
203
204 EFI_STATUS
205 EhciAllocatePool (
206 IN USB2_HC_DEV *HcDev,
207 OUT UINT8 **Pool,
208 IN UINTN AllocSize
209 )
210 /*++
211
212 Routine Description:
213
214 Ehci Allocate Pool
215
216 Arguments:
217
218 HcDev - USB2_HC_DEV
219 Pool - Place to store pointer to the memory buffer
220 AllocSize - Alloc Size
221
222 Returns:
223
224 EFI_SUCCESS Success
225 EFI_DEVICE_ERROR Fail
226
227 --*/
228 {
229 MEMORY_MANAGE_HEADER *MemoryHeader;
230 MEMORY_MANAGE_HEADER *TempHeaderPtr;
231 MEMORY_MANAGE_HEADER *NewMemoryHeader;
232 UINTN RealAllocSize;
233 UINTN MemoryBlockSizeInPages;
234 EFI_STATUS Status;
235 EFI_TPL OldTpl;
236
237 *Pool = NULL;
238
239 MemoryHeader = HcDev->MemoryHeader;
240 ASSERT (MemoryHeader != NULL);
241
242 OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);
243
244 //
245 // allocate unit is 32 bytes (align on 32 byte)
246 //
247 if (AllocSize & 0x1F) {
248 RealAllocSize = (AllocSize / 32 + 1) * 32;
249 } else {
250 RealAllocSize = AllocSize;
251 }
252
253 //
254 // There may be linked MemoryHeaders.
255 // To allocate a free pool in Memory blocks,
256 // must search in the MemoryHeader link list
257 // until enough free pool is found.
258 //
259 Status = EFI_NOT_FOUND;
260 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
261
262 Status = AllocMemInMemoryBlock (
263 TempHeaderPtr,
264 (VOID **) Pool,
265 RealAllocSize / 32
266 );
267 if (!EFI_ERROR (Status)) {
268 ZeroMem (*Pool, AllocSize);
269 gBS->RestoreTPL (OldTpl);
270 return EFI_SUCCESS;
271 }
272 }
273
274 gBS->RestoreTPL (OldTpl);
275
276 //
277 // There is no enough memory,
278 // Create a new Memory Block
279 //
280
281 //
282 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
283 // just allocate a large enough memory block.
284 //
285 if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {
286 MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;
287 } else {
288 MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
289 }
290
291 Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
292 if (EFI_ERROR (Status)) {
293 return Status;
294 }
295
296 OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);
297
298 //
299 // Link the new Memory Block to the Memory Header list
300 //
301 InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
302
303 Status = AllocMemInMemoryBlock (
304 NewMemoryHeader,
305 (VOID **) Pool,
306 RealAllocSize / 32
307 );
308 if (!EFI_ERROR (Status)) {
309 ZeroMem (*Pool, AllocSize);
310 }
311
312 gBS->RestoreTPL (OldTpl);
313 return Status;
314 }
315
316 VOID
317 EhciFreePool (
318 IN USB2_HC_DEV *HcDev,
319 IN UINT8 *Pool,
320 IN UINTN AllocSize
321 )
322 /*++
323
324 Routine Description:
325
326 Uhci Free Pool
327
328 Arguments:
329
330 HcDev - USB_HC_DEV
331 Pool - Pool to free
332 AllocSize - Pool size
333
334 Returns:
335
336 VOID
337
338 --*/
339 {
340 MEMORY_MANAGE_HEADER *MemoryHeader;
341 MEMORY_MANAGE_HEADER *TempHeaderPtr;
342 UINTN StartBytePos;
343 UINTN Index;
344 UINT8 StartBitPos;
345 UINT8 Index2;
346 UINTN Count;
347 UINTN RealAllocSize;
348 EFI_TPL OldTpl;
349
350 OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);
351
352 MemoryHeader = HcDev->MemoryHeader;
353
354 //
355 // allocate unit is 32 byte (align on 32 byte)
356 //
357 if (AllocSize & 0x1F) {
358 RealAllocSize = (AllocSize / 32 + 1) * 32;
359 } else {
360 RealAllocSize = AllocSize;
361 }
362
363 //
364 // scan the memory header linked list for
365 // the asigned memory to free.
366 //
367 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
368
369 if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
370 ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))
371 ) {
372 //
373 // Pool is in the Memory Block area,
374 // find the start byte and bit in the bit array
375 //
376 StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
377 StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) & 0x7);
378
379 //
380 // reset associated bits in bit arry
381 //
382 for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
383 TempHeaderPtr->BitArrayPtr[Index] ^= (UINT8) (bit (Index2));
384 Index2++;
385 if (Index2 == 8) {
386 Index += 1;
387 Index2 = 0;
388 }
389 }
390 //
391 // break the loop
392 //
393 break;
394 }
395 }
396
397 //
398 // Release emptied memory blocks (only if the memory block is not
399 // the first one in the memory header list
400 //
401 for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) {
402
403 ASSERT (MemoryHeader->Next != NULL);
404
405 if (IsMemoryBlockEmptied (TempHeaderPtr)) {
406
407 DelinkMemoryBlock (MemoryHeader, TempHeaderPtr);
408 //
409 // when the TempHeaderPtr is freed in FreeMemoryHeader(),
410 // the TempHeaderPtr is pointing to nonsense content.
411 //
412 gBS->RestoreTPL (OldTpl);
413 FreeMemoryHeader (HcDev, TempHeaderPtr);
414 OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);
415 //
416 // reset the TempHeaderPtr, continue search for
417 // another empty memory block.
418 //
419 TempHeaderPtr = MemoryHeader->Next;
420 continue;
421 }
422
423 TempHeaderPtr = TempHeaderPtr->Next;
424 }
425
426 gBS->RestoreTPL (OldTpl);
427 }
428
429 VOID
430 InsertMemoryHeaderToList (
431 IN MEMORY_MANAGE_HEADER *MemoryHeader,
432 IN MEMORY_MANAGE_HEADER *NewMemoryHeader
433 )
434 /*++
435
436 Routine Description:
437
438 Insert Memory Header To List
439
440 Arguments:
441
442 MemoryHeader - MEMORY_MANAGE_HEADER
443 NewMemoryHeader - MEMORY_MANAGE_HEADER
444
445 Returns:
446
447 VOID
448
449 --*/
450 {
451 MEMORY_MANAGE_HEADER *TempHeaderPtr;
452
453 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
454 if (TempHeaderPtr->Next == NULL) {
455 TempHeaderPtr->Next = NewMemoryHeader;
456 break;
457 }
458 }
459 }
460
461 EFI_STATUS
462 AllocMemInMemoryBlock (
463 IN MEMORY_MANAGE_HEADER *MemoryHeader,
464 OUT VOID **Pool,
465 IN UINTN NumberOfMemoryUnit
466 )
467 /*++
468
469 Routine Description:
470
471 Alloc Memory In MemoryBlock
472
473 Arguments:
474
475 MemoryHeader - MEMORY_MANAGE_HEADER
476 Pool - Place to store pointer to memory
477 NumberOfMemoryUnit - Number Of Memory Unit
478
479 Returns:
480
481 EFI_SUCCESS Success
482 EFI_NOT_FOUND Can't find the free memory
483
484 --*/
485 {
486 UINTN TempBytePos;
487 UINTN FoundBytePos;
488 UINT8 Index;
489 UINT8 FoundBitPos;
490 UINT8 ByteValue;
491 UINT8 BitValue;
492 UINTN NumberOfZeros;
493 UINTN Count;
494
495 FoundBytePos = 0;
496 FoundBitPos = 0;
497 ByteValue = MemoryHeader->BitArrayPtr[0];
498 NumberOfZeros = 0;
499 Index = 0;
500
501 for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
502
503 //
504 // Pop out BitValue from a byte in TempBytePos.
505 //
506 BitValue = (UINT8) (ByteValue & 0x1);
507
508 //
509 // right shift the byte
510 //
511 ByteValue /= 2;
512
513 if (BitValue == 0) {
514 //
515 // Found a free bit, the NumberOfZeros only record the number
516 // of those consecutive zeros
517 //
518 NumberOfZeros++;
519 //
520 // Found enough consecutive free space, break the loop
521 //
522 if (NumberOfZeros >= NumberOfMemoryUnit) {
523 break;
524 }
525 } else {
526 //
527 // Encountering a '1', meant the bit is ocupied.
528 //
529 if (NumberOfZeros >= NumberOfMemoryUnit) {
530 //
531 // Found enough consecutive free space,break the loop
532 //
533 break;
534 } else {
535 //
536 // the NumberOfZeros only record the number of those consecutive zeros,
537 // so reset the NumberOfZeros to 0 when encountering '1' before finding
538 // enough consecutive '0's
539 //
540 NumberOfZeros = 0;
541 //
542 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
543 //
544 FoundBytePos = TempBytePos;
545 FoundBitPos = Index;
546 }
547 }
548
549 //
550 // step forward a bit
551 //
552 Index++;
553 if (Index == 8) {
554 //
555 // step forward a byte, getting the byte value,
556 // and reset the bit pos.
557 //
558 TempBytePos += 1;
559 ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
560 Index = 0;
561 }
562 }
563
564 if (NumberOfZeros < NumberOfMemoryUnit) {
565 return EFI_NOT_FOUND;
566 }
567
568 //
569 // Found enough free space.
570 //
571
572 //
573 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
574 // 1)(FoundBytePos,FoundBitPos) record the position
575 // of the last '1' before the consecutive '0's, it must
576 // be adjusted to the start position of the consecutive '0's.
577 // 2)the start address of the consecutive '0's is just the start of
578 // the bitarray. so no need to adjust the values of
579 // (FoundBytePos,FoundBitPos).
580 //
581 if ((MemoryHeader->BitArrayPtr[FoundBytePos] & bit (FoundBitPos)) != 0) {
582 FoundBitPos += 1;
583 }
584
585 //
586 // Have the (FoundBytePos,FoundBitPos) make sense.
587 //
588 if (FoundBitPos > 7) {
589 FoundBytePos += 1;
590 FoundBitPos -= 8;
591 }
592
593 //
594 // Set the memory as allocated
595 //
596 for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
597
598 MemoryHeader->BitArrayPtr[TempBytePos] |= bit (Index);
599 Index++;
600 if (Index == 8) {
601 TempBytePos += 1;
602 Index = 0;
603 }
604 }
605
606 *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
607
608 return EFI_SUCCESS;
609 }
610
611 BOOLEAN
612 IsMemoryBlockEmptied (
613 IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr
614 )
615 /*++
616
617 Routine Description:
618
619 Is Memory Block Emptied
620
621 Arguments:
622
623 MemoryHeaderPtr - MEMORY_MANAGE_HEADER
624
625 Returns:
626
627 TRUE Empty
628 FALSE Not Empty
629
630 --*/
631 {
632 UINTN Index;
633
634 for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {
635 if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {
636 return FALSE;
637 }
638 }
639
640 return TRUE;
641 }
642
643 VOID
644 DelinkMemoryBlock (
645 IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,
646 IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader
647 )
648 /*++
649
650 Routine Description:
651
652 Delink Memory Block
653
654 Arguments:
655
656 FirstMemoryHeader - MEMORY_MANAGE_HEADER
657 NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER
658
659 Returns:
660
661 VOID
662
663 --*/
664 {
665 MEMORY_MANAGE_HEADER *TempHeaderPtr;
666
667 if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) {
668 return ;
669 }
670
671 for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
672
673 if (TempHeaderPtr->Next == NeedFreeMemoryHeader) {
674 //
675 // Link the before and after
676 //
677 TempHeaderPtr->Next = NeedFreeMemoryHeader->Next;
678 break;
679 }
680 }
681 }
682
683 EFI_STATUS
684 InitialMemoryManagement (
685 IN USB2_HC_DEV *HcDev
686 )
687 /*++
688
689 Routine Description:
690
691 Initialize Memory Management
692
693 Arguments:
694
695 HcDev - USB2_HC_DEV
696
697 Returns:
698
699 EFI_SUCCESS Success
700 EFI_DEVICE_ERROR Fail
701
702 --*/
703 {
704 EFI_STATUS Status;
705 MEMORY_MANAGE_HEADER *MemoryHeader;
706 UINTN MemPages;
707
708 MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
709 Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages);
710 if (EFI_ERROR (Status)) {
711 Status = EFI_OUT_OF_RESOURCES;
712 goto exit;
713 }
714
715 HcDev->MemoryHeader = MemoryHeader;
716
717 exit:
718 return Status;
719 }
720
721 EFI_STATUS
722 DeinitialMemoryManagement (
723 IN USB2_HC_DEV *HcDev
724 )
725 /*++
726
727 Routine Description:
728
729 Deinitialize Memory Management
730
731 Arguments:
732
733 HcDev - USB2_HC_DEV
734
735 Returns:
736
737 EFI_SUCCESS Success
738 EFI_DEVICE_ERROR Fail
739
740 --*/
741 {
742 MEMORY_MANAGE_HEADER *TempHeaderPtr;
743
744 for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) {
745
746 DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr);
747 //
748 // when the TempHeaderPtr is freed in FreeMemoryHeader(),
749 // the TempHeaderPtr is pointing to nonsense content.
750 //
751 FreeMemoryHeader (HcDev, TempHeaderPtr);
752 //
753 // reset the TempHeaderPtr,continue free another memory block.
754 //
755 TempHeaderPtr = HcDev->MemoryHeader->Next;
756 }
757
758 FreeMemoryHeader (HcDev, HcDev->MemoryHeader);
759
760 return EFI_SUCCESS;
761 }