mem.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-08-25 GuEe-GUI first version
  9. */
  10. #include <drivers/pci_endpoint.h>
  11. #define DBG_TAG "pci.ep.mem"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. rt_err_t rt_pci_ep_mem_array_init(struct rt_pci_ep *ep,
  15. struct rt_pci_ep_mem *mems, rt_size_t mems_nr)
  16. {
  17. rt_size_t idx;
  18. rt_err_t err = RT_EOK;
  19. if (!ep || !mems)
  20. {
  21. return -RT_EINVAL;
  22. }
  23. rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
  24. ep->mems_nr = mems_nr;
  25. ep->mems = rt_calloc(mems_nr, sizeof(*ep->mems));
  26. if (!ep->mems)
  27. {
  28. return -RT_ENOMEM;
  29. }
  30. for (idx = 0; idx < mems_nr; ++idx)
  31. {
  32. struct rt_pci_ep_mem *mem = &ep->mems[idx];
  33. mem->cpu_addr = mems->cpu_addr;
  34. mem->size = mems->size;
  35. mem->page_size = mems->page_size;
  36. mem->bits = mems->size / mems->page_size;
  37. mem->map = rt_calloc(RT_BITMAP_LEN(mem->bits), sizeof(*mem->map));
  38. if (!mem->map)
  39. {
  40. err = -RT_ENOMEM;
  41. goto _out_lock;
  42. }
  43. }
  44. _out_lock:
  45. if (err)
  46. {
  47. while (idx --> 0)
  48. {
  49. rt_free(ep->mems[idx].map);
  50. }
  51. rt_free(ep->mems);
  52. ep->mems_nr = 0;
  53. ep->mems = RT_NULL;
  54. }
  55. rt_mutex_release(&ep->lock);
  56. return err;
  57. }
  58. rt_err_t rt_pci_ep_mem_init(struct rt_pci_ep *ep,
  59. rt_ubase_t cpu_addr, rt_size_t size, rt_size_t page_size)
  60. {
  61. struct rt_pci_ep_mem mem;
  62. if (!ep)
  63. {
  64. return -RT_EINVAL;
  65. }
  66. mem.cpu_addr = cpu_addr;
  67. mem.size = size;
  68. mem.page_size = page_size;
  69. return rt_pci_ep_mem_array_init(ep, &mem, 1);
  70. }
  71. static rt_ubase_t bitmap_region_alloc(struct rt_pci_ep_mem *mem, rt_size_t size)
  72. {
  73. rt_size_t bit, next_bit, end_bit, max_bits;
  74. size /= mem->page_size;
  75. max_bits = mem->bits - size;
  76. rt_bitmap_for_each_clear_bit(mem->map, bit, max_bits)
  77. {
  78. end_bit = bit + size;
  79. for (next_bit = bit + 1; next_bit < end_bit; ++next_bit)
  80. {
  81. if (rt_bitmap_test_bit(mem->map, next_bit))
  82. {
  83. bit = next_bit;
  84. goto _next;
  85. }
  86. }
  87. if (next_bit == end_bit)
  88. {
  89. while (next_bit --> bit)
  90. {
  91. rt_bitmap_set_bit(mem->map, next_bit);
  92. }
  93. return mem->cpu_addr + bit * mem->page_size;
  94. }
  95. _next:
  96. ;
  97. }
  98. return ~0ULL;
  99. }
  100. static void bitmap_region_free(struct rt_pci_ep_mem *mem,
  101. rt_ubase_t cpu_addr, rt_size_t size)
  102. {
  103. rt_size_t bit = (cpu_addr - mem->cpu_addr) / mem->page_size, end_bit;
  104. size /= mem->page_size;
  105. end_bit = bit + size;
  106. for (; bit < end_bit; ++bit)
  107. {
  108. rt_bitmap_clear_bit(mem->map, bit);
  109. }
  110. }
  111. void *rt_pci_ep_mem_alloc(struct rt_pci_ep *ep,
  112. rt_ubase_t *out_cpu_addr, rt_size_t size)
  113. {
  114. void *vaddr = RT_NULL;
  115. if (!ep || !out_cpu_addr)
  116. {
  117. return vaddr;
  118. }
  119. rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
  120. for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
  121. {
  122. rt_ubase_t cpu_addr;
  123. struct rt_pci_ep_mem *mem = &ep->mems[idx];
  124. cpu_addr = bitmap_region_alloc(mem, size);
  125. if (cpu_addr != ~0ULL)
  126. {
  127. vaddr = rt_ioremap((void *)cpu_addr, size);
  128. if (!vaddr)
  129. {
  130. bitmap_region_free(mem, cpu_addr, size);
  131. /* Try next memory */
  132. continue;
  133. }
  134. *out_cpu_addr = cpu_addr;
  135. break;
  136. }
  137. }
  138. rt_mutex_release(&ep->lock);
  139. return vaddr;
  140. }
  141. void rt_pci_ep_mem_free(struct rt_pci_ep *ep,
  142. void *vaddr, rt_ubase_t cpu_addr, rt_size_t size)
  143. {
  144. if (!ep || !vaddr || !size)
  145. {
  146. return;
  147. }
  148. rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
  149. for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
  150. {
  151. struct rt_pci_ep_mem *mem = &ep->mems[idx];
  152. if (mem->cpu_addr > cpu_addr &&
  153. mem->cpu_addr + mem->size >= cpu_addr + size)
  154. {
  155. rt_iounmap(mem);
  156. bitmap_region_free(mem, cpu_addr, size);
  157. break;
  158. }
  159. }
  160. rt_mutex_release(&ep->lock);
  161. }