1 /*
2  * Copyright (c) 2017, 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,\
24 		  MEM_ALIGN);
25 
dpl_sem_pool_alloc()26 static struct k_sem *dpl_sem_pool_alloc()
27 {
28 	struct k_sem *sem_ptr = NULL;
29 
30 	if (k_mem_slab_alloc(&sem_slab, (void **)&sem_ptr, K_NO_WAIT) < 0) {
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 	case SemaphoreP_NO_WAIT:
53 		return K_NO_WAIT;
54 	case SemaphoreP_WAIT_FOREVER:
55 		return K_FOREVER;
56 	default:
57 		return K_TICKS(timeout);
58 	}
59 }
60 
61 
SemaphoreP_create(unsigned int count,SemaphoreP_Params * params)62 SemaphoreP_Handle SemaphoreP_create(unsigned int count,
63 				    SemaphoreP_Params *params)
64 {
65 	unsigned int limit = UINT_MAX;
66 	struct k_sem *sem;
67 
68 	if (params) {
69 		limit = (params->mode == SemaphoreP_Mode_BINARY) ?
70 			1 : UINT_MAX;
71 	}
72 
73 	sem = dpl_sem_pool_alloc();
74 	if (sem) {
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 
91 
SemaphoreP_delete(SemaphoreP_Handle handle)92 void SemaphoreP_delete(SemaphoreP_Handle handle)
93 {
94 	k_sem_reset((struct k_sem *)handle);
95 
96 	(void)dpl_sem_pool_free((struct k_sem *)handle);
97 }
98 
SemaphoreP_Params_init(SemaphoreP_Params * params)99 void SemaphoreP_Params_init(SemaphoreP_Params *params)
100 {
101 	params->mode = SemaphoreP_Mode_COUNTING;
102 	params->callback = NULL;
103 }
104 
105 /*
106  * The SimpleLink driver calls this function with a timeout of 0 to "clear"
107  * the SyncObject, rather than calling dpl_SyncObjClear() directly.
108  * See: <simplelinksdk>/source/ti/drivers/net/wifi/source/driver.h
109  *  #define SL_DRV_SYNC_OBJ_CLEAR(pObj)
110  *	    (void)sl_SyncObjWait(pObj,SL_OS_NO_WAIT);
111  *
112  * So, we claim (via simplelink driver code inspection), that SyncObjWait
113  * will *only* be called with timeout == 0 if the intention is to clear the
114  * semaphore: in that case, we just call k_sem_reset.
115  */
SemaphoreP_pend(SemaphoreP_Handle handle,uint32_t timeout)116 SemaphoreP_Status SemaphoreP_pend(SemaphoreP_Handle handle, uint32_t timeout)
117 {
118 	int retval;
119 
120 	if (0 == timeout) {
121 		k_sem_reset((struct k_sem *)handle);
122 		retval = SemaphoreP_OK;
123 	} else {
124 		retval = k_sem_take((struct k_sem *)handle,
125 				    dpl_convert_timeout(timeout));
126 		__ASSERT_NO_MSG(retval != -EBUSY);
127 		retval = (retval >= 0) ? SemaphoreP_OK : SemaphoreP_TIMEOUT;
128 	}
129 	return retval;
130 }
131 
SemaphoreP_post(SemaphoreP_Handle handle)132 void SemaphoreP_post(SemaphoreP_Handle handle)
133 {
134 	k_sem_give((struct k_sem *)handle);
135 }
136 
SemaphoreP_construct(SemaphoreP_Struct * handle,unsigned int count,SemaphoreP_Params * params)137 SemaphoreP_Handle SemaphoreP_construct(SemaphoreP_Struct *handle,
138                     unsigned int count, SemaphoreP_Params *params)
139 {
140     unsigned int limit = UINT_MAX;
141     struct k_sem *sem;
142 
143     if (params) {
144         limit = (params->mode == SemaphoreP_Mode_BINARY) ?
145             1 : UINT_MAX;
146     }
147 
148     sem = (struct k_sem *)handle;
149     if (sem) {
150         k_sem_init(sem, count, limit);
151     }
152 
153     return (SemaphoreP_Handle)sem;
154 }
155 
SemaphoreP_constructBinary(SemaphoreP_Struct * handle,unsigned int count)156 SemaphoreP_Handle SemaphoreP_constructBinary(SemaphoreP_Struct *handle, unsigned int count) {
157     SemaphoreP_Params params;
158 
159     SemaphoreP_Params_init(&params);
160     params.mode = SemaphoreP_Mode_BINARY;
161 
162     return (SemaphoreP_construct(handle, count, &params));
163 }
164 
SemaphoreP_destruct(SemaphoreP_Struct * semP)165 void SemaphoreP_destruct(SemaphoreP_Struct *semP) {
166     struct k_sem *sem;
167 
168     sem = (struct k_sem *)semP->data;
169     if (sem) {
170         k_sem_reset(sem);
171     }
172 }
173