1 /** @file 2 Routine procedures for memory allocate/free. 3 4 Copyright (c) 2013-2015 Intel Corporation. 5 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT 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 **/ 29 USBHC_MEM_BLOCK * 30 UsbHcAllocMemBlock ( 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 111 FREE_BUFFER: 112 PciIo->FreeBuffer (PciIo, Pages, BufHost); 113 114 FREE_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 **/ 128 VOID 129 UsbHcFreeMemBlock ( 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 **/ 161 VOID * 162 UsbHcAllocMemFromBlock ( 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 **/ 233 EFI_PHYSICAL_ADDRESS 234 UsbHcGetPciAddressForHostMem ( 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 **/ 280 VOID 281 UsbHcInsertMemBlockToPool ( 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 **/ 301 BOOLEAN 302 UsbHcIsMemBlockEmpty ( 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 **/ 325 VOID 326 UsbHcUnlinkMemBlock ( 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 **/ 357 USBHC_MEM_POOL * 358 UsbHcInitMemPool ( 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 **/ 395 EFI_STATUS 396 UsbHcFreeMemPool ( 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 **/ 430 VOID * 431 UsbHcAllocateMem ( 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 **/ 505 VOID 506 UsbHcFreeMem ( 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