Commit 97fed795 authored by Alexander Aring's avatar Alexander Aring Committed by Marcel Holtmann

at86rf230: fix enable_irq handling on async spi

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: default avatarAlexander Aring <alex.aring@gmail.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 35e92a8e
......@@ -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) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment