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