Bluetooth: Controller: Fix HCI Reset Command implementation
Added implementation for HCI Reset Command. Implementation gracefully disables any running advertiser, observer, and/ or connection roles, and it resets controller context members. The HCI Reset Command is implemented in such a way that driver instances shared with other sub-systems and application is not disturbed and instance/references used by Bluetooth Controller are gracefully returned back. Jira: ZEP-1282 Change-id: Ifb9ae6807736b5ec2d9f346cf2a590322056bcee Signed-off-by: Vinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no> Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
parent
2305196461
commit
11770b8bf4
6 changed files with 147 additions and 63 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) + \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue