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