zephyr/subsys/bluetooth/controller/util/mayfly.c
Vinayak Kariappa Chettimada 87fe440f01 Bluetooth: controller: Prepare to introduce LL split architecture
Preparation to introduce the Upper Link Layer (ULL) and
Lower Link Layer (LLL) split architecture.

- Move SoC dependent HAL to vendor specific folder.
- Preparation to split data structures into ULL and LLL
  types.
- Added more role and state conditional compilations.
- Added some work-in-progress implementation of advertising
  extensions, will be used as inspiration in the new split
  architecture work.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
2019-01-07 13:42:01 +01:00

333 lines
6.8 KiB
C

/*
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stddef.h>
#include <zephyr/types.h>
#include <misc/printk.h>
#include "memq.h"
#include "mayfly.h"
static struct {
memq_link_t *head;
memq_link_t *tail;
u8_t enable_req;
u8_t enable_ack;
u8_t disable_req;
u8_t disable_ack;
} mft[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT];
static memq_link_t mfl[MAYFLY_CALLEE_COUNT][MAYFLY_CALLER_COUNT];
static u8_t mfp[MAYFLY_CALLEE_COUNT];
#if defined(CONFIG_MAYFLY_UT)
static u8_t _state;
#endif /* CONFIG_MAYFLY_UT */
void mayfly_init(void)
{
u8_t callee_id;
callee_id = MAYFLY_CALLEE_COUNT;
while (callee_id--) {
u8_t caller_id;
caller_id = MAYFLY_CALLER_COUNT;
while (caller_id--) {
memq_init(&mfl[callee_id][caller_id],
&mft[callee_id][caller_id].head,
&mft[callee_id][caller_id].tail);
}
}
}
void mayfly_enable(u8_t caller_id, u8_t callee_id, u8_t enable)
{
if (enable) {
if (mft[callee_id][caller_id].enable_req ==
mft[callee_id][caller_id].enable_ack) {
mft[callee_id][caller_id].enable_req++;
}
mayfly_enable_cb(caller_id, callee_id, enable);
} else {
if (mft[callee_id][caller_id].disable_req ==
mft[callee_id][caller_id].disable_ack) {
mft[callee_id][caller_id].disable_req++;
mayfly_pend(caller_id, callee_id);
}
}
}
u32_t mayfly_enqueue(u8_t caller_id, u8_t callee_id, u8_t chain,
struct mayfly *m)
{
u8_t state;
u8_t ack;
chain = chain || !mayfly_prio_is_equal(caller_id, callee_id) ||
!mayfly_is_enabled(caller_id, callee_id) ||
(mft[callee_id][caller_id].disable_req !=
mft[callee_id][caller_id].disable_ack);
/* shadow the ack */
ack = m->_ack;
/* already in queue */
state = (m->_req - ack) & 0x03;
if (state != 0) {
if (chain) {
if (state != 1) {
/* mark as ready in queue */
m->_req = ack + 1;
goto mayfly_enqueue_pend;
}
/* already ready */
return 1;
}
/* mark as done in queue, and fall thru */
m->_req = ack + 2;
}
/* handle mayfly(s) that can be inline */
if (!chain) {
/* call fp */
m->fp(m->param);
return 0;
}
/* new, add as ready in the queue */
m->_req = ack + 1;
memq_enqueue(m->_link, m, &mft[callee_id][caller_id].tail);
mayfly_enqueue_pend:
/* set mayfly callee pending */
mfp[callee_id] = 1;
/* pend the callee for execution */
mayfly_pend(caller_id, callee_id);
return 0;
}
static void dequeue(u8_t callee_id, u8_t caller_id, memq_link_t *link,
struct mayfly *m)
{
u8_t req;
req = m->_req;
if (((req - m->_ack) & 0x03) != 1) {
u8_t ack;
#if defined(CONFIG_MAYFLY_UT)
u32_t mayfly_ut_run_test(void);
void mayfly_ut_mfy(void *param);
if (_state && m->fp == mayfly_ut_mfy) {
static u8_t single;
if (!single) {
single = 1;
mayfly_ut_run_test();
}
}
#endif /* CONFIG_MAYFLY_UT */
/* dequeue mayfly struct */
memq_dequeue(mft[callee_id][caller_id].tail,
&mft[callee_id][caller_id].head,
0);
/* release link into dequeued mayfly struct */
m->_link = link;
/* reset mayfly state to idle */
ack = m->_ack;
m->_ack = req;
/* re-insert, if re-pended by interrupt */
if (((m->_req - ack) & 0x03) == 1) {
#if defined(CONFIG_MAYFLY_UT)
printk("%s: RACE\n", __func__);
#endif /* CONFIG_MAYFLY_UT */
m->_ack = ack;
memq_enqueue(link, m, &mft[callee_id][callee_id].tail);
}
}
}
void mayfly_run(u8_t callee_id)
{
u8_t disable = 0U;
u8_t enable = 0U;
u8_t caller_id;
if (!mfp[callee_id]) {
return;
}
mfp[callee_id] = 1;
/* iterate through each caller queue to this callee_id */
caller_id = MAYFLY_CALLER_COUNT;
while (caller_id--) {
memq_link_t *link;
struct mayfly *m = 0;
/* fetch mayfly in callee queue, if any */
link = memq_peek(mft[callee_id][caller_id].head,
mft[callee_id][caller_id].tail,
(void **)&m);
while (link) {
u8_t state;
#if defined(CONFIG_MAYFLY_UT)
_state = 0;
#endif /* CONFIG_MAYFLY_UT */
/* execute work if ready */
state = (m->_req - m->_ack) & 0x03;
if (state == 1) {
#if defined(CONFIG_MAYFLY_UT)
_state = 1;
#endif /* CONFIG_MAYFLY_UT */
/* mark mayfly as ran */
m->_ack--;
/* call the mayfly function */
m->fp(m->param);
}
/* dequeue if not re-pended */
dequeue(callee_id, caller_id, link, m);
/* fetch next mayfly in callee queue, if any */
link = memq_peek(mft[callee_id][caller_id].head,
mft[callee_id][caller_id].tail,
(void **)&m);
/* yield out of mayfly_run if a mayfly function was
* called.
*/
if (state == 1) {
/* pend callee (tailchain) if mayfly queue is
* not empty or all caller queues are not
* processed.
*/
if (caller_id || link) {
mayfly_pend(callee_id, callee_id);
return;
}
}
}
if (mft[callee_id][caller_id].disable_req !=
mft[callee_id][caller_id].disable_ack) {
disable = 1U;
mft[callee_id][caller_id].disable_ack =
mft[callee_id][caller_id].disable_req;
}
if (mft[callee_id][caller_id].enable_req !=
mft[callee_id][caller_id].enable_ack) {
enable = 1U;
mft[callee_id][caller_id].enable_ack =
mft[callee_id][caller_id].enable_req;
}
}
if (disable && !enable) {
mayfly_enable_cb(callee_id, callee_id, 0);
}
}
#if defined(CONFIG_MAYFLY_UT)
#define MAYFLY_CALL_ID_CALLER MAYFLY_CALL_ID_0
#define MAYFLY_CALL_ID_CALLEE MAYFLY_CALL_ID_2
void mayfly_ut_mfy(void *param)
{
printk("%s: ran.\n", __func__);
(*((u32_t *)param))++;
}
void mayfly_ut_test(void *param)
{
static u32_t *count;
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, mayfly_ut_mfy};
u32_t err;
printk("%s: req= %u, ack= %u\n", __func__, mfy._req, mfy._ack);
if (param) {
count = param;
}
mfy.param = count;
err = mayfly_enqueue(MAYFLY_CALL_ID_CALLER, MAYFLY_CALL_ID_CALLEE, 1,
&mfy);
if (err) {
printk("%s: FAILED (%u).\n", __func__, err);
} else {
printk("%s: SUCCESS.\n", __func__);
}
}
u32_t mayfly_ut_run_test(void)
{
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, NULL, mayfly_ut_test};
u32_t err;
printk("%s: req= %u, ack= %u\n", __func__, mfy._req, mfy._ack);
err = mayfly_enqueue(MAYFLY_CALL_ID_CALLEE, MAYFLY_CALL_ID_CALLER, 0,
&mfy);
if (err) {
printk("%s: FAILED.\n", __func__);
return err;
}
printk("%s: SUCCESS.\n", __func__);
return 0;
}
u32_t mayfly_ut(void)
{
static u32_t count;
static memq_link_t link;
static struct mayfly mfy = {0, 0, &link, &count, mayfly_ut_test};
u32_t err;
printk("%s: req= %u, ack= %u\n", __func__, mfy._req, mfy._ack);
err = mayfly_enqueue(MAYFLY_CALL_ID_PROGRAM, MAYFLY_CALL_ID_CALLER, 0,
&mfy);
if (err) {
printk("%s: FAILED.\n", __func__);
return err;
}
printk("%s: count = %u.\n", __func__, count);
printk("%s: SUCCESS.\n", __func__);
return 0;
}
#endif /* CONFIG_MAYFLY_UT */