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