blob: 521b5618b5f5c66dbbb477c071229d7b14fa9722 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-09-23 GuEe-GUI first version
*/
#ifndef __HWSPINLOCK_DM_H__
#define __HWSPINLOCK_DM_H__
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <drivers/misc.h>
#include <ref.h>
/**
* @brief Hardware spinlock instance
*
* Represents a single hardware spinlock managed by a bank. Each lock
* maintains a local software spinlock to protect internal state and a
* usage flag to indicate whether it has been allocated to clients.
*/
struct rt_hwspinlock
{
struct rt_hwspinlock_bank *bank;
struct rt_spinlock lock; /**< Local software spinlock to guard structure access */
rt_bool_t used; /**< Indicates whether this lock is currently in use */
void *priv; /**< Driver-specific private data */
};
/**
* @brief Hardware spinlock operations
*
* A hardware spinlock driver must provide these low-level operations.
* trylock() performs a non-blocking acquire. relax() is called inside
* busy-wait loops to reduce power usage or yield the bus.
*/
struct rt_hwspinlock_ops
{
/**
* @brief Attempt to acquire the hardware spinlock (non-blocking)
*
* Should immediately return RT_EOK on success or -RT_EBUSY if the lock
* is already taken by another CPU or hardware requester.
*/
rt_err_t (*trylock)(struct rt_hwspinlock *hwlock);
/**
* @brief Release the hardware spinlock
*/
void (*unlock)(struct rt_hwspinlock *hwlock);
/**
* @brief Relax operation called during spinning
*
* Typically implemented using power-saving instructions (e.g., WFE),
* yielding the CPU, or other hardware-supported wait mechanisms.
*/
void (*relax)(struct rt_hwspinlock *hwlock);
};
/**
* @brief Hardware spinlock bank
*
* Represents a group of hardware spinlocks exported by the same device
* or hardware module. A bank is registered globally so that locks can be
* retrieved by index, name, or device tree bindings.
*/
struct rt_hwspinlock_bank
{
rt_list_t list;
struct rt_ref ref;
struct rt_device *dev;
const struct rt_hwspinlock_ops *ops;
int base_id; /**< Global base ID used to calculate lock identifiers */
rt_size_t locks_nr; /**< Number of hardware spinlocks in this bank */
/**
* @brief Array of hardware spinlock instances
*
* Implemented as a flexible array member. Memory is allocated using
* hwspinlock_bank_alloc(), ensuring space for all lock structures.
*/
struct rt_hwspinlock locks[];
};
/**
* @brief Allocate a hardware spinlock bank with a given number of locks
*
* The allocation includes both the bank structure and the flexible array
* of hardware spinlock objects.
*
* @param obj The object pointer used to store the bank
* @param locks_nr Number of hardware spinlocks to allocate
*
* @return Pointer to the allocated memory or NULL on failure
*/
#define hwspinlock_bank_alloc(obj, locks_nr) \
rt_calloc(1, sizeof(typeof(*obj)) + sizeof(struct rt_hwspinlock) * (locks_nr))
/**
* @brief Compute the global hardware spinlock ID
*
* The global ID is calculated as:
* bank->base_id + index
* where the index is derived from the hardware spinlock's position inside
* the bank->locks array.
*
* @param hwlock Pointer to a hardware spinlock
*
* @return The global lock identifier
*/
rt_inline int hwspinlock_find_id(struct rt_hwspinlock *hwlock)
{
return hwlock->bank->base_id + (hwlock - &hwlock->bank->locks[0]);
}
#endif /* __HWSPINLOCK_DM_H__ */
|