1 /*
2 * Copyright (c) 2024, Texas Instruments Incorporated
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/__assert.h>
9 #include <kernel/zephyr/dpl/dpl.h>
10 #include <ti/drivers/dpl/SemaphoreP.h>
11
12 /*
13 * Zephyr kernel object pools:
14 *
15 * This bit of code enables the simplelink host driver, which assumes dynamic
16 * allocation of kernel objects (semaphores, mutexes, hwis), to be
17 * more easily ported to Zephyr (which supports static allocation).
18 *
19 * It leverages the Zephyr memory slab, enabling us to define a semaphore
20 * object pool for use by the SimpleLink host driver.
21 */
22 #define DPL_MAX_SEMAPHORES 14 /* (user.h:MAX_CONCURRENT_ACTIONS+4) = 14 */
23 K_MEM_SLAB_DEFINE(sem_slab, sizeof(struct k_sem), DPL_MAX_SEMAPHORES, MEM_ALIGN);
24
dpl_sem_pool_alloc()25 static struct k_sem *dpl_sem_pool_alloc()
26 {
27 struct k_sem *sem_ptr = NULL;
28
29 if (k_mem_slab_alloc(&sem_slab, (void **)&sem_ptr, K_NO_WAIT) < 0)
30 {
31 /*
32 * We assert, as this is a logic error, due to a change in #
33 * of semaphores needed by the simplelink driver. In that case,
34 * the sem pool must be increased programmatically to match.
35 */
36 __ASSERT(0, "Increase size of DPL semaphore pool");
37 }
38 return sem_ptr;
39 }
40
dpl_sem_pool_free(struct k_sem * sem)41 static SemaphoreP_Status dpl_sem_pool_free(struct k_sem *sem)
42 {
43 k_mem_slab_free(&sem_slab, (void **)&sem);
44
45 return SemaphoreP_OK;
46 }
47
48 /* timeout comes in and out in ticks */
dpl_convert_timeout(uint32_t timeout)49 static k_timeout_t dpl_convert_timeout(uint32_t timeout)
50 {
51 switch (timeout)
52 {
53 case SemaphoreP_NO_WAIT:
54 return K_NO_WAIT;
55 case SemaphoreP_WAIT_FOREVER:
56 return K_FOREVER;
57 default:
58 return K_TICKS(timeout);
59 }
60 }
61
SemaphoreP_create(unsigned int count,SemaphoreP_Params * params)62 SemaphoreP_Handle SemaphoreP_create(unsigned int count, SemaphoreP_Params *params)
63 {
64 unsigned int limit = UINT_MAX;
65 struct k_sem *sem;
66
67 if (params)
68 {
69 limit = (params->mode == SemaphoreP_Mode_BINARY) ? 1 : UINT_MAX;
70 }
71
72 sem = dpl_sem_pool_alloc();
73 if (sem)
74 {
75 k_sem_init(sem, count, limit);
76 }
77
78 return (SemaphoreP_Handle)sem;
79 }
80
SemaphoreP_createBinary(unsigned int count)81 SemaphoreP_Handle SemaphoreP_createBinary(unsigned int count)
82 {
83 SemaphoreP_Params params;
84
85 SemaphoreP_Params_init(¶ms);
86 params.mode = SemaphoreP_Mode_BINARY;
87
88 return (SemaphoreP_create(count, ¶ms));
89 }
90
SemaphoreP_delete(SemaphoreP_Handle handle)91 void SemaphoreP_delete(SemaphoreP_Handle handle)
92 {
93 k_sem_reset((struct k_sem *)handle);
94
95 (void)dpl_sem_pool_free((struct k_sem *)handle);
96 }
97
SemaphoreP_Params_init(SemaphoreP_Params * params)98 void SemaphoreP_Params_init(SemaphoreP_Params *params)
99 {
100 params->mode = SemaphoreP_Mode_COUNTING;
101 params->callback = NULL;
102 }
103
104 /*
105 * The SimpleLink driver calls this function with a timeout of 0 to "clear"
106 * the SyncObject, rather than calling dpl_SyncObjClear() directly.
107 * See: <simplelinksdk>/source/ti/drivers/net/wifi/source/driver.h
108 * #define SL_DRV_SYNC_OBJ_CLEAR(pObj)
109 * (void)sl_SyncObjWait(pObj,SL_OS_NO_WAIT);
110 *
111 * So, we claim (via simplelink driver code inspection), that SyncObjWait
112 * will *only* be called with timeout == 0 if the intention is to clear the
113 * semaphore: in that case, we just call k_sem_reset.
114 */
SemaphoreP_pend(SemaphoreP_Handle handle,uint32_t timeout)115 SemaphoreP_Status SemaphoreP_pend(SemaphoreP_Handle handle, uint32_t timeout)
116 {
117 int retval;
118
119 if (0 == timeout)
120 {
121 k_sem_reset((struct k_sem *)handle);
122 retval = SemaphoreP_OK;
123 }
124 else
125 {
126 retval = k_sem_take((struct k_sem *)handle, dpl_convert_timeout(timeout));
127 __ASSERT_NO_MSG(retval != -EBUSY);
128 retval = (retval >= 0) ? SemaphoreP_OK : SemaphoreP_TIMEOUT;
129 }
130 return retval;
131 }
132
SemaphoreP_post(SemaphoreP_Handle handle)133 void SemaphoreP_post(SemaphoreP_Handle handle)
134 {
135 k_sem_give((struct k_sem *)handle);
136 }
137
SemaphoreP_construct(SemaphoreP_Struct * handle,unsigned int count,SemaphoreP_Params * params)138 SemaphoreP_Handle SemaphoreP_construct(SemaphoreP_Struct *handle, unsigned int count, SemaphoreP_Params *params)
139 {
140 unsigned int limit = UINT_MAX;
141 struct k_sem *sem;
142
143 if (params)
144 {
145 limit = (params->mode == SemaphoreP_Mode_BINARY) ? 1 : UINT_MAX;
146 }
147
148 sem = (struct k_sem *)handle;
149 if (sem)
150 {
151 k_sem_init(sem, count, limit);
152 }
153
154 return (SemaphoreP_Handle)sem;
155 }
156
SemaphoreP_constructBinary(SemaphoreP_Struct * handle,unsigned int count)157 SemaphoreP_Handle SemaphoreP_constructBinary(SemaphoreP_Struct *handle, unsigned int count)
158 {
159 SemaphoreP_Params params;
160
161 SemaphoreP_Params_init(¶ms);
162 params.mode = SemaphoreP_Mode_BINARY;
163
164 return (SemaphoreP_construct(handle, count, ¶ms));
165 }
166
SemaphoreP_destruct(SemaphoreP_Struct * semP)167 void SemaphoreP_destruct(SemaphoreP_Struct *semP)
168 {
169 struct k_sem *sem;
170
171 sem = (struct k_sem *)semP->data;
172 if (sem)
173 {
174 k_sem_reset(sem);
175 }
176 }
177