Skip to content

Commit

Permalink
hostap: Protect against initialization interrupt
Browse files Browse the repository at this point in the history
Use an irq spinlock to hold off the IRQ handler until
enough early card init is complete such that the handler
can run without faulting.

Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Tim Gardner authored and John W. Linville committed Jun 15, 2010
1 parent a69b03e commit d6a574f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
15 changes: 13 additions & 2 deletions drivers/net/wireless/hostap/hostap_cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ static int prism2_config(struct pcmcia_device *link)
local_info_t *local;
int ret = 1;
struct hostap_cs_priv *hw_priv;
unsigned long flags;

PDEBUG(DEBUG_FLOW, "prism2_config()\n");

Expand Down Expand Up @@ -625,9 +626,15 @@ static int prism2_config(struct pcmcia_device *link)
local->hw_priv = hw_priv;
hw_priv->link = link;

/*
* Make sure the IRQ handler cannot proceed until at least
* dev->base_addr is initialized.
*/
spin_lock_irqsave(&local->irq_init_lock, flags);

ret = pcmcia_request_irq(link, prism2_interrupt);
if (ret)
goto failed;
goto failed_unlock;

/*
* This actually configures the PCMCIA socket -- setting up
Expand All @@ -636,11 +643,13 @@ static int prism2_config(struct pcmcia_device *link)
*/
ret = pcmcia_request_configuration(link, &link->conf);
if (ret)
goto failed;
goto failed_unlock;

dev->irq = link->irq;
dev->base_addr = link->io.BasePort1;

spin_unlock_irqrestore(&local->irq_init_lock, flags);

/* Finally, report what we've done */
printk(KERN_INFO "%s: index 0x%02x: ",
dev_info, link->conf.ConfigIndex);
Expand All @@ -667,6 +676,8 @@ static int prism2_config(struct pcmcia_device *link)

return ret;

failed_unlock:
spin_unlock_irqrestore(&local->irq_init_lock, flags);
failed:
kfree(hw_priv);
prism2_release((u_long)link);
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/wireless/hostap/hostap_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2621,6 +2621,18 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
iface = netdev_priv(dev);
local = iface->local;

/* Detect early interrupt before driver is fully configued */
spin_lock(&local->irq_init_lock);
if (!dev->base_addr) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
dev->name);
}
spin_unlock(&local->irq_init_lock);
return IRQ_HANDLED;
}
spin_unlock(&local->irq_init_lock);

prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);

if (local->func->card_present && !local->func->card_present(local)) {
Expand Down Expand Up @@ -3138,6 +3150,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
spin_lock_init(&local->cmdlock);
spin_lock_init(&local->baplock);
spin_lock_init(&local->lock);
spin_lock_init(&local->irq_init_lock);
mutex_init(&local->rid_bap_mtx);

if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/hostap/hostap_wlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ struct local_info {
rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
* when removing entries from the list.
* TX and RX paths can use read lock. */
spinlock_t cmdlock, baplock, lock;
spinlock_t cmdlock, baplock, lock, irq_init_lock;
struct mutex rid_bap_mtx;
u16 infofid; /* MAC buffer id for info frame */
/* txfid, intransmitfid, next_txtid, and next_alloc are protected by
Expand Down

0 comments on commit d6a574f

Please sign in to comment.