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