]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
hostap: Protect against initialization interrupt
authorTim Gardner <tim.gardner@canonical.com>
Tue, 8 Jun 2010 17:33:02 +0000 (11:33 -0600)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 2 Aug 2010 17:29:30 +0000 (10:29 -0700)
commit d6a574ff6bfb842bdb98065da053881ff527be46 upstream.

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>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_wlan.h

index a36501dbbe02471ecdb3eb58f455134b0ac130d4..f33e18ecac6ac06aa741c38c716b3e8db80c0ead 100644 (file)
@@ -603,6 +603,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");
 
@@ -636,6 +637,12 @@ static int prism2_config(struct pcmcia_device *link)
        strcpy(hw_priv->node.dev_name, dev->name);
        link->dev_node = &hw_priv->node;
 
+       /*
+        * Make sure the IRQ handler cannot proceed until at least
+        * dev->base_addr is initialized.
+        */
+       spin_lock_irqsave(&local->irq_init_lock, flags);
+
        /*
         * Allocate an interrupt line.  Note that this does not assign a
         * handler to the interrupt, unless the 'Handler' member of the
@@ -646,7 +653,7 @@ static int prism2_config(struct pcmcia_device *link)
                link->irq.Handler = prism2_interrupt;
                ret = pcmcia_request_irq(link, &link->irq);
                if (ret)
-                       goto failed;
+                       goto failed_unlock;
        }
 
        /*
@@ -656,11 +663,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.AssignedIRQ;
        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);
@@ -689,6 +698,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);
index d70732819423d25d09627fa0bc371be5f6976896..9cad06a217c59980dcb26f5ffdd9426e39d74c64 100644 (file)
@@ -2630,6 +2630,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)) {
@@ -3147,6 +3159,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)
index 3d238917af07f32bcd16ffcf8eb75f90f824b120..1ba33be98b254ce9ef8a56fcb6c55501d14a9839 100644 (file)
@@ -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