Skip to content

Commit

Permalink
Merge branch 'mrf24j40'
Browse files Browse the repository at this point in the history
Alan Ott says:

====================
Fix race conditions in mrf24j40 interrupts

After testing with the betas of this patchset, it's been rebased and is
ready for inclusion.

David Hauweele noticed that the mrf24j40 would hang arbitrarily after some
period of heavy traffic.  Two race conditions were discovered, and the
driver was changed to use threaded interrupts, since the enable/disable of
interrupts in the driver has recently been a lighning rod whenever issues
arise related to interrupts (costing engineering time), and since threaded
interrupts are the right way to do it.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Oct 8, 2013
2 parents 8cc27d1 + 40afbb6 commit 66e358a
Showing 1 changed file with 9 additions and 22 deletions.
31 changes: 9 additions & 22 deletions drivers/net/ieee802154/mrf24j40.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ struct mrf24j40 {

struct mutex buffer_mutex; /* only used to protect buf */
struct completion tx_complete;
struct work_struct irqwork;
u8 *buf; /* 3 bytes. Used for SPI single-register transfers. */
};

Expand Down Expand Up @@ -344,6 +343,8 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
if (ret)
goto err;

INIT_COMPLETION(devrec->tx_complete);

/* Set TXNTRIG bit of TXNCON to send packet */
ret = read_short_reg(devrec, REG_TXNCON, &val);
if (ret)
Expand All @@ -354,8 +355,6 @@ static int mrf24j40_tx(struct ieee802154_dev *dev, struct sk_buff *skb)
val |= 0x4;
write_short_reg(devrec, REG_TXNCON, val);

INIT_COMPLETION(devrec->tx_complete);

/* Wait for the device to send the TX complete interrupt. */
ret = wait_for_completion_interruptible_timeout(
&devrec->tx_complete,
Expand Down Expand Up @@ -590,17 +589,6 @@ static struct ieee802154_ops mrf24j40_ops = {
static irqreturn_t mrf24j40_isr(int irq, void *data)
{
struct mrf24j40 *devrec = data;

disable_irq_nosync(irq);

schedule_work(&devrec->irqwork);

return IRQ_HANDLED;
}

static void mrf24j40_isrwork(struct work_struct *work)
{
struct mrf24j40 *devrec = container_of(work, struct mrf24j40, irqwork);
u8 intstat;
int ret;

Expand All @@ -618,7 +606,7 @@ static void mrf24j40_isrwork(struct work_struct *work)
mrf24j40_handle_rx(devrec);

out:
enable_irq(devrec->spi->irq);
return IRQ_HANDLED;
}

static int mrf24j40_probe(struct spi_device *spi)
Expand All @@ -642,7 +630,6 @@ static int mrf24j40_probe(struct spi_device *spi)

mutex_init(&devrec->buffer_mutex);
init_completion(&devrec->tx_complete);
INIT_WORK(&devrec->irqwork, mrf24j40_isrwork);
devrec->spi = spi;
spi_set_drvdata(spi, devrec);

Expand Down Expand Up @@ -688,11 +675,12 @@ static int mrf24j40_probe(struct spi_device *spi)
val &= ~0x3; /* Clear RX mode (normal) */
write_short_reg(devrec, REG_RXMCR, val);

ret = request_irq(spi->irq,
mrf24j40_isr,
IRQF_TRIGGER_FALLING,
dev_name(&spi->dev),
devrec);
ret = request_threaded_irq(spi->irq,
NULL,
mrf24j40_isr,
IRQF_TRIGGER_LOW|IRQF_ONESHOT,
dev_name(&spi->dev),
devrec);

if (ret) {
dev_err(printdev(devrec), "Unable to get IRQ");
Expand Down Expand Up @@ -721,7 +709,6 @@ static int mrf24j40_remove(struct spi_device *spi)
dev_dbg(printdev(devrec), "remove\n");

free_irq(spi->irq, devrec);
flush_work(&devrec->irqwork); /* TODO: Is this the right call? */
ieee802154_unregister_device(devrec->dev);
ieee802154_free_device(devrec->dev);
/* TODO: Will ieee802154_free_device() wait until ->xmit() is
Expand Down

0 comments on commit 66e358a

Please sign in to comment.