drivers: ieee802154: Add auto-ack support to KW41Z driver

- Enabled and fixed auto-ack offload support for 802.15.4 transmit

Signed-off-by: David Leach <david.leach@nxp.com>
This commit is contained in:
David Leach 2018-03-12 15:15:19 -05:00 committed by Jukka Rissanen
parent c90b9f53cd
commit 7738a501d9

View file

@ -42,6 +42,7 @@
struct kw41_dbg_trace {
u8_t type;
u32_t time;
u32_t irqsts;
u32_t phy_ctrl;
u32_t seq_state;
@ -53,6 +54,8 @@ int kw41_dbg_idx;
#define KW_DBG_TRACE(_type, _irqsts, _phy_ctrl, _seq_state) \
do { \
kw41_dbg[kw41_dbg_idx].type = (_type); \
kw41_dbg[kw41_dbg_idx].time = \
ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT; \
kw41_dbg[kw41_dbg_idx].irqsts = (_irqsts); \
kw41_dbg[kw41_dbg_idx].phy_ctrl = (_phy_ctrl); \
kw41_dbg[kw41_dbg_idx].seq_state = (_seq_state); \
@ -81,12 +84,6 @@ int kw41_dbg_idx;
#define KW41Z_OUTPUT_POWER_MAX 2
#define KW41Z_OUTPUT_POWER_MIN (-19)
/*
* When ACK offload is implemented in the 15.4 stack we can enable
* things here.
*/
#define KW41Z_AUTOACK_ENABLED 0
#define BM_ZLL_IRQSTS_TMRxMSK (ZLL_IRQSTS_TMR1MSK_MASK | \
ZLL_IRQSTS_TMR2MSK_MASK | \
ZLL_IRQSTS_TMR3MSK_MASK | \
@ -518,11 +515,6 @@ static inline void kw41z_rx(struct kw41z_context *kw41z, u8_t len)
net_buf_add(frag, pkt_len);
if (ieee802154_radio_handle_ack(kw41z->iface, pkt) == NET_OK) {
SYS_LOG_DBG("ACK packet handled");
goto out;
}
hw_lqi = (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_LQI_VALUE_MASK) >>
ZLL_LQI_AND_RSSI_LQI_VALUE_SHIFT;
net_pkt_set_ieee802154_lqi(pkt, kw41z_convert_lqi(hw_lqi));
@ -546,9 +538,9 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
{
struct kw41z_context *kw41z = dev->driver_data;
u8_t payload_len = net_pkt_ll_reserve(pkt) + frag->len;
#if KW41Z_AUTOACK_ENABLED
u32_t tx_timeout;
#endif
u8_t xcvseq;
int key;
/*
* The transmit requests are preceded by the CCA request. On
@ -565,6 +557,12 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
return 0;
}
key = irq_lock();
/* Disable the 802.15.4 radio IRQ */
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TRCV_MSK_MASK;
kw41z_disable_seq_irq();
#if CONFIG_SOC_MKW41Z4
((u8_t *)ZLL->PKT_BUFFER_TX)[0] = payload_len + KW41Z_FCS_LENGTH;
memcpy(((u8_t *)ZLL->PKT_BUFFER_TX) + 1,
@ -586,32 +584,38 @@ static int kw41z_tx(struct device *dev, struct net_pkt *pkt,
* Current Zephyr 802.15.4 stack doesn't support ACK offload
*/
#if KW41Z_AUTOACK_ENABLED
/* Perform automatic reception of ACK frame, if required */
if (ieee802154_is_ar_flag_set(pkt)) {
tx_timeout = kw41z->tx_warmup_time + KW41Z_SHR_PHY_TIME +
payload_len * KW41Z_PER_BYTE_TIME + 10 +
KW41Z_ACK_WAIT_TIME;
SYS_LOG_DBG("AUTOACK_ENABLED: len: %d, timeout: %d, seq: %d",
SYS_LOG_DBG("AUTOACK ENABLED: len: %d, timeout: %d, seq: %d",
payload_len, tx_timeout,
(frag->data - net_pkt_ll_reserve(pkt))[2]);
kw41z_tmr3_set_timeout(tx_timeout);
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_RXACKRQD_MASK;
kw41z_set_seq_state(KW41Z_STATE_TXRX);
} else
#endif
{
SYS_LOG_DBG("AUTOACK disabled: len: %d, seq: %d",
xcvseq = KW41Z_STATE_TXRX;
} else {
SYS_LOG_DBG("AUTOACK DISABLED: len: %d, seq: %d",
payload_len, (frag->data - net_pkt_ll_reserve(pkt))[2]);
ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_RXACKRQD_MASK;
kw41z_set_seq_state(KW41Z_STATE_TX);
xcvseq = KW41Z_STATE_TX;
}
kw41z_enable_seq_irq();
/*
* PHY_CTRL is sensitive to multiple writes that can kick off
* the sequencer engine causing TX with AR request to send the
* TX frame multiple times.
*
* To minimize, ensure there is only one write to PHY_CTRL with
* TXRX sequence enable and the 802.15.4 radio IRQ.
*/
ZLL->PHY_CTRL = (ZLL->PHY_CTRL & ~ZLL_PHY_CTRL_TRCV_MSK_MASK) | xcvseq;
irq_unlock(key);
k_sem_take(&kw41z->seq_sync, K_FOREVER);
SYS_LOG_DBG("seq_retval: %d", kw41z->seq_retval);
@ -669,12 +673,13 @@ static void kw41z_isr(int unused)
rx_len = (irqsts & ZLL_IRQSTS_RX_FRAME_LENGTH_MASK)
>> ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT;
SYS_LOG_DBG("WMRK irq: seq_state: 0x%08x, rx_len: %d",
seq_state, rx_len);
KW_DBG_TRACE(KW41_DBG_TRACE_WTRM, irqsts,
(unsigned int)ZLL->PHY_CTRL, seq_state);
if (rx_len > IEEE802154_ACK_LENGTH) {
SYS_LOG_DBG("WMRK irq: seq_state: 0x%08x, rx_len: %d",
seq_state, rx_len);
/*
* Assume the RX includes an auto-ACK so set the timer to
* include the RX frame size, crc, IFS, and ACK length and
@ -688,6 +693,7 @@ static void kw41z_isr(int unused)
*/
rx_len = rx_len * 2 + 12 + 22 + 2;
kw41z_tmr3_set_timeout(rx_len);
}
restart_rx = 0;
}
@ -726,6 +732,7 @@ static void kw41z_isr(int unused)
/* TODO: What is the right error for no ACK? */
atomic_set(&kw41z_context_data.seq_retval,
-EBUSY);
k_sem_give(&kw41z_context_data.seq_sync);
}
} else {
kw41z_isr_seq_cleanup();
@ -823,7 +830,7 @@ static void kw41z_isr(int unused)
/* Restart RX */
if (restart_rx) {
SYS_LOG_DBG("RESET RX");
kw41z_phy_abort();
kw41z_set_seq_state(KW41Z_STATE_RX);
kw41z_enable_seq_irq();
}
@ -879,15 +886,14 @@ static int kw41z_init(struct device *dev)
ZLL_PHY_CTRL_CCAMSK_MASK |
ZLL_PHY_CTRL_RXMSK_MASK |
ZLL_PHY_CTRL_TXMSK_MASK |
ZLL_PHY_CTRL_CCABFRTX_MASK |
ZLL_PHY_CTRL_SEQMSK_MASK;
#if CONFIG_SOC_MKW41Z4
ZLL->PHY_CTRL |= ZLL_IRQSTS_WAKE_IRQ_MASK;
#endif
#if KW41Z_AUTOACK_ENABLED
ZLL->PHY_CTRL |= ZLL_PHY_CTRL_AUTOACK_MASK;
#endif
/*
* Clear all PP IRQ bits to avoid unexpected interrupts immediately
@ -904,6 +910,7 @@ static int kw41z_init(struct device *dev)
ZLL->RX_FRAME_FILTER = ZLL_RX_FRAME_FILTER_FRM_VER_FILTER(3) |
ZLL_RX_FRAME_FILTER_CMD_FT_MASK |
ZLL_RX_FRAME_FILTER_DATA_FT_MASK |
ZLL_RX_FRAME_FILTER_ACK_FT_MASK |
ZLL_RX_FRAME_FILTER_BEACON_FT_MASK;
/* Set prescaller to obtain 1 symbol (16us) timebase */