Skip to content

Commit

Permalink
sparc64: Fix lockdep issues in LDC protocol layer.
Browse files Browse the repository at this point in the history
We're calling request_irq() with a IRQs disabled.

No straightforward fix exists because we want to
enable these IRQs and setup state atomically before
getting into the IRQ handler the first time.

What happens now is that we mark the VIRQ to not be
automatically enabled by request_irq().  Then we
make explicit enable_irq() calls when we grab the
LDC channel.

This way we don't need to call request_irq() illegally
under the LDC channel lock any more.

Bump LDC version and release date.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 23, 2008
1 parent 4a0a088 commit b7c2a75
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 20 deletions.
10 changes: 9 additions & 1 deletion arch/sparc64/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,9 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
{
struct irq_handler_data *data;
struct ino_bucket *bucket;
unsigned long hv_err, cookie;
struct ino_bucket *bucket;
struct irq_desc *desc;
unsigned int virt_irq;

bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
Expand All @@ -643,6 +644,13 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
if (unlikely(!data))
return 0;

/* In order to make the LDC channel startup sequence easier,
* especially wrt. locking, we do not let request_irq() enable
* the interrupt.
*/
desc = irq_desc + virt_irq;
desc->status |= IRQ_NOAUTOEN;

set_irq_chip_data(virt_irq, data);

/* Catch accidental accesses to these things. IMAP/ICLR handling
Expand Down
38 changes: 19 additions & 19 deletions arch/sparc64/kernel/ldc.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* ldc.c: Logical Domain Channel link-layer protocol driver.
*
* Copyright (C) 2007 David S. Miller <davem@davemloft.net>
* Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
*/

#include <linux/kernel.h>
Expand All @@ -23,8 +23,8 @@

#define DRV_MODULE_NAME "ldc"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.0"
#define DRV_MODULE_RELDATE "June 25, 2007"
#define DRV_MODULE_VERSION "1.1"
#define DRV_MODULE_RELDATE "July 22, 2008"

static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
Expand Down Expand Up @@ -1235,13 +1235,9 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
unsigned long hv_err, flags;
int err = -EINVAL;

spin_lock_irqsave(&lp->lock, flags);

if (!name)
goto out_err;

if (lp->state != LDC_STATE_INIT)
goto out_err;
if (!name ||
(lp->state != LDC_STATE_INIT))
return -EINVAL;

snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
Expand All @@ -1250,25 +1246,32 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
IRQF_SAMPLE_RANDOM | IRQF_SHARED,
lp->rx_irq_name, lp);
if (err)
goto out_err;
return err;

err = request_irq(lp->cfg.tx_irq, ldc_tx,
IRQF_SAMPLE_RANDOM | IRQF_SHARED,
lp->tx_irq_name, lp);
if (err)
goto out_free_rx_irq;
if (err) {
free_irq(lp->cfg.rx_irq, lp);
return err;
}


spin_lock_irqsave(&lp->lock, flags);

enable_irq(lp->cfg.rx_irq);
enable_irq(lp->cfg.tx_irq);

lp->flags |= LDC_FLAG_REGISTERED_IRQS;

err = -ENODEV;
hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0);
if (hv_err)
goto out_free_tx_irq;
goto out_free_irqs;

hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
if (hv_err)
goto out_free_tx_irq;
goto out_free_irqs;

hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0);
if (hv_err)
Expand Down Expand Up @@ -1304,14 +1307,11 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
out_unmap_tx:
sun4v_ldc_tx_qconf(lp->id, 0, 0);

out_free_tx_irq:
out_free_irqs:
lp->flags &= ~LDC_FLAG_REGISTERED_IRQS;
free_irq(lp->cfg.tx_irq, lp);

out_free_rx_irq:
free_irq(lp->cfg.rx_irq, lp);

out_err:
spin_unlock_irqrestore(&lp->lock, flags);

return err;
Expand Down

0 comments on commit b7c2a75

Please sign in to comment.