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(&params);
86     params.mode = SemaphoreP_Mode_BINARY;
87 
88     return (SemaphoreP_create(count, &params));
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(&params);
162     params.mode = SemaphoreP_Mode_BINARY;
163 
164     return (SemaphoreP_construct(handle, count, &params));
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