1818#include  "hal/ticker.h" 
1919
2020#include  "util/util.h" 
21+ #include  "util/mem.h" 
2122#include  "util/memq.h" 
23+ #include  "util/mfifo.h" 
2224
2325#include  "ticker/ticker.h" 
2426
@@ -75,6 +77,46 @@ static inline bool isr_rx_ci_tgta_check(struct lll_adv *lll,
7577static  inline  bool  isr_rx_ci_adva_check (struct  pdu_adv  * adv ,
7678					struct  pdu_adv  * ci );
7779
80+ #if  defined(CONFIG_BT_CTLR_ADV_EXT )
81+ #define  PAYLOAD_FRAG_COUNT    ((CONFIG_BT_CTLR_ADV_DATA_LEN_MAX + \
82+ 			       PDU_AC_PAYLOAD_SIZE_MAX - 1) / \
83+ 			      PDU_AC_PAYLOAD_SIZE_MAX)
84+ #define  BT_CTLR_ADV_AUX_SET   CONFIG_BT_CTLR_ADV_AUX_SET
85+ #if  defined(CONFIG_BT_CTLR_ADV_PERIODIC )
86+ #define  BT_CTLR_ADV_SYNC_SET  CONFIG_BT_CTLR_ADV_SYNC_SET
87+ #else  /* !CONFIG_BT_CTLR_ADV_PERIODIC */ 
88+ #define  BT_CTLR_ADV_SYNC_SET  0
89+ #endif  /* !CONFIG_BT_CTLR_ADV_PERIODIC */ 
90+ #else 
91+ #define  PAYLOAD_FRAG_COUNT    1
92+ #define  BT_CTLR_ADV_AUX_SET   0
93+ #define  BT_CTLR_ADV_SYNC_SET  0
94+ #endif 
95+ 
96+ #define  PDU_MEM_SIZE        MROUND(PDU_AC_LL_HEADER_SIZE + \
97+ 				  PDU_AC_PAYLOAD_SIZE_MAX)
98+ #define  PDU_MEM_COUNT_MIN   (BT_CTLR_ADV_SET + \
99+ 			    (BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT) + \
100+ 			    (BT_CTLR_ADV_AUX_SET * PAYLOAD_FRAG_COUNT) + \
101+ 			    (BT_CTLR_ADV_SYNC_SET * PAYLOAD_FRAG_COUNT))
102+ #define  PDU_MEM_FIFO_COUNT  ((BT_CTLR_ADV_SET * PAYLOAD_FRAG_COUNT * 2) + \
103+ 			    (CONFIG_BT_CTLR_ADV_DATA_BUF_MAX * \
104+ 			     PAYLOAD_FRAG_COUNT))
105+ #define  PDU_MEM_COUNT       (PDU_MEM_COUNT_MIN + PDU_MEM_FIFO_COUNT)
106+ #define  PDU_POOL_SIZE       (PDU_MEM_SIZE * PDU_MEM_COUNT)
107+ 
108+ /* Free AD data PDU buffer pool */ 
109+ static  struct  {
110+ 	void  * free ;
111+ 	uint8_t  pool [PDU_POOL_SIZE ];
112+ } mem_pdu ;
113+ 
114+ /* FIFO to return stale AD data PDU buffers from LLL to thread context */ 
115+ static  MFIFO_DEFINE (pdu_free , sizeof (void  * ), PDU_MEM_FIFO_COUNT );
116+ 
117+ /* Semaphore to wakeup thread waiting for free AD data PDU buffers */ 
118+ static  struct  k_sem  sem_pdu_free ;
119+ 
78120int  lll_adv_init (void )
79121{
80122	int  err ;
@@ -99,6 +141,166 @@ int lll_adv_reset(void)
99141	return  0 ;
100142}
101143
144+ int  lll_adv_data_init (struct  lll_adv_pdu  * pdu )
145+ {
146+ 	struct  pdu_adv  * p ;
147+ 
148+ 	p  =  mem_acquire (& mem_pdu .free );
149+ 	if  (!p ) {
150+ 		return  - ENOMEM ;
151+ 	}
152+ 
153+ 	pdu -> pdu [0 ] =  (void  * )p ;
154+ 
155+ 	return  0 ;
156+ }
157+ 
158+ int  lll_adv_data_reset (struct  lll_adv_pdu  * pdu )
159+ {
160+ 	/* NOTE: this function is used on HCI reset to mem-zero the structure 
161+ 	 *       members that otherwise was zero-ed by the architecture 
162+ 	 *       startup code that zero-ed the .bss section. 
163+ 	 *       pdu[0] element in the array is not initialized as subsequent 
164+ 	 *       call to lll_adv_data_init will allocate a PDU buffer and 
165+ 	 *       assign that. 
166+ 	 */ 
167+ 
168+ 	pdu -> first  =  0U ;
169+ 	pdu -> last  =  0U ;
170+ 	pdu -> pdu [1 ] =  NULL ;
171+ 
172+ 	return  0 ;
173+ }
174+ 
175+ int  lll_adv_data_release (struct  lll_adv_pdu  * pdu )
176+ {
177+ 	uint8_t  last ;
178+ 	void  * p ;
179+ 
180+ 	last  =  pdu -> last ;
181+ 	p  =  pdu -> pdu [last ];
182+ 	pdu -> pdu [last ] =  NULL ;
183+ 	mem_release (p , & mem_pdu .free );
184+ 
185+ 	last ++ ;
186+ 	if  (last  ==  DOUBLE_BUFFER_SIZE ) {
187+ 		last  =  0U ;
188+ 	}
189+ 	p  =  pdu -> pdu [last ];
190+ 	if  (p ) {
191+ 		pdu -> pdu [last ] =  NULL ;
192+ 		mem_release (p , & mem_pdu .free );
193+ 	}
194+ 
195+ 	return  0 ;
196+ }
197+ 
198+ struct  pdu_adv  * lll_adv_pdu_alloc (struct  lll_adv_pdu  * pdu , uint8_t  * idx )
199+ {
200+ 	uint8_t  first , last ;
201+ 	struct  pdu_adv  * p ;
202+ 	int  err ;
203+ 
204+ 	first  =  pdu -> first ;
205+ 	last  =  pdu -> last ;
206+ 	if  (first  ==  last ) {
207+ 		last ++ ;
208+ 		if  (last  ==  DOUBLE_BUFFER_SIZE ) {
209+ 			last  =  0U ;
210+ 		}
211+ 	} else  {
212+ 		uint8_t  first_latest ;
213+ 
214+ 		pdu -> last  =  first ;
215+ 		/* FIXME: Ensure that data is synchronized so that an ISR 
216+ 		 *        vectored, after pdu->last has been updated, does 
217+ 		 *        access the latest value. __DSB() is used in ARM 
218+ 		 *        Cortex M4 architectures. Use appropriate 
219+ 		 *        instructions on other platforms. 
220+ 		 * 
221+ 		 *        cpu_dsb(); 
222+ 		 */ 
223+ 		first_latest  =  pdu -> first ;
224+ 		if  (first_latest  !=  first ) {
225+ 			last ++ ;
226+ 			if  (last  ==  DOUBLE_BUFFER_SIZE ) {
227+ 				last  =  0U ;
228+ 			}
229+ 		}
230+ 	}
231+ 
232+ 	* idx  =  last ;
233+ 
234+ 	p  =  (void  * )pdu -> pdu [last ];
235+ 	if  (p ) {
236+ 		return  p ;
237+ 	}
238+ 
239+ 	p  =  MFIFO_DEQUEUE_PEEK (pdu_free );
240+ 	if  (p ) {
241+ 		err  =  k_sem_take (& sem_pdu_free , K_NO_WAIT );
242+ 		LL_ASSERT (!err );
243+ 
244+ 		MFIFO_DEQUEUE (pdu_free );
245+ 		pdu -> pdu [last ] =  (void  * )p ;
246+ 
247+ 		return  p ;
248+ 	}
249+ 
250+ 	p  =  mem_acquire (& mem_pdu .free );
251+ 	if  (p ) {
252+ 		pdu -> pdu [last ] =  (void  * )p ;
253+ 
254+ 		return  p ;
255+ 	}
256+ 
257+ 	err  =  k_sem_take (& sem_pdu_free , K_FOREVER );
258+ 	LL_ASSERT (!err );
259+ 
260+ 	p  =  MFIFO_DEQUEUE (pdu_free );
261+ 	LL_ASSERT (p );
262+ 
263+ 	pdu -> pdu [last ] =  (void  * )p ;
264+ 
265+ 	return  p ;
266+ }
267+ 
268+ struct  pdu_adv  * lll_adv_pdu_latest_get (struct  lll_adv_pdu  * pdu ,
269+ 				       uint8_t  * is_modified )
270+ {
271+ 	uint8_t  first ;
272+ 
273+ 	first  =  pdu -> first ;
274+ 	if  (first  !=  pdu -> last ) {
275+ 		uint8_t  free_idx ;
276+ 		uint8_t  pdu_idx ;
277+ 		void  * p ;
278+ 
279+ 		if  (!MFIFO_ENQUEUE_IDX_GET (pdu_free , & free_idx )) {
280+ 			LL_ASSERT (false);
281+ 
282+ 			return  NULL ;
283+ 		}
284+ 
285+ 		pdu_idx  =  first ;
286+ 
287+ 		first  +=  1U ;
288+ 		if  (first  ==  DOUBLE_BUFFER_SIZE ) {
289+ 			first  =  0U ;
290+ 		}
291+ 		pdu -> first  =  first ;
292+ 		* is_modified  =  1U ;
293+ 
294+ 		p  =  pdu -> pdu [pdu_idx ];
295+ 		pdu -> pdu [pdu_idx ] =  NULL ;
296+ 
297+ 		MFIFO_BY_IDX_ENQUEUE (pdu_free , free_idx , p );
298+ 		k_sem_give (& sem_pdu_free );
299+ 	}
300+ 
301+ 	return  (void  * )pdu -> pdu [first ];
302+ }
303+ 
102304void  lll_adv_prepare (void  * param )
103305{
104306	struct  lll_prepare_param  * p  =  param ;
0 commit comments