Skip to content

Commit

Permalink
Bluetooth: controller: split: Fix missing data len update event
Browse files Browse the repository at this point in the history
Fix missing generation of data length update HCI event when
effective tx and rx timings change due to PHY update
procedure.

Fixes BT LL TS 5.1.0 test:
LL/CON/MAS/BV-52-C [Master Receiving Data, LE Coded, CI
Change]

Relates to zephyrproject-rtos#17097.

Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
  • Loading branch information
cvinayak authored and carlescufi committed Oct 10, 2019
1 parent 186a584 commit d12c53f
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 18 deletions.
8 changes: 7 additions & 1 deletion subsys/bluetooth/controller/ll_sw/ull.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,13 @@ static struct {
u8_t pool[sizeof(memq_link_t) * EVENT_DONE_MAX];
} mem_link_done;

#define PDU_RX_CNT (CONFIG_BT_CTLR_RX_BUFFERS + 3)
#if defined(CONFIG_BT_CTLR_PHY) && defined(CONFIG_BT_CTLR_DATA_LENGTH)
#define LL_PDU_RX_CNT 2
#else
#define LL_PDU_RX_CNT 1
#endif

#define PDU_RX_CNT (CONFIG_BT_CTLR_RX_BUFFERS + 3)
#define RX_CNT (PDU_RX_CNT + LL_PDU_RX_CNT)

static MFIFO_DEFINE(pdu_rx_free, sizeof(void *), PDU_RX_CNT);
Expand Down Expand Up @@ -1249,6 +1254,7 @@ static inline void rx_alloc(u8_t max)
break;
}

link->mem = NULL;
rx->link = link;

MFIFO_BY_IDX_ENQUEUE(ll_pdu_rx_free, idx, rx);
Expand Down
147 changes: 130 additions & 17 deletions subsys/bluetooth/controller/ll_sw/ull_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1524,12 +1524,18 @@ static void conn_cleanup(struct ll_conn *conn, u8_t reason)

/* release any llcp reserved rx node */
rx = conn->llcp_rx;
if (rx) {
while (rx) {
struct node_rx_hdr *hdr;

/* traverse to next rx node */
hdr = &rx->hdr;
rx = hdr->link->mem;

/* Mark for buffer for release */
rx->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE;
hdr->type = NODE_RX_TYPE_DC_PDU_RELEASE;

/* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx);
ll_rx_put(hdr->link, hdr);
}

/* flush demux-ed Tx buffer still in ULL context */
Expand Down Expand Up @@ -2962,6 +2968,23 @@ static inline void event_len_prep(struct ll_conn *conn)
break;
}
}

static u16_t calc_eff_time(u8_t max_octets, u8_t phy, u16_t default_time)
{
u16_t time = PKT_US(max_octets, phy);
u16_t eff_time;

if (time >= PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0)) {
eff_time = MIN(time, default_time);
#if defined(CONFIG_BT_CTLR_PHY_CODED)
eff_time = MAX(eff_time, PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, phy));
#endif /* CONFIG_BT_CTLR_PHY_CODED */
} else {
eff_time = PKT_US(PDU_DC_PAYLOAD_SIZE_MIN, 0);
}

return eff_time;
}
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */

#if defined(CONFIG_BT_CTLR_PHY)
Expand Down Expand Up @@ -3086,7 +3109,11 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,

LL_ASSERT(!conn->llcp_rx);

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
rx = ll_pdu_rx_alloc_peek(2);
#else /* !CONFIG_BT_CTLR_DATA_LENGTH */
rx = ll_pdu_rx_alloc_peek(1);
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
if (!rx) {
return;
}
Expand Down Expand Up @@ -3135,7 +3162,15 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,
6;
/* reserve rx node for event generation at instant */
(void)ll_pdu_rx_alloc();
rx->hdr.link->mem = conn->llcp_rx;
conn->llcp_rx = rx;

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* reserve rx node for DLE event generation */
rx = ll_pdu_rx_alloc();
rx->hdr.link->mem = conn->llcp_rx;
conn->llcp_rx = rx;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}

/* place the phy update ind packet as next in
Expand All @@ -3154,8 +3189,8 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,
ind->instant = sys_cpu_to_le16(conn->llcp.phy_upd_ind.instant);

ctrl_tx_enqueue(conn, tx);
} else if (((event_counter - conn->llcp.phy_upd_ind.instant) & 0xFFFF)
<= 0x7FFF) {
} else if (((event_counter - conn->llcp.phy_upd_ind.instant) &
0xFFFF) <= 0x7FFF) {
struct lll_conn *lll = &conn->lll;
struct node_rx_pdu *rx;
u8_t old_tx, old_rx;
Expand All @@ -3166,37 +3201,105 @@ static inline void event_phy_upd_ind_prep(struct ll_conn *conn,
/* apply new phy */
old_tx = lll->phy_tx;
old_rx = lll->phy_rx;

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
u16_t eff_tx_time = lll->max_tx_time;
u16_t eff_rx_time = lll->max_rx_time;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */

if (conn->llcp.phy_upd_ind.tx) {
lll->phy_tx = conn->llcp.phy_upd_ind.tx;

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
eff_tx_time = calc_eff_time(lll->max_tx_octets,
lll->phy_tx,
conn->default_tx_time);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}
if (conn->llcp.phy_upd_ind.rx) {
lll->phy_rx = conn->llcp.phy_upd_ind.rx;

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
eff_rx_time =
calc_eff_time(lll->max_rx_octets, lll->phy_rx,
PKT_US(LL_LENGTH_OCTETS_RX_MAX,
BIT(2)));
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
}
lll->phy_flags = conn->phy_pref_flags;

/* Acquire Rx node */
rx = conn->llcp_rx;
conn->llcp_rx = NULL;

LL_ASSERT(rx && rx->hdr.link);
conn->llcp_rx = rx->hdr.link->mem;

/* generate event if phy changed or initiated by cmd */
if (conn->llcp.phy_upd_ind.cmd || (lll->phy_tx != old_tx) ||
(lll->phy_rx != old_rx)) {
rx->hdr.handle = lll->handle;
rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;

upd = (void *)rx->pdu;
upd->status = 0U;
upd->tx = lll->phy_tx;
upd->rx = lll->phy_rx;
} else {
if (!conn->llcp.phy_upd_ind.cmd && (lll->phy_tx == old_tx) &&
(lll->phy_rx == old_rx)) {
/* Mark for buffer for release */
rx->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE;

/* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx);
ll_rx_sched();

return;
}

rx->hdr.handle = lll->handle;
rx->hdr.type = NODE_RX_TYPE_PHY_UPDATE;

upd = (void *)rx->pdu;
upd->status = 0U;
upd->tx = lll->phy_tx;
upd->rx = lll->phy_rx;

/* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx);

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* get a rx node for ULL->LL */
rx = conn->llcp_rx;
LL_ASSERT(rx && rx->hdr.link);
conn->llcp_rx = rx->hdr.link->mem;

/* Update max tx and/or max rx if changed */
if ((eff_tx_time <= lll->max_tx_time) &&
(eff_rx_time <= lll->max_rx_time)) {
/* Mark buffer for release */
rx->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE;

/* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx);
ll_rx_sched();
return;
}
lll->max_tx_time = eff_tx_time;
lll->max_rx_time = eff_rx_time;

/* prepare length rsp structure */
rx->hdr.handle = lll->handle;
rx->hdr.type = NODE_RX_TYPE_DC_PDU;

struct pdu_data *pdu_rx = (void *)rx->pdu;

pdu_rx->ll_id = PDU_DATA_LLID_CTRL;
pdu_rx->len = offsetof(struct pdu_data_llctrl, length_rsp) +
sizeof(struct pdu_data_llctrl_length_rsp);
pdu_rx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP;

struct pdu_data_llctrl_length_req *lr =
(void *)&pdu_rx->llctrl.length_rsp;

lr->max_rx_octets = sys_cpu_to_le16(lll->max_rx_octets);
lr->max_tx_octets = sys_cpu_to_le16(lll->max_tx_octets);
lr->max_rx_time = sys_cpu_to_le16(lll->max_rx_time);
lr->max_tx_time = sys_cpu_to_le16(lll->max_tx_time);

/* enqueue rx node towards Thread */
ll_rx_put(rx->hdr.link, rx);
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */

ll_rx_sched();
}
}
Expand Down Expand Up @@ -4325,10 +4428,20 @@ static inline u8_t phy_upd_ind_recv(struct ll_conn *conn, memq_link_t *link,

LL_ASSERT(!conn->llcp_rx);

link->mem = conn->llcp_rx;
(*rx)->hdr.link = link;
conn->llcp_rx = *rx;
*rx = NULL;

#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* reserve rx node for DLE event generation */
struct node_rx_pdu *rx_dle = ll_pdu_rx_alloc();

LL_ASSERT(rx_dle);
rx_dle->hdr.link->mem = conn->llcp_rx;
conn->llcp_rx = rx_dle;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */

conn->llcp_type = LLCP_PHY_UPD;
conn->llcp_ack -= 2U;

Expand Down

0 comments on commit d12c53f

Please sign in to comment.