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 
11 #include <drivers/pci_endpoint.h>
12 
13 #define DBG_TAG "pci.ep.mem"
14 #define DBG_LVL DBG_INFO
15 #include <rtdbg.h>
16 
rt_pci_ep_mem_array_init(struct rt_pci_ep * ep,struct rt_pci_ep_mem * mems,rt_size_t mems_nr)17 rt_err_t rt_pci_ep_mem_array_init(struct rt_pci_ep *ep,
18         struct rt_pci_ep_mem *mems, rt_size_t mems_nr)
19 {
20     rt_size_t idx;
21     rt_err_t err = RT_EOK;
22 
23     if (!ep || !mems)
24     {
25         return -RT_EINVAL;
26     }
27 
28     rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
29 
30     ep->mems_nr = mems_nr;
31     ep->mems = rt_calloc(mems_nr, sizeof(*ep->mems));
32 
33     if (!ep->mems)
34     {
35         return -RT_ENOMEM;
36     }
37 
38     for (idx = 0; idx < mems_nr; ++idx)
39     {
40         struct rt_pci_ep_mem *mem = &ep->mems[idx];
41 
42         mem->cpu_addr = mems->cpu_addr;
43         mem->size = mems->size;
44         mem->page_size = mems->page_size;
45         mem->bits = mems->size / mems->page_size;
46         mem->map = rt_calloc(RT_BITMAP_LEN(mem->bits), sizeof(*mem->map));
47 
48         if (!mem->map)
49         {
50             err = -RT_ENOMEM;
51             goto _out_lock;
52         }
53     }
54 
55 _out_lock:
56     if (err)
57     {
58         while (idx --> 0)
59         {
60             rt_free(ep->mems[idx].map);
61         }
62         rt_free(ep->mems);
63 
64         ep->mems_nr = 0;
65         ep->mems = RT_NULL;
66     }
67 
68     rt_mutex_release(&ep->lock);
69 
70     return err;
71 }
72 
rt_pci_ep_mem_init(struct rt_pci_ep * ep,rt_ubase_t cpu_addr,rt_size_t size,rt_size_t page_size)73 rt_err_t rt_pci_ep_mem_init(struct rt_pci_ep *ep,
74         rt_ubase_t cpu_addr, rt_size_t size, rt_size_t page_size)
75 {
76     struct rt_pci_ep_mem mem;
77 
78     if (!ep)
79     {
80         return -RT_EINVAL;
81     }
82 
83     mem.cpu_addr = cpu_addr;
84     mem.size = size;
85     mem.page_size = page_size;
86 
87     return rt_pci_ep_mem_array_init(ep, &mem, 1);
88 }
89 
bitmap_region_alloc(struct rt_pci_ep_mem * mem,rt_size_t size)90 static rt_ubase_t bitmap_region_alloc(struct rt_pci_ep_mem *mem, rt_size_t size)
91 {
92     rt_size_t bit, next_bit, end_bit, max_bits;
93 
94     size /= mem->page_size;
95     max_bits = mem->bits - size;
96 
97     rt_bitmap_for_each_clear_bit(mem->map, bit, max_bits)
98     {
99         end_bit = bit + size;
100 
101         for (next_bit = bit + 1; next_bit < end_bit; ++next_bit)
102         {
103             if (rt_bitmap_test_bit(mem->map, next_bit))
104             {
105                 bit = next_bit;
106                 goto _next;
107             }
108         }
109 
110         if (next_bit == end_bit)
111         {
112             while (next_bit --> bit)
113             {
114                 rt_bitmap_set_bit(mem->map, next_bit);
115             }
116 
117             return mem->cpu_addr + bit * mem->page_size;
118         }
119     _next:
120     }
121 
122     return ~0ULL;
123 }
124 
bitmap_region_free(struct rt_pci_ep_mem * mem,rt_ubase_t cpu_addr,rt_size_t size)125 static void bitmap_region_free(struct rt_pci_ep_mem *mem,
126         rt_ubase_t cpu_addr, rt_size_t size)
127 {
128     rt_size_t bit = (cpu_addr - mem->cpu_addr) / mem->page_size, end_bit;
129 
130     size /= mem->page_size;
131     end_bit = bit + size;
132 
133     for (; bit < end_bit; ++bit)
134     {
135         rt_bitmap_clear_bit(mem->map, bit);
136     }
137 }
138 
rt_pci_ep_mem_alloc(struct rt_pci_ep * ep,rt_ubase_t * out_cpu_addr,rt_size_t size)139 void *rt_pci_ep_mem_alloc(struct rt_pci_ep *ep,
140         rt_ubase_t *out_cpu_addr, rt_size_t size)
141 {
142     void *vaddr = RT_NULL;
143 
144     if (!ep || !out_cpu_addr)
145     {
146         return vaddr;
147     }
148 
149     rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
150 
151     for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
152     {
153         rt_ubase_t cpu_addr;
154         struct rt_pci_ep_mem *mem = &ep->mems[idx];
155 
156         cpu_addr = bitmap_region_alloc(mem, size);
157 
158         if (cpu_addr != ~0ULL)
159         {
160             vaddr = rt_ioremap((void *)cpu_addr, size);
161 
162             if (!vaddr)
163             {
164                 bitmap_region_free(mem, cpu_addr, size);
165 
166                 /* Try next memory */
167                 continue;
168             }
169 
170             *out_cpu_addr = cpu_addr;
171             break;
172         }
173     }
174 
175     rt_mutex_release(&ep->lock);
176 
177     return vaddr;
178 }
179 
rt_pci_ep_mem_free(struct rt_pci_ep * ep,void * vaddr,rt_ubase_t cpu_addr,rt_size_t size)180 void rt_pci_ep_mem_free(struct rt_pci_ep *ep,
181         void *vaddr, rt_ubase_t cpu_addr, rt_size_t size)
182 {
183     if (!ep || !vaddr || !size)
184     {
185         return;
186     }
187 
188     rt_mutex_take(&ep->lock, RT_WAITING_FOREVER);
189 
190     for (rt_size_t idx = 0; idx < ep->mems_nr; ++idx)
191     {
192         struct rt_pci_ep_mem *mem = &ep->mems[idx];
193 
194         if (mem->cpu_addr > cpu_addr &&
195             mem->cpu_addr + mem->size >= cpu_addr + size)
196         {
197             rt_iounmap(mem);
198             bitmap_region_free(mem, cpu_addr, size);
199 
200             break;
201         }
202     }
203 
204     rt_mutex_release(&ep->lock);
205 }
206