at86rf230: fix enable_irq handling on async spi
authorAlexander Aring <alex.aring@gmail.com>
Tue, 7 Oct 2014 08:38:32 +0000 (10:38 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 25 Oct 2014 05:56:23 +0000 (07:56 +0200)
Sometimes the async state function is call in an context where the spi
irq is diabled. This patch fix the handling to enable the irq when
spi_async failed in the async state change calling chain. We do this by
a context parameter irq_enable and evaluate this parameter when
spi_async failed instead of returning spi_async errno.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/net/ieee802154/at86rf230.c

index 5dbec64eb7868f9bcf307ad8b26a663d8d8e5c09..7a1a8e39b1308f4a8e551161ac9bdb272acd653d 100644 (file)
@@ -74,6 +74,8 @@ struct at86rf230_state_change {
        void (*complete)(void *context);
        u8 from_state;
        u8 to_state;
+
+       bool irq_enable;
 };
 
 struct at86rf230_local {
@@ -292,10 +294,11 @@ struct at86rf230_local {
 
 #define AT86RF2XX_NUMREGS 0x3F
 
-static int
+static void
 at86rf230_async_state_change(struct at86rf230_local *lp,
                             struct at86rf230_state_change *ctx,
-                            const u8 state, void (*complete)(void *context));
+                            const u8 state, void (*complete)(void *context),
+                            const bool irq_enable);
 
 static inline int
 __at86rf230_write(struct at86rf230_local *lp,
@@ -452,7 +455,7 @@ at86rf230_async_error_recover(void *context)
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
 
-       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL);
+       at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON, NULL, false);
 }
 
 static void
@@ -462,21 +465,31 @@ at86rf230_async_error(struct at86rf230_local *lp,
        dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
 
        at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
-                                    at86rf230_async_error_recover);
+                                    at86rf230_async_error_recover, false);
 }
 
 /* Generic function to get some register value in async mode */
-static int
+static void
 at86rf230_async_read_reg(struct at86rf230_local *lp, const u8 reg,
                         struct at86rf230_state_change *ctx,
-                        void (*complete)(void *context))
+                        void (*complete)(void *context),
+                        const bool irq_enable)
 {
+       int rc;
+
        u8 *tx_buf = ctx->buf;
 
        tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
        ctx->trx.len = 2;
        ctx->msg.complete = complete;
-       return spi_async(lp->spi, &ctx->msg);
+       ctx->irq_enable = irq_enable;
+       rc = spi_async(lp->spi, &ctx->msg);
+       if (rc) {
+               if (irq_enable)
+                       enable_irq(lp->spi->irq);
+
+               at86rf230_async_error(lp, ctx, rc);
+       }
 }
 
 static void
@@ -513,7 +526,8 @@ at86rf230_async_state_assert(void *context)
                        if (ctx->to_state == STATE_TX_ON) {
                                at86rf230_async_state_change(lp, ctx,
                                                             STATE_FORCE_TX_ON,
-                                                            ctx->complete);
+                                                            ctx->complete,
+                                                            ctx->irq_enable);
                                return;
                        }
                }
@@ -536,7 +550,6 @@ at86rf230_async_state_delay(void *context)
        struct at86rf230_local *lp = ctx->lp;
        struct at86rf2xx_chip_data *c = lp->data;
        bool force = false;
-       int rc;
 
        /* The force state changes are will show as normal states in the
         * state status subregister. We change the to_state to the
@@ -605,10 +618,9 @@ at86rf230_async_state_delay(void *context)
        udelay(1);
 
 change:
-       rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                     at86rf230_async_state_assert);
-       if (rc)
-               dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+       at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                at86rf230_async_state_assert,
+                                ctx->irq_enable);
 }
 
 static void
@@ -623,10 +635,9 @@ at86rf230_async_state_change_start(void *context)
        /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
        if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
                udelay(1);
-               rc = at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                             at86rf230_async_state_change_start);
-               if (rc)
-                       dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+               at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                        at86rf230_async_state_change_start,
+                                        ctx->irq_enable);
                return;
        }
 
@@ -648,20 +659,28 @@ at86rf230_async_state_change_start(void *context)
        ctx->trx.len = 2;
        ctx->msg.complete = at86rf230_async_state_delay;
        rc = spi_async(lp->spi, &ctx->msg);
-       if (rc)
+       if (rc) {
+               if (ctx->irq_enable)
+                       enable_irq(lp->spi->irq);
+
+               at86rf230_async_error(lp, &lp->state, rc);
                dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
+       }
 }
 
-static int
+static void
 at86rf230_async_state_change(struct at86rf230_local *lp,
                             struct at86rf230_state_change *ctx,
-                            const u8 state, void (*complete)(void *context))
+                            const u8 state, void (*complete)(void *context),
+                            const bool irq_enable)
 {
        /* Initialization for the state change context */
        ctx->to_state = state;
        ctx->complete = complete;
-       return at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
-                                       at86rf230_async_state_change_start);
+       ctx->irq_enable = irq_enable;
+       at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
+                                at86rf230_async_state_change_start,
+                                irq_enable);
 }
 
 static void
@@ -682,12 +701,9 @@ at86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state)
 {
        int rc;
 
-       rc = at86rf230_async_state_change(lp, &lp->state, state,
-                                         at86rf230_sync_state_change_complete);
-       if (rc) {
-               at86rf230_async_error(lp, &lp->state, rc);
-               return rc;
-       }
+       at86rf230_async_state_change(lp, &lp->state, state,
+                                    at86rf230_sync_state_change_complete,
+                                    false);
 
        rc = wait_for_completion_timeout(&lp->state_complete,
                                         msecs_to_jiffies(100));
@@ -714,12 +730,9 @@ at86rf230_tx_on(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
-                                         at86rf230_tx_complete);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, &lp->irq, STATE_RX_AACK_ON,
+                                    at86rf230_tx_complete, true);
 }
 
 static void
@@ -727,12 +740,9 @@ at86rf230_tx_trac_error(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                         at86rf230_tx_on);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
+                                    at86rf230_tx_on, true);
 }
 
 static void
@@ -742,17 +752,14 @@ at86rf230_tx_trac_check(void *context)
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = ctx->buf;
        const u8 trac = (buf[1] & 0xe0) >> 5;
-       int rc;
 
        /* If trac status is different than zero we need to do a state change
         * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
         * state to TX_ON.
         */
        if (trac) {
-               rc = at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
-                                                 at86rf230_tx_trac_error);
-               if (rc)
-                       at86rf230_async_error(lp, ctx, rc);
+               at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
+                                            at86rf230_tx_trac_error, true);
                return;
        }
 
@@ -765,12 +772,9 @@ at86rf230_tx_trac_status(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
-                                     at86rf230_tx_trac_check);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
+                                at86rf230_tx_trac_check, true);
 }
 
 static void
@@ -823,15 +827,21 @@ at86rf230_rx_read_frame_complete(void *context)
        at86rf230_rx(lp, buf + 2, len);
 }
 
-static int
+static void
 at86rf230_rx_read_frame(struct at86rf230_local *lp)
 {
+       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;
-       return spi_async(lp->spi, &lp->irq.msg);
+       rc = spi_async(lp->spi, &lp->irq.msg);
+       if (rc) {
+               enable_irq(lp->spi->irq);
+               at86rf230_async_error(lp, &lp->irq, rc);
+       }
 }
 
 static void
@@ -839,7 +849,6 @@ at86rf230_rx_trac_check(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
        /* 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
@@ -847,14 +856,10 @@ at86rf230_rx_trac_check(void *context)
         * The programming guide say do it so.
         */
 
-       rc = at86rf230_rx_read_frame(lp);
-       if (rc) {
-               enable_irq(lp->spi->irq);
-               at86rf230_async_error(lp, ctx, rc);
-       }
+       at86rf230_rx_read_frame(lp);
 }
 
-static int
+static void
 at86rf230_irq_trx_end(struct at86rf230_local *lp)
 {
        spin_lock(&lp->lock);
@@ -863,17 +868,19 @@ at86rf230_irq_trx_end(struct at86rf230_local *lp)
                spin_unlock(&lp->lock);
 
                if (lp->tx_aret)
-                       return at86rf230_async_state_change(lp, &lp->irq,
-                                                           STATE_FORCE_TX_ON,
-                                                           at86rf230_tx_trac_status);
+                       at86rf230_async_state_change(lp, &lp->irq,
+                                                    STATE_FORCE_TX_ON,
+                                                    at86rf230_tx_trac_status,
+                                                    true);
                else
-                       return at86rf230_async_state_change(lp, &lp->irq,
-                                                           STATE_RX_AACK_ON,
-                                                           at86rf230_tx_complete);
+                       at86rf230_async_state_change(lp, &lp->irq,
+                                                    STATE_RX_AACK_ON,
+                                                    at86rf230_tx_complete,
+                                                    true);
        } else {
                spin_unlock(&lp->lock);
-               return at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
-                                               at86rf230_rx_trac_check);
+               at86rf230_async_read_reg(lp, RG_TRX_STATE, &lp->irq,
+                                        at86rf230_rx_trac_check, true);
        }
 }
 
@@ -884,12 +891,9 @@ at86rf230_irq_status(void *context)
        struct at86rf230_local *lp = ctx->lp;
        const u8 *buf = lp->irq.buf;
        const u8 irq = buf[1];
-       int rc;
 
        if (irq & IRQ_TRX_END) {
-               rc = at86rf230_irq_trx_end(lp);
-               if (rc)
-                       at86rf230_async_error(lp, ctx, rc);
+               at86rf230_irq_trx_end(lp);
        } else {
                enable_irq(lp->spi->irq);
                dev_err(&lp->spi->dev, "not supported irq %02x received\n",
@@ -964,12 +968,9 @@ at86rf230_xmit_tx_on(void *context)
 {
        struct at86rf230_state_change *ctx = context;
        struct at86rf230_local *lp = ctx->lp;
-       int rc;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
-                                         at86rf230_write_frame);
-       if (rc)
-               at86rf230_async_error(lp, ctx, rc);
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
+                                    at86rf230_write_frame, false);
 }
 
 static int
@@ -990,12 +991,8 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        if (lp->tx_aret)
                tx_complete = at86rf230_xmit_tx_on;
 
-       rc = at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
-                                         tx_complete);
-       if (rc) {
-               at86rf230_async_error(lp, ctx, rc);
-               return rc;
-       }
+       at86rf230_async_state_change(lp, ctx, STATE_TX_ON, tx_complete, false);
+
        rc = wait_for_completion_interruptible_timeout(&lp->tx_complete,
                                                       msecs_to_jiffies(lp->data->t_tx_timeout));
        if (!rc) {