Skip to content

Commit f16bd3e

Browse files
committed
[dm][hwspinlock] support hwspinlock
Hardware spinlock modules provide hardware assistance for synchronization and mutual exclusion between heterogeneous processors and those not operating under a single, shared operating system. Signed-off-by: GuEe-GUI <[email protected]>
1 parent 2fb53c8 commit f16bd3e

File tree

7 files changed

+659
-0
lines changed

7 files changed

+659
-0
lines changed

components/drivers/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ rsource "hwcrypto/Kconfig"
2323
rsource "wlan/Kconfig"
2424
rsource "led/Kconfig"
2525
rsource "mailbox/Kconfig"
26+
rsource "hwspinlock/Kconfig"
2627
rsource "phye/Kconfig"
2728
rsource "ata/Kconfig"
2829
rsource "nvme/Kconfig"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
menuconfig RT_USING_HWSPINLOCK
2+
bool "Using Hardware Spinlock device drivers"
3+
depends on RT_USING_DM
4+
depends on RT_USING_OFW
5+
select RT_USING_ADT
6+
select RT_USING_ADT_REF
7+
default n
8+
help
9+
Hardware spinlock modules provide hardware assistance for
10+
synchronization and mutual exclusion between heterogeneous processors
11+
and those not operating under a single, shared operating system.
12+
13+
if RT_USING_HWSPINLOCK
14+
osource "$(SOC_DM_HWSPINLOCK_DIR)/Kconfig"
15+
endif
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from building import *
2+
3+
group = []
4+
5+
if not GetDepend(['RT_USING_HWSPINLOCK']):
6+
Return('group')
7+
8+
cwd = GetCurrentDir()
9+
CPPPATH = [cwd + '/../include']
10+
11+
src = ['hwspinlock.c']
12+
13+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
14+
15+
Return('group')
Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
/*
2+
* Copyright (c) 2006-2023, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2023-09-23 GuEe-GUI first version
9+
*/
10+
11+
#include <rtthread.h>
12+
13+
#include <cpuport.h>
14+
15+
#define DBG_TAG "rtdm.hwspinlock"
16+
#define DBG_LVL DBG_INFO
17+
#include <rtdbg.h>
18+
19+
#include "hwspinlock_dm.h"
20+
21+
static RT_DEFINE_SPINLOCK(hwspinlock_ops_lock);
22+
static rt_list_t hwspinlock_bank_nodes = RT_LIST_OBJECT_INIT(hwspinlock_bank_nodes);
23+
24+
rt_err_t rt_hwspinlock_bank_register(struct rt_hwspinlock_bank *bank)
25+
{
26+
struct rt_hwspinlock *hwlock;
27+
28+
if (!bank || !bank->ops || bank->locks_nr <= 0 || !bank->dev)
29+
{
30+
return -RT_EINVAL;
31+
}
32+
33+
rt_list_init(&bank->list);
34+
rt_ref_init(&bank->ref);
35+
36+
hwlock = &bank->locks[0];
37+
38+
for (int i = 0; i < bank->locks_nr; ++i, ++hwlock)
39+
{
40+
hwlock->bank = bank;
41+
hwlock->used = RT_FALSE;
42+
rt_spin_lock_init(&hwlock->lock);
43+
}
44+
45+
rt_spin_lock(&hwspinlock_ops_lock);
46+
rt_list_insert_after(&hwspinlock_bank_nodes, &bank->list);
47+
rt_spin_unlock(&hwspinlock_ops_lock);
48+
49+
rt_dm_dev_bind_fwdata(bank->dev, RT_NULL, bank);
50+
51+
return RT_EOK;
52+
}
53+
54+
rt_err_t rt_hwspinlock_bank_unregister(struct rt_hwspinlock_bank *bank)
55+
{
56+
rt_err_t err;
57+
58+
if (!bank)
59+
{
60+
return -RT_EINVAL;
61+
}
62+
63+
rt_spin_lock(&hwspinlock_ops_lock);
64+
65+
if (rt_ref_read(&bank->ref) == 1)
66+
{
67+
rt_list_remove(&bank->list);
68+
rt_dm_dev_unbind_fwdata(bank->dev, RT_NULL);
69+
70+
err = RT_EOK;
71+
}
72+
else
73+
{
74+
err = -RT_EBUSY;
75+
}
76+
77+
rt_spin_unlock(&hwspinlock_ops_lock);
78+
79+
return err;
80+
}
81+
82+
rt_err_t rt_hwspin_trylock_raw(struct rt_hwspinlock *hwlock,
83+
rt_ubase_t *out_irq_level)
84+
{
85+
rt_err_t err;
86+
87+
if (!hwlock)
88+
{
89+
return -RT_EINVAL;
90+
}
91+
92+
if (out_irq_level)
93+
{
94+
*out_irq_level = rt_spin_lock_irqsave(&hwlock->lock);
95+
}
96+
else
97+
{
98+
rt_spin_lock(&hwlock->lock);
99+
}
100+
101+
err = hwlock->bank->ops->trylock(hwlock);
102+
103+
if (err)
104+
{
105+
if (out_irq_level)
106+
{
107+
rt_spin_unlock_irqrestore(&hwlock->lock, *out_irq_level);
108+
}
109+
else
110+
{
111+
rt_spin_unlock(&hwlock->lock);
112+
}
113+
}
114+
115+
rt_hw_dmb();
116+
117+
return err;
118+
}
119+
120+
rt_err_t rt_hwspin_lock_timeout_raw(struct rt_hwspinlock *hwlock,
121+
rt_uint32_t timeout_ms, rt_ubase_t *out_irq_level)
122+
{
123+
rt_err_t err;
124+
rt_tick_t timeout = rt_tick_get() + rt_tick_from_millisecond(timeout_ms);
125+
126+
for (;;)
127+
{
128+
err = rt_hwspin_trylock_raw(hwlock, out_irq_level);
129+
130+
if (err != -RT_EBUSY)
131+
{
132+
break;
133+
}
134+
135+
if (timeout < rt_tick_get())
136+
{
137+
return -RT_ETIMEOUT;
138+
}
139+
140+
if (hwlock->bank->ops->relax)
141+
{
142+
hwlock->bank->ops->relax(hwlock);
143+
}
144+
}
145+
146+
return err;
147+
}
148+
149+
void rt_hwspin_unlock_raw(struct rt_hwspinlock *hwlock,
150+
rt_ubase_t *out_irq_level)
151+
{
152+
if (!hwlock)
153+
{
154+
return;
155+
}
156+
157+
rt_hw_dmb();
158+
159+
hwlock->bank->ops->unlock(hwlock);
160+
161+
if (out_irq_level)
162+
{
163+
rt_spin_unlock_irqrestore(&hwlock->lock, *out_irq_level);
164+
}
165+
else
166+
{
167+
rt_spin_unlock(&hwlock->lock);
168+
}
169+
}
170+
171+
static struct rt_hwspinlock *hwspinlock_get(struct rt_hwspinlock_bank *bank, int id)
172+
{
173+
struct rt_hwspinlock *hwlock = RT_NULL;
174+
175+
if (bank)
176+
{
177+
int offset = id - bank->base_id;
178+
179+
if (!bank->locks[offset].used)
180+
{
181+
hwlock = &bank->locks[offset];
182+
}
183+
}
184+
else
185+
{
186+
rt_list_for_each_entry(bank, &hwspinlock_bank_nodes, list)
187+
{
188+
hwlock = rt_err_ptr(-RT_EBUSY);
189+
190+
for (int i = 0; i < bank->locks_nr; ++i)
191+
{
192+
if (!bank->locks[i].used)
193+
{
194+
hwlock = &bank->locks[i];
195+
goto _found;
196+
}
197+
}
198+
}
199+
}
200+
201+
_found:
202+
if (!rt_is_err_or_null(hwlock))
203+
{
204+
hwlock->used = RT_TRUE;
205+
rt_ref_get(&hwlock->bank->ref);
206+
}
207+
208+
return hwlock;
209+
}
210+
211+
struct rt_hwspinlock *rt_hwspinlock_get(void)
212+
{
213+
struct rt_hwspinlock *lock;
214+
215+
rt_spin_lock(&hwspinlock_ops_lock);
216+
217+
lock = hwspinlock_get(RT_NULL, -1);
218+
219+
rt_spin_unlock(&hwspinlock_ops_lock);
220+
221+
return lock;
222+
}
223+
224+
struct rt_hwspinlock *rt_hwspinlock_get_by_index(struct rt_device *dev, int index)
225+
{
226+
return rt_ofw_get_hwspinlock_by_index(dev->ofw_node, index);
227+
}
228+
229+
struct rt_hwspinlock *rt_hwspinlock_get_by_name(struct rt_device *dev, const char *name)
230+
{
231+
return rt_ofw_get_hwspinlock_by_name(dev->ofw_node, name);
232+
}
233+
234+
static void hwspinlock_release(struct rt_ref *r)
235+
{
236+
struct rt_hwspinlock_bank *bank = rt_container_of(r, struct rt_hwspinlock_bank, ref);
237+
238+
LOG_E("%s is release", rt_dm_dev_get_name(bank->dev));
239+
(void)bank;
240+
241+
RT_ASSERT(0);
242+
}
243+
244+
void rt_hwspinlock_put(struct rt_hwspinlock *hwlock)
245+
{
246+
if (hwlock)
247+
{
248+
rt_spin_lock(&hwspinlock_ops_lock);
249+
hwlock->used = RT_FALSE;
250+
rt_spin_unlock(&hwspinlock_ops_lock);
251+
252+
rt_ref_put(&hwlock->bank->ref, &hwspinlock_release);
253+
}
254+
}
255+
256+
struct rt_hwspinlock *rt_ofw_get_hwspinlock_by_index(struct rt_ofw_node *np, int index)
257+
{
258+
rt_err_t err;
259+
struct rt_ofw_node *bank_np;
260+
struct rt_ofw_cell_args args;
261+
struct rt_hwspinlock *lock;
262+
struct rt_hwspinlock_bank *bank;
263+
264+
if (!np || index < 0)
265+
{
266+
return rt_err_ptr(-RT_EINVAL);
267+
}
268+
269+
err = rt_ofw_parse_phandle_cells(np, "hwlocks", "#hwlock-cells", index, &args);
270+
271+
if (err)
272+
{
273+
return rt_err_ptr(err);
274+
}
275+
276+
bank_np = args.data;
277+
278+
if (!rt_ofw_data(bank_np))
279+
{
280+
rt_platform_ofw_request(bank_np);
281+
}
282+
283+
rt_spin_lock(&hwspinlock_ops_lock);
284+
285+
bank = rt_ofw_data(bank_np);
286+
rt_ofw_node_put(bank_np);
287+
288+
if (!bank || args.args_count != 1)
289+
{
290+
lock = rt_err_ptr(-RT_ENOSYS);
291+
}
292+
else
293+
{
294+
lock = hwspinlock_get(bank, bank->base_id + args.args[0]);
295+
}
296+
297+
rt_spin_unlock(&hwspinlock_ops_lock);
298+
299+
return lock;
300+
}
301+
302+
struct rt_hwspinlock *rt_ofw_get_hwspinlock_by_name(struct rt_ofw_node *np, const char *name)
303+
{
304+
int index;
305+
306+
if (!np || !name)
307+
{
308+
return rt_err_ptr(-RT_EINVAL);
309+
}
310+
311+
index = rt_ofw_prop_index_of_string(np, "hwlock-names", name);
312+
313+
if (index < 0)
314+
{
315+
return rt_err_ptr(index);
316+
}
317+
318+
return rt_ofw_get_hwspinlock_by_index(np, index);
319+
}

0 commit comments

Comments
 (0)