123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- * Copyright (c) 2006-2022, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-08-25 GuEe-GUI first version
- */
- #include <drivers/pci_endpoint.h>
- #define DBG_TAG "pci.ep.mem"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- rt_err_t rt_pci_ep_mem_array_init(struct rt_pci_ep *ep,
- struct rt_pci_ep_mem *mems, rt_size_t mems_nr)
- {
- rt_size_t idx;
- rt_err_t err = RT_EOK;
- if (!ep || !mems)
- {
- return -RT_EINVAL;
- }
- rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
- ep->mems_nr = mems_nr;
- ep->mems = rt_calloc(mems_nr, sizeof(*ep->mems));
- if (!ep->mems)
- {
- return -RT_ENOMEM;
- }
- for (idx = 0; idx < mems_nr; ++idx)
- {
- struct rt_pci_ep_mem *mem = &ep->mems[idx];
- mem->cpu_addr = mems->cpu_addr;
- mem->size = mems->size;
- mem->page_size = mems->page_size;
- mem->bits = mems->size / mems->page_size;
- mem->map = rt_calloc(RT_BITMAP_LEN(mem->bits), sizeof(*mem->map));
- if (!mem->map)
- {
- err = -RT_ENOMEM;
- goto _out_lock;
- }
- }
- _out_lock:
- if (err)
- {
- while (idx --> 0)
- {
- rt_free(ep->mems[idx].map);
- }
- rt_free(ep->mems);
- ep->mems_nr = 0;
- ep->mems = RT_NULL;
- }
- rt_mutex_release(&ep->lock);
- return err;
- }
- rt_err_t rt_pci_ep_mem_init(struct rt_pci_ep *ep,
- rt_ubase_t cpu_addr, rt_size_t size, rt_size_t page_size)
- {
- struct rt_pci_ep_mem mem;
- if (!ep)
- {
- return -RT_EINVAL;
- }
- mem.cpu_addr = cpu_addr;
- mem.size = size;
- mem.page_size = page_size;
- return rt_pci_ep_mem_array_init(ep, &mem, 1);
- }
- static rt_ubase_t bitmap_region_alloc(struct rt_pci_ep_mem *mem, rt_size_t size)
- {
- rt_size_t bit, next_bit, end_bit, max_bits;
- size /= mem->page_size;
- max_bits = mem->bits - size;
- rt_bitmap_for_each_clear_bit(mem->map, bit, max_bits)
- {
- end_bit = bit + size;
- for (next_bit = bit + 1; next_bit < end_bit; ++next_bit)
- {
- if (rt_bitmap_test_bit(mem->map, next_bit))
- {
- bit = next_bit;
- goto _next;
- }
- }
- if (next_bit == end_bit)
- {
- while (next_bit --> bit)
- {
- rt_bitmap_set_bit(mem->map, next_bit);
- }
- return mem->cpu_addr + bit * mem->page_size;
- }
- _next:
- }
- return ~0ULL;
- }
- static void bitmap_region_free(struct rt_pci_ep_mem *mem,
- rt_ubase_t cpu_addr, rt_size_t size)
- {
- rt_size_t bit = (cpu_addr - mem->cpu_addr) / mem->page_size, end_bit;
- size /= mem->page_size;
- end_bit = bit + size;
- for (; bit < end_bit; ++bit)
- {
- rt_bitmap_clear_bit(mem->map, bit);
- }
- }
- void *rt_pci_ep_mem_alloc(struct rt_pci_ep *ep,
- rt_ubase_t *out_cpu_addr, rt_size_t size)
- {
- void *vaddr = RT_NULL;
- if (!ep || !out_cpu_addr)
- {
- return vaddr;
- }
- rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
- for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
- {
- rt_ubase_t cpu_addr;
- struct rt_pci_ep_mem *mem = &ep->mems[idx];
- cpu_addr = bitmap_region_alloc(mem, size);
- if (cpu_addr != ~0ULL)
- {
- vaddr = rt_ioremap((void *)cpu_addr, size);
- if (!vaddr)
- {
- bitmap_region_free(mem, cpu_addr, size);
- /* Try next memory */
- continue;
- }
- *out_cpu_addr = cpu_addr;
- break;
- }
- }
- rt_mutex_release(&ep->lock);
- return vaddr;
- }
- void rt_pci_ep_mem_free(struct rt_pci_ep *ep,
- void *vaddr, rt_ubase_t cpu_addr, rt_size_t size)
- {
- if (!ep || !vaddr || !size)
- {
- return;
- }
- rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
- for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
- {
- struct rt_pci_ep_mem *mem = &ep->mems[idx];
- if (mem->cpu_addr > cpu_addr &&
- mem->cpu_addr + mem->size >= cpu_addr + size)
- {
- rt_iounmap(mem);
- bitmap_region_free(mem, cpu_addr, size);
- break;
- }
- }
- rt_mutex_release(&ep->lock);
- }
|