diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index f80241425b3..ec9ba87c78b 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -145,7 +145,7 @@ static void reset(struct net_buf *buf, struct net_buf *evt) { struct bt_hci_evt_cc_status *ccst; - /** TODO */ + ctrl_reset(); ccst = cmd_complete(evt, sizeof(*ccst)); ccst->status = 0x00; diff --git a/subsys/bluetooth/controller/hci/hci_driver.c b/subsys/bluetooth/controller/hci/hci_driver.c index cafa1d50477..eff5fa94d28 100644 --- a/subsys/bluetooth/controller/hci/hci_driver.c +++ b/subsys/bluetooth/controller/hci/hci_driver.c @@ -43,6 +43,7 @@ #include "hal/rand.h" #include "hal/ccm.h" #include "hal/radio.h" +#include "hal/hal_rtc.h" #include "ll/ticker.h" #include "ll/ctrl_internal.h" #include "hci_internal.h" @@ -267,6 +268,9 @@ static int hci_driver_open(void) DEBUG_INIT(); + /* TODO: bind and use RNG driver */ + rand_init(_rand_context, sizeof(_rand_context)); + clk_k32 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME); if (!clk_k32) { return -ENODEV; @@ -274,6 +278,9 @@ static int hci_driver_open(void) clock_control_on(clk_k32, (void *)CLOCK_CONTROL_NRF5_K32SRC); + /* TODO: bind and use counter driver */ + rtc_init(); + _ticker_users[RADIO_TICKER_USER_ID_WORKER][0] = RADIO_TICKER_USER_WORKER_OPS; _ticker_users[RADIO_TICKER_USER_ID_JOB][0] = @@ -287,8 +294,6 @@ static int hci_driver_open(void) , RADIO_TICKER_USER_OPS, &_ticker_user_ops[0] ); - rand_init(_rand_context, sizeof(_rand_context)); - clk_m16 = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_M16SRC_DRV_NAME); if (!clk_m16) { return -ENODEV; diff --git a/subsys/bluetooth/controller/ll/ctrl.c b/subsys/bluetooth/controller/ll/ctrl.c index 788ee45c803..8287d389038 100644 --- a/subsys/bluetooth/controller/ll/ctrl.c +++ b/subsys/bluetooth/controller/ll/ctrl.c @@ -213,6 +213,7 @@ static struct { static uint16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 }; +static void common_init(void); static void ticker_success_assert(uint32_t status, void *params); static void event_inactive(uint32_t ticks_at_expire, uint32_t remainder, uint16_t lazy, void *context); @@ -271,6 +272,8 @@ static void reject_ind_ext_send(struct connection *conn, static void length_resp_send(struct connection *conn, uint16_t eff_rx_octets, uint16_t eff_tx_octets); +static uint32_t role_disable(uint8_t ticker_id_primary, + uint8_t ticker_id_stop); static void rx_fc_lock(uint16_t handle); /***************************************************************************** @@ -282,9 +285,7 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, uint16_t mem_size) { uint32_t retcode; - uint16_t packet_tx_ctrl_size; uint8_t *mem_radio_end; - void *link; /* intialise hf_clock device to use in prepare */ _radio.hf_clock = hf_clock; @@ -339,11 +340,9 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, (ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + (RADIO_ACPDU_SIZE_MAX + 1)) * rx_count_max); } - _radio.packet_rx_data_size = - ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + - (RADIO_ACPDU_SIZE_MAX + 1)); - _radio.packet_rx_data_count = - _radio.packet_rx_data_pool_size / _radio.packet_rx_data_size; + _radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN; + _radio.packet_rx_data_count = (_radio.packet_rx_data_pool_size / + _radio.packet_rx_data_size); /* initialise rx data pool memory */ _radio.pkt_rx_data_pool = mem_radio; @@ -356,10 +355,7 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, /* initialise tx ctrl pool memory */ _radio.pkt_tx_ctrl_pool = mem_radio; - packet_tx_ctrl_size = - ALIGN4(offsetof(struct radio_pdu_node_tx, pdu_data) + - offsetof(struct pdu_data, payload) + 27); - mem_radio += packet_tx_ctrl_size * PACKET_MEM_COUNT_TX_CTRL; + mem_radio += PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL; /* initialise tx data memory size and count */ _radio.packet_tx_data_size = @@ -381,6 +377,61 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, return (retcode + mem_size); } + /* enable connection handle based on-off flow control feature. + * This is a simple flow control to rx data only on one selected + * connection handle. + * TODO: replace this feature with host-to-controller flowcontrol + * implementation/design. + */ + _radio.fc_ena = 1; + + /* memory allocations */ + common_init(); + + return retcode; +} + +void ctrl_reset(void) +{ + uint16_t conn_handle; + + /* disable advertiser events */ + role_disable(RADIO_TICKER_ID_ADV, RADIO_TICKER_ID_ADV_STOP); + + /* disable oberver events */ + role_disable(RADIO_TICKER_ID_OBS, RADIO_TICKER_ID_OBS_STOP); + + /* disable connection events */ + for (conn_handle = 0; conn_handle < _radio.connection_count; + conn_handle++) { + role_disable(RADIO_TICKER_ID_FIRST_CONNECTION + conn_handle, + TICKER_NULL); + } + + /* reset controller context members */ + _radio.filter_enable_bitmask = 0; + _radio.nirk = 0; + _radio.advertiser.conn = NULL; + _radio.observer.conn = NULL; + _radio.packet_rx_data_size = PACKET_RX_DATA_SIZE_MIN; + _radio.packet_rx_data_count = (_radio.packet_rx_data_pool_size / + _radio.packet_rx_data_size); + _radio.packet_rx_last = 0; + _radio.packet_rx_acquire = 0; + _radio.link_rx_data_quota = _radio.packet_rx_count - 1; + _radio.packet_tx_first = 0; + _radio.packet_tx_last = 0; + _radio.packet_release_first = 0; + _radio.packet_release_last = 0; + + /* memory allocations */ + common_init(); +} + +static void common_init(void) +{ + void *link; + /* initialise connection pool. */ if (_radio.connection_count) { mem_init(_radio.conn_pool, CONNECTION_T_SIZE, @@ -402,17 +453,17 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, &_radio.link_rx_free); /* initialise ctrl tx pool. */ - mem_init(_radio.pkt_tx_ctrl_pool, packet_tx_ctrl_size, + mem_init(_radio.pkt_tx_ctrl_pool, PACKET_TX_CTRL_SIZE_MIN, PACKET_MEM_COUNT_TX_CTRL, &_radio.pkt_tx_ctrl_free); /* initialise data tx pool. */ mem_init(_radio.pkt_tx_data_pool, _radio.packet_tx_data_size, (_radio.packet_tx_count - 1), &_radio.pkt_tx_data_free); - /* initialise controller states and flags */ - _radio.role = ROLE_NONE; - _radio.state = STATE_NONE; - _radio.fc_ena = 1; + /* initialise the event-cum-data memq */ + link = mem_acquire(&_radio.link_rx_free); + LL_ASSERT(link); + memq_init(link, &_radio.link_rx_head, (void *)&_radio.link_rx_tail); /* initialise advertiser channel map */ _radio.advertiser.chl_map = 0x07; @@ -427,16 +478,6 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, /* allocate the rx queue */ packet_rx_allocate(0xFF); - - /* initialise the event-cum-data memq */ - link = mem_acquire(&_radio.link_rx_free); - link = memq_init(link, &_radio.link_rx_head, - (void *)&_radio.link_rx_tail); - - /* after rx queue allocation, one link mem should still be available */ - LL_ASSERT(link); - - return retcode; } static inline void isr_radio_state_tx(void) @@ -6361,7 +6402,21 @@ uint32_t radio_irk_add(uint8_t *irk) return 0; } -static inline void do_adv_scan_disable(uint8_t ticker_id_stop, +static struct connection *connection_get(uint16_t handle) +{ + struct connection *conn; + + if (handle < _radio.connection_count) { + conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE, handle); + if ((conn) && (conn->handle == handle)) { + return conn; + } + } + + return 0; +} + +static inline void role_active_disable(uint8_t ticker_id_stop, uint32_t ticks_xtal_to_start, uint32_t ticks_active_to_start) { @@ -6485,12 +6540,48 @@ static inline void do_adv_scan_disable(uint8_t ticker_id_stop, } -static uint32_t adv_scan_disable(uint8_t ticker_id_primary, - uint8_t ticker_id_stop, - uint32_t ticks_xtal_to_start, - uint32_t ticks_active_to_start) +static uint32_t role_disable(uint8_t ticker_id_primary, + uint8_t ticker_id_stop) { uint32_t volatile ticker_status; + uint32_t ticks_xtal_to_start = 0; + uint32_t ticks_active_to_start = 0; + + switch (ticker_id_primary) { + case RADIO_TICKER_ID_ADV: + ticks_xtal_to_start = + _radio.advertiser.hdr.ticks_xtal_to_start; + ticks_active_to_start = + _radio.advertiser.hdr.ticks_active_to_start; + break; + + case RADIO_TICKER_ID_OBS: + ticks_xtal_to_start = + _radio.observer.hdr.ticks_xtal_to_start; + ticks_active_to_start = + _radio.observer.hdr.ticks_active_to_start; + break; + default: + if (ticker_id_primary >= RADIO_TICKER_ID_FIRST_CONNECTION) { + struct connection *conn; + uint16_t conn_handle; + + conn_handle = ticker_id_primary - + RADIO_TICKER_ID_FIRST_CONNECTION; + conn = connection_get(conn_handle); + if (!conn) { + return 1; + } + + ticks_xtal_to_start = + conn->hdr.ticks_xtal_to_start; + ticks_active_to_start = + conn->hdr.ticks_active_to_start; + } else { + BT_ASSERT(0); + } + break; + } /* Step 1: Is Primary started? Stop the Primary ticker */ ticker_status = @@ -6519,7 +6610,7 @@ static uint32_t adv_scan_disable(uint8_t ticker_id_primary, if ((_radio.ticker_id_prepare == ticker_id_primary) || (_radio.ticker_id_event == ticker_id_primary)) { - do_adv_scan_disable(ticker_id_stop, + role_active_disable(ticker_id_stop, ticks_xtal_to_start, ticks_active_to_start); } @@ -6709,10 +6800,8 @@ uint32_t radio_adv_disable(void) { uint32_t status; - status = adv_scan_disable(RADIO_TICKER_ID_ADV, - RADIO_TICKER_ID_ADV_STOP, - _radio.advertiser.hdr.ticks_xtal_to_start, - _radio.advertiser.hdr.ticks_active_to_start); + status = role_disable(RADIO_TICKER_ID_ADV, + RADIO_TICKER_ID_ADV_STOP); if (!status) { struct connection *conn; @@ -6816,10 +6905,8 @@ uint32_t radio_scan_disable(void) { uint32_t status; - status = adv_scan_disable(RADIO_TICKER_ID_OBS, - RADIO_TICKER_ID_OBS_STOP, - _radio.observer.hdr.ticks_xtal_to_start, - _radio.observer.hdr.ticks_active_to_start); + status = role_disable(RADIO_TICKER_ID_OBS, + RADIO_TICKER_ID_OBS_STOP); if (!status) { struct connection *conn; @@ -6954,20 +7041,6 @@ uint32_t radio_connect_disable(void) return status; } -static struct connection *connection_get(uint16_t handle) -{ - struct connection *conn; - - if (handle < _radio.connection_count) { - conn = mem_get(_radio.conn_pool, CONNECTION_T_SIZE, handle); - if ((conn) && (conn->handle == handle)) { - return conn; - } - } - - return 0; -} - uint32_t radio_conn_update(uint16_t handle, uint8_t cmd, uint8_t status, uint16_t interval, uint16_t latency, uint16_t timeout) diff --git a/subsys/bluetooth/controller/ll/ctrl.h b/subsys/bluetooth/controller/ll/ctrl.h index f9b092d708b..cd2a6c1e996 100644 --- a/subsys/bluetooth/controller/ll/ctrl.h +++ b/subsys/bluetooth/controller/ll/ctrl.h @@ -208,6 +208,7 @@ uint32_t radio_init(void *hf_clock, uint8_t sca, uint8_t connection_count_max, uint8_t rx_count_max, uint8_t tx_count_max, uint16_t data_octets_max, uint8_t *mem_radio, uint16_t mem_size); +void ctrl_reset(void); void radio_ticks_active_to_start_set(uint32_t ticks_active_to_start); struct radio_adv_data *radio_adv_data_get(void); struct radio_adv_data *radio_scan_data_get(void); diff --git a/subsys/bluetooth/controller/ll/ctrl_internal.h b/subsys/bluetooth/controller/ll/ctrl_internal.h index 25f7c200efa..21e8959c76e 100644 --- a/subsys/bluetooth/controller/ll/ctrl_internal.h +++ b/subsys/bluetooth/controller/ll/ctrl_internal.h @@ -198,6 +198,16 @@ struct pdu_data_q_tx { struct radio_pdu_node_tx *node_tx; }; +/* Minimum Rx Data allocation size */ +#define PACKET_RX_DATA_SIZE_MIN \ + ALIGN4(offsetof(struct radio_pdu_node_rx, pdu_data) + \ + (RADIO_ACPDU_SIZE_MAX + 1)) + +/* Minimum Tx Ctrl allocation size */ +#define PACKET_TX_CTRL_SIZE_MIN \ + ALIGN4(offsetof(struct radio_pdu_node_tx, pdu_data) + \ + offsetof(struct pdu_data, payload) + 27) + /** @todo fix starvation when ctrl rx in radio ISR * for multiple connections needs to tx back to peer. */ @@ -223,10 +233,7 @@ struct pdu_data_q_tx { #define LL_MEM_RX_LINK_POOL (sizeof(void *) * 2 * ((RADIO_PACKET_COUNT_RX_MAX +\ 4) + RADIO_CONNECTION_CONTEXT_MAX)) -#define LL_MEM_TX_CTRL_POOL ((ALIGN4(offsetof( \ - struct radio_pdu_node_tx, pdu_data) + \ - offsetof(struct pdu_data, payload) + 27)) * \ - PACKET_MEM_COUNT_TX_CTRL) +#define LL_MEM_TX_CTRL_POOL (PACKET_TX_CTRL_SIZE_MIN * PACKET_MEM_COUNT_TX_CTRL) #define LL_MEM_TX_DATA_POOL ((ALIGN4(offsetof( \ struct radio_pdu_node_tx, pdu_data) + \ offsetof(struct pdu_data, payload) + \ diff --git a/subsys/bluetooth/controller/ll/ticker.c b/subsys/bluetooth/controller/ll/ticker.c index 18001936872..2ba98ef7e29 100644 --- a/subsys/bluetooth/controller/ll/ticker.c +++ b/subsys/bluetooth/controller/ll/ticker.c @@ -1315,8 +1315,6 @@ uint32_t ticker_init(uint8_t instance_index, uint8_t count_node, void *node, instance->ticks_elapsed_first = 0; instance->ticks_elapsed_last = 0; - rtc_init(); - return TICKER_STATUS_SUCCESS; }