From ba6d22393284b703e6174278c31858bf59337ed2 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:28 +0100 Subject: at86rf230: add transmit retry support This patch introduce a transmit retry handling into at86rf230 transmit path. Current behaviour is to wait the normal receive time if we want to go into STATE_TX_ON when the transceiver is in STATE_BUSY_RX_AACK which indicates that a frame is currently receiving. A non force state change will not interrupt the the receiving state. The current behaviour is that after the normal receive time we will start a force change into STATE_TX_ON. With this patch we do seven retries to go into STATE_TX_ON without forcing. After we hit the AT86RF2XX_MAX_TX_RETRIES we will start the force state change. This is a polling like method to go into STATE_TX_ON in times of maximum receiving time. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 1d438bc54189..503fabddd431 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -52,7 +52,13 @@ struct at86rf2xx_chip_data { int (*get_desense_steps)(struct at86rf230_local *, s32); }; -#define AT86RF2XX_MAX_BUF (127 + 3) +#define AT86RF2XX_MAX_BUF (127 + 3) +/* tx retries to access the TX_ON state + * if it's above then force change will be started. + * + * We assume the max_frame_retries (7) value of 802.15.4 here. + */ +#define AT86RF2XX_MAX_TX_RETRIES 7 struct at86rf230_state_change { struct at86rf230_local *lp; @@ -85,6 +91,7 @@ struct at86rf230_local { bool is_tx; /* spinlock for is_tx protection */ spinlock_t lock; + u8 tx_retry; struct sk_buff *tx_skb; struct at86rf230_state_change tx; }; @@ -512,10 +519,20 @@ at86rf230_async_state_assert(void *context) * in STATE_BUSY_RX_AACK, we run a force state change * to STATE_TX_ON. This is a timeout handling, if the * transceiver stucks in STATE_BUSY_RX_AACK. + * + * Additional we do several retries to try to get into + * TX_ON state without forcing. If the retries are + * higher or equal than AT86RF2XX_MAX_TX_RETRIES we + * will do a force change. */ if (ctx->to_state == STATE_TX_ON) { - at86rf230_async_state_change(lp, ctx, - STATE_FORCE_TX_ON, + u8 state = STATE_TX_ON; + + if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) + state = STATE_FORCE_TX_ON; + lp->tx_retry++; + + at86rf230_async_state_change(lp, ctx, state, ctx->complete, ctx->irq_enable); return; @@ -963,6 +980,7 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) if (lp->tx_aret) tx_complete = at86rf230_xmit_tx_on; + lp->tx_retry = 0; at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); return 0; -- cgit v1.2.3 From ef5428a1386d472939c763abc68a9d0f1fb18dce Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:29 +0100 Subject: at86rf230: cleanup and squash stack variable I had this variable because I thought it would be protected by disable/enable irq but this is not true. It's protected by stop/wake netdev queue which is called by ieee802154_xmit_complete. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 503fabddd431..85012201eaf5 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -725,11 +725,10 @@ at86rf230_tx_complete(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - struct sk_buff *skb = lp->tx_skb; enable_irq(lp->spi->irq); - ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret); + ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret); } static void -- cgit v1.2.3 From 74de4c804c53f612ef1287e4241d8d06f8e794c7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:30 +0100 Subject: at86rf230: refactor receive handling This patch refactor the receive handling into one function. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 85012201eaf5..8e93ea415149 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -781,13 +781,23 @@ at86rf230_tx_trac_status(void *context) } static void -at86rf230_rx(struct at86rf230_local *lp, - const u8 *data, const u8 len, const u8 lqi) +at86rf230_rx_read_frame_complete(void *context) { - struct sk_buff *skb; + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; u8 rx_local_buf[AT86RF2XX_MAX_BUF]; + const u8 *buf = lp->irq.buf; + struct sk_buff *skb; + u8 len, lqi; - memcpy(rx_local_buf, data, len); + len = buf[1]; + if (!ieee802154_is_valid_psdu_len(len)) { + dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); + len = IEEE802154_MTU; + } + lqi = buf[2 + len]; + + memcpy(rx_local_buf, buf + 2, len); enable_irq(lp->spi->irq); skb = dev_alloc_skb(IEEE802154_MTU); @@ -800,22 +810,6 @@ at86rf230_rx(struct at86rf230_local *lp, ieee802154_rx_irqsafe(lp->hw, skb, lqi); } -static void -at86rf230_rx_read_frame_complete(void *context) -{ - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - const u8 *buf = lp->irq.buf; - u8 len = buf[1]; - - if (!ieee802154_is_valid_psdu_len(len)) { - dev_vdbg(&lp->spi->dev, "corrupted frame received\n"); - len = IEEE802154_MTU; - } - - at86rf230_rx(lp, buf + 2, len, buf[2 + len]); -} - static void at86rf230_rx_read_frame(struct at86rf230_local *lp) { -- cgit v1.2.3 From cca990c85d37a9ed42d2cac53c619abec7faa12f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:31 +0100 Subject: at86rf230: remove multiple dereferencing for irq By holding the irq variable inside at86rf230_state_change we can squash some multiple dereferencing for getting irq num. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 8e93ea415149..7f27fa35bde3 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -62,6 +62,7 @@ struct at86rf2xx_chip_data { struct at86rf230_state_change { struct at86rf230_local *lp; + int irq; struct spi_message msg; struct spi_transfer trx; @@ -483,7 +484,7 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (irq_enable) - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -667,7 +668,7 @@ at86rf230_async_state_change_start(void *context) rc = spi_async(lp->spi, &ctx->msg); if (rc) { if (ctx->irq_enable) - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -726,7 +727,7 @@ at86rf230_tx_complete(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); ieee802154_xmit_complete(lp->hw, lp->tx_skb, !lp->tx_aret); } @@ -798,7 +799,7 @@ at86rf230_rx_read_frame_complete(void *context) lqi = buf[2 + len]; memcpy(rx_local_buf, buf + 2, len); - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); skb = dev_alloc_skb(IEEE802154_MTU); if (!skb) { @@ -811,8 +812,10 @@ at86rf230_rx_read_frame_complete(void *context) } static void -at86rf230_rx_read_frame(struct at86rf230_local *lp) +at86rf230_rx_read_frame(void *context) { + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; int rc; u8 *buf = lp->irq.buf; @@ -822,7 +825,7 @@ at86rf230_rx_read_frame(struct at86rf230_local *lp) lp->irq.msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &lp->irq.msg); if (rc) { - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); at86rf230_async_error(lp, &lp->irq, rc); } } @@ -830,16 +833,13 @@ at86rf230_rx_read_frame(struct at86rf230_local *lp) static void at86rf230_rx_trac_check(void *context) { - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - /* Possible check on trac status here. This could be useful to make * some stats why receive is failed. Not used at the moment, but it's * maybe timing relevant. Datasheet doesn't say anything about this. * The programming guide say do it so. */ - at86rf230_rx_read_frame(lp); + at86rf230_rx_read_frame(context); } static void @@ -878,7 +878,7 @@ at86rf230_irq_status(void *context) if (irq & IRQ_TRX_END) { at86rf230_irq_trx_end(lp); } else { - enable_irq(lp->spi->irq); + enable_irq(ctx->irq); dev_err(&lp->spi->dev, "not supported irq %02x received\n", irq); } @@ -1539,6 +1539,7 @@ static void at86rf230_setup_spi_messages(struct at86rf230_local *lp) { lp->state.lp = lp; + lp->state.irq = lp->spi->irq; spi_message_init(&lp->state.msg); lp->state.msg.context = &lp->state; lp->state.trx.tx_buf = lp->state.buf; @@ -1546,6 +1547,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) spi_message_add_tail(&lp->state.trx, &lp->state.msg); lp->irq.lp = lp; + lp->irq.irq = lp->spi->irq; spi_message_init(&lp->irq.msg); lp->irq.msg.context = &lp->irq; lp->irq.trx.tx_buf = lp->irq.buf; @@ -1553,6 +1555,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); lp->tx.lp = lp; + lp->tx.irq = lp->spi->irq; spi_message_init(&lp->tx.msg); lp->tx.msg.context = &lp->tx; lp->tx.trx.tx_buf = lp->tx.buf; -- cgit v1.2.3 From 31fa74344c1e75fd66f7b43f456ae9e0a137ba69 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:32 +0100 Subject: at86rf230: remove multiple dereferencing for ctx This patch cleanups the referencing for the state change context variable. The state change context should only set once and this is by initial a state change. This patch will use the initial state change variable in the complete handler of the state change by using the ctx context which should be always the same like the initial state change context. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 7f27fa35bde3..216c80c3532c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -738,7 +738,7 @@ at86rf230_tx_on(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON, + at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, at86rf230_tx_complete, true); } @@ -787,7 +787,7 @@ at86rf230_rx_read_frame_complete(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 rx_local_buf[AT86RF2XX_MAX_BUF]; - const u8 *buf = lp->irq.buf; + const u8 *buf = ctx->buf; struct sk_buff *skb; u8 len, lqi; @@ -816,17 +816,16 @@ at86rf230_rx_read_frame(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; + u8 *buf = ctx->buf; int rc; - u8 *buf = lp->irq.buf; - buf[0] = CMD_FB; - lp->irq.trx.len = AT86RF2XX_MAX_BUF; - lp->irq.msg.complete = at86rf230_rx_read_frame_complete; - rc = spi_async(lp->spi, &lp->irq.msg); + ctx->trx.len = AT86RF2XX_MAX_BUF; + ctx->msg.complete = at86rf230_rx_read_frame_complete; + rc = spi_async(lp->spi, &ctx->msg); if (rc) { enable_irq(ctx->irq); - at86rf230_async_error(lp, &lp->irq, rc); + at86rf230_async_error(lp, ctx, rc); } } @@ -872,7 +871,7 @@ at86rf230_irq_status(void *context) { struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; - const u8 *buf = lp->irq.buf; + const u8 *buf = ctx->buf; const u8 irq = buf[1]; if (irq & IRQ_TRX_END) { @@ -929,7 +928,7 @@ at86rf230_write_frame(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; struct sk_buff *skb = lp->tx_skb; - u8 *buf = lp->tx.buf; + u8 *buf = ctx->buf; int rc; spin_lock(&lp->lock); @@ -939,9 +938,9 @@ at86rf230_write_frame(void *context) buf[0] = CMD_FB | CMD_WRITE; buf[1] = skb->len + 2; memcpy(buf + 2, skb->data, skb->len); - lp->tx.trx.len = skb->len + 2; - lp->tx.msg.complete = at86rf230_write_frame_complete; - rc = spi_async(lp->spi, &lp->tx.msg); + ctx->trx.len = skb->len + 2; + ctx->msg.complete = at86rf230_write_frame_complete; + rc = spi_async(lp->spi, &ctx->msg); if (rc) at86rf230_async_error(lp, ctx, rc); } -- cgit v1.2.3 From 263be3326b89a1a4994b29cbe898637fd72e6f0b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 1 Mar 2015 21:55:33 +0100 Subject: at86rf230: restore trx len when needed In the most cases the spi messages has a length of two. Currently we always set the the len field to two before transmit a spi message. In cases for read out/write in the frame buffer we need another len. This patch use trx len two as default. For the frame buffer cases we restore the trx len to two on success and failure. This will reduce the len setting of two when it's already two. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 216c80c3532c..088fa68f5098 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -478,7 +478,6 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, u8 *tx_buf = ctx->buf; tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG; - ctx->trx.len = 2; ctx->msg.complete = complete; ctx->irq_enable = irq_enable; rc = spi_async(lp->spi, &ctx->msg); @@ -663,7 +662,6 @@ at86rf230_async_state_change_start(void *context) */ buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; buf[1] = ctx->to_state; - ctx->trx.len = 2; ctx->msg.complete = at86rf230_async_state_delay; rc = spi_async(lp->spi, &ctx->msg); if (rc) { @@ -799,6 +797,7 @@ at86rf230_rx_read_frame_complete(void *context) lqi = buf[2 + len]; memcpy(rx_local_buf, buf + 2, len); + ctx->trx.len = 2; enable_irq(ctx->irq); skb = dev_alloc_skb(IEEE802154_MTU); @@ -824,6 +823,7 @@ at86rf230_rx_read_frame(void *context) ctx->msg.complete = at86rf230_rx_read_frame_complete; rc = spi_async(lp->spi, &ctx->msg); if (rc) { + ctx->trx.len = 2; enable_irq(ctx->irq); at86rf230_async_error(lp, ctx, rc); } @@ -893,7 +893,6 @@ static irqreturn_t at86rf230_isr(int irq, void *data) disable_irq_nosync(irq); buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG; - ctx->trx.len = 2; ctx->msg.complete = at86rf230_irq_status; rc = spi_async(lp->spi, &ctx->msg); if (rc) { @@ -941,8 +940,10 @@ at86rf230_write_frame(void *context) ctx->trx.len = skb->len + 2; ctx->msg.complete = at86rf230_write_frame_complete; rc = spi_async(lp->spi, &ctx->msg); - if (rc) + if (rc) { + ctx->trx.len = 2; at86rf230_async_error(lp, ctx, rc); + } } static void @@ -1541,6 +1542,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->state.irq = lp->spi->irq; spi_message_init(&lp->state.msg); lp->state.msg.context = &lp->state; + lp->state.trx.len = 2; lp->state.trx.tx_buf = lp->state.buf; lp->state.trx.rx_buf = lp->state.buf; spi_message_add_tail(&lp->state.trx, &lp->state.msg); @@ -1549,6 +1551,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->irq.irq = lp->spi->irq; spi_message_init(&lp->irq.msg); lp->irq.msg.context = &lp->irq; + lp->irq.trx.len = 2; lp->irq.trx.tx_buf = lp->irq.buf; lp->irq.trx.rx_buf = lp->irq.buf; spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); @@ -1557,6 +1560,7 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->tx.irq = lp->spi->irq; spi_message_init(&lp->tx.msg); lp->tx.msg.context = &lp->tx; + lp->tx.trx.len = 2; lp->tx.trx.tx_buf = lp->tx.buf; lp->tx.trx.rx_buf = lp->tx.buf; spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); -- cgit v1.2.3 From e3721749000e11ba3f315efc5c98bf4cd5662f99 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 7 Mar 2015 22:07:07 +0100 Subject: at86rf230: init xtal_trim with zero This patch initialize xtal_trim value to zero. The xtal_trim property is an optional device tree value. Currently if no xtal_trim property is given the xtal_trim value can be contain random data, because it's a stack variable. This patch init the xtal_trim value to zero which is also the default value after reset for at86rf230 transceivers. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 088fa68f5098..edf575c88345 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1572,7 +1572,7 @@ static int at86rf230_probe(struct spi_device *spi) struct at86rf230_local *lp; unsigned int status; int rc, irq_type, rstn, slp_tr; - u8 xtal_trim; + u8 xtal_trim = 0; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); -- cgit v1.2.3 From eb3b435ecdb84d05698db862ce316b3c682f9a95 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:10 +0100 Subject: at86rf230: replace state change sleeps with hrtimer This patch replace the state change timing relevant sleeps with hrtimers. Currently the sleeps are done in the complete handler of spi_async. The relation of doing the state change timing sleep with a timer will get the sleep functionality out of spi_async complete handler context. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 39 ++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index edf575c88345..4030fa69f176 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ struct at86rf230_state_change { struct at86rf230_local *lp; int irq; + struct hrtimer timer; struct spi_message msg; struct spi_transfer trx; u8 buf[AT86RF2XX_MAX_BUF]; @@ -548,6 +550,19 @@ done: ctx->complete(context); } +static enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer) +{ + struct at86rf230_state_change *ctx = + container_of(timer, struct at86rf230_state_change, timer); + struct at86rf230_local *lp = ctx->lp; + + at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, + at86rf230_async_state_assert, + ctx->irq_enable); + + return HRTIMER_NORESTART; +} + /* Do state change timing delay. */ static void at86rf230_async_state_delay(void *context) @@ -556,6 +571,7 @@ at86rf230_async_state_delay(void *context) struct at86rf230_local *lp = ctx->lp; struct at86rf2xx_chip_data *c = lp->data; bool force = false; + ktime_t tim; /* The force state changes are will show as normal states in the * state status subregister. We change the to_state to the @@ -579,11 +595,10 @@ at86rf230_async_state_delay(void *context) case STATE_TRX_OFF: switch (ctx->to_state) { case STATE_RX_AACK_ON: - usleep_range(c->t_off_to_aack, c->t_off_to_aack + 10); + tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC); goto change; case STATE_TX_ON: - usleep_range(c->t_off_to_tx_on, - c->t_off_to_tx_on + 10); + tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); goto change; default: break; @@ -597,8 +612,8 @@ at86rf230_async_state_delay(void *context) * to TX_ON. */ if (!force) { - usleep_range(c->t_frame + c->t_p_ack, - c->t_frame + c->t_p_ack + 1000); + tim = ktime_set(0, (c->t_frame + c->t_p_ack) * + NSEC_PER_USEC); goto change; } break; @@ -610,7 +625,7 @@ at86rf230_async_state_delay(void *context) case STATE_P_ON: switch (ctx->to_state) { case STATE_TRX_OFF: - usleep_range(c->t_reset_to_off, c->t_reset_to_off + 10); + tim = ktime_set(0, c->t_reset_to_off * NSEC_PER_USEC); goto change; default: break; @@ -621,12 +636,10 @@ at86rf230_async_state_delay(void *context) } /* Default delay is 1us in the most cases */ - udelay(1); + tim = ktime_set(0, NSEC_PER_USEC); change: - at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx, - at86rf230_async_state_assert, - ctx->irq_enable); + hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL); } static void @@ -1546,6 +1559,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->state.trx.tx_buf = lp->state.buf; lp->state.trx.rx_buf = lp->state.buf; spi_message_add_tail(&lp->state.trx, &lp->state.msg); + hrtimer_init(&lp->state.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->state.timer.function = at86rf230_async_state_timer; lp->irq.lp = lp; lp->irq.irq = lp->spi->irq; @@ -1555,6 +1570,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->irq.trx.tx_buf = lp->irq.buf; lp->irq.trx.rx_buf = lp->irq.buf; spi_message_add_tail(&lp->irq.trx, &lp->irq.msg); + hrtimer_init(&lp->irq.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->irq.timer.function = at86rf230_async_state_timer; lp->tx.lp = lp; lp->tx.irq = lp->spi->irq; @@ -1564,6 +1581,8 @@ at86rf230_setup_spi_messages(struct at86rf230_local *lp) lp->tx.trx.tx_buf = lp->tx.buf; lp->tx.trx.rx_buf = lp->tx.buf; spi_message_add_tail(&lp->tx.trx, &lp->tx.msg); + hrtimer_init(&lp->tx.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + lp->tx.timer.function = at86rf230_async_state_timer; } static int at86rf230_probe(struct spi_device *spi) -- cgit v1.2.3 From dce481e63dc18ece7c86c607aa17b7c753fce0b7 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:11 +0100 Subject: at86rf230: add support for calibration timeout This patch adds a handling for calibration if we are 5 minutes in PLL state. I first tried to implement the calibration functionality in TX_ON state via register values CF_START and DCU_START, but this occurs a one second delay at each calibration time. An another solution to start a calibration is to switch from TRX_OFF state into TX_ON, then a calibration is done automatically by transceiver. This method will be used in this patch, after each transmit of a frame we check with jiffies if the PLL is set 5 minutes without doing a TRX_OFF->(TX_ON || RX_AACK_ON) or channel switch. The worst case would be a transceiver in receiving mode only, but this is under normal operation very unlikely. Signed-off-by: Alexander Aring Cc: Phoebe Buckheister Cc: Werner Almesberger Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 72 ++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 4030fa69f176..795106c23097 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,8 @@ struct at86rf2xx_chip_data { * We assume the max_frame_retries (7) value of 802.15.4 here. */ #define AT86RF2XX_MAX_TX_RETRIES 7 +/* We use the recommended 5 minutes timeout to recalibrate */ +#define AT86RF2XX_CAL_LOOP_TIMEOUT (5 * 60 * HZ) struct at86rf230_state_change { struct at86rf230_local *lp; @@ -90,6 +93,7 @@ struct at86rf230_local { struct at86rf230_state_change irq; bool tx_aret; + unsigned long cal_timeout; s8 max_frame_retries; bool is_tx; /* spinlock for is_tx protection */ @@ -491,6 +495,14 @@ at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg, } } +static inline u8 at86rf230_state_to_force(u8 state) +{ + if (state == STATE_TX_ON) + return STATE_FORCE_TX_ON; + else + return STATE_FORCE_TRX_OFF; +} + static void at86rf230_async_state_assert(void *context) { @@ -527,11 +539,12 @@ at86rf230_async_state_assert(void *context) * higher or equal than AT86RF2XX_MAX_TX_RETRIES we * will do a force change. */ - if (ctx->to_state == STATE_TX_ON) { - u8 state = STATE_TX_ON; + if (ctx->to_state == STATE_TX_ON || + ctx->to_state == STATE_TRX_OFF) { + u8 state = ctx->to_state; if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES) - state = STATE_FORCE_TX_ON; + state = at86rf230_state_to_force(state); lp->tx_retry++; at86rf230_async_state_change(lp, ctx, state, @@ -599,6 +612,11 @@ at86rf230_async_state_delay(void *context) goto change; case STATE_TX_ON: tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); + /* state change from TRX_OFF to TX_ON to do a + * calibration, we need to reset the timeout for the + * next one. + */ + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; goto change; default: break; @@ -606,10 +624,11 @@ at86rf230_async_state_delay(void *context) break; case STATE_BUSY_RX_AACK: switch (ctx->to_state) { + case STATE_TRX_OFF: case STATE_TX_ON: /* Wait for worst case receiving time if we * didn't make a force change from BUSY_RX_AACK - * to TX_ON. + * to TX_ON or TRX_OFF. */ if (!force) { tim = ktime_set(0, (c->t_frame + c->t_p_ack) * @@ -969,25 +988,45 @@ at86rf230_xmit_tx_on(void *context) at86rf230_write_frame, false); } -static int -at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +static void +at86rf230_xmit_start(void *context) { - struct at86rf230_local *lp = hw->priv; - struct at86rf230_state_change *ctx = &lp->tx; - - void (*tx_complete)(void *context) = at86rf230_write_frame; - - lp->tx_skb = skb; + struct at86rf230_state_change *ctx = context; + struct at86rf230_local *lp = ctx->lp; /* In ARET mode we need to go into STATE_TX_ARET_ON after we * are in STATE_TX_ON. The pfad differs here, so we change * the complete handler. */ if (lp->tx_aret) - tx_complete = at86rf230_xmit_tx_on; + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_xmit_tx_on, false); + else + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_write_frame, false); +} + +static int +at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) +{ + struct at86rf230_local *lp = hw->priv; + struct at86rf230_state_change *ctx = &lp->tx; + lp->tx_skb = skb; lp->tx_retry = 0; - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false); + + /* After 5 minutes in PLL and the same frequency we run again the + * calibration loops which is recommended by at86rf2xx datasheets. + * + * The calibration is initiate by a state change from TRX_OFF + * to TX_ON, the lp->cal_timeout should be reinit by state_delay + * function then to start in the next 5 minutes. + */ + if (time_is_before_jiffies(lp->cal_timeout)) + at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, + at86rf230_xmit_start, false); + else + at86rf230_xmit_start(ctx); return 0; } @@ -1003,6 +1042,9 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) static int at86rf230_start(struct ieee802154_hw *hw) { + struct at86rf230_local *lp = hw->priv; + + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); } @@ -1083,6 +1125,8 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel) /* Wait for PLL */ usleep_range(lp->data->t_channel_switch, lp->data->t_channel_switch + 10); + + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return rc; } -- cgit v1.2.3 From 51b3b2cfc64dbfa91d08077abf0791e36c44f916 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 9 Mar 2015 13:56:12 +0100 Subject: at86rf230: fix volatile regmap registers These registers are also changed by transceiver and should be volatile for right accessing via regmap debugfs. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 795106c23097..b64c5c7b2a50 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -421,6 +421,8 @@ at86rf230_reg_volatile(struct device *dev, unsigned int reg) case RG_PHY_ED_LEVEL: case RG_IRQ_STATUS: case RG_VREG_CTRL: + case RG_PLL_CF: + case RG_PLL_DCU: return true; default: return false; -- cgit v1.2.3