usbnet: fix skb traversing races during unlink(v2)
[linux-2.6.git] / drivers / net / 3c59x.c
index a045559..8cc2256 100644 (file)
@@ -635,6 +635,9 @@ struct vortex_private {
                must_free_region:1,                             /* Flag: if zero, Cardbus owns the I/O region */
                large_frames:1,                 /* accept large frames */
                handling_irq:1;                 /* private in_irq indicator */
+       /* {get|set}_wol operations are already serialized by rtnl.
+        * no additional locking is required for the enable_wol and acpi_set_WOL()
+        */
        int drv_flags;
        u16 status_enable;
        u16 intr_enable;
@@ -696,7 +699,8 @@ DEFINE_WINDOW_IO(32)
 #define DEVICE_PCI(dev) NULL
 #endif
 
-#define VORTEX_PCI(vp) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL)
+#define VORTEX_PCI(vp)                                                 \
+       ((struct pci_dev *) (((vp)->gendev) ? DEVICE_PCI((vp)->gendev) : NULL))
 
 #ifdef CONFIG_EISA
 #define DEVICE_EISA(dev) (((dev)->bus == &eisa_bus_type) ? to_eisa_device((dev)) : NULL)
@@ -704,7 +708,8 @@ DEFINE_WINDOW_IO(32)
 #define DEVICE_EISA(dev) NULL
 #endif
 
-#define VORTEX_EISA(vp) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL)
+#define VORTEX_EISA(vp)                                                        \
+       ((struct eisa_device *) (((vp)->gendev) ? DEVICE_EISA((vp)->gendev) : NULL))
 
 /* The action to take with a media selection timer tick.
    Note that we deviate from the 3Com order by checking 10base2 before AUI.
@@ -979,7 +984,7 @@ static int __init vortex_eisa_init(void)
                 * any device have been found when we exit from
                 * eisa_driver_register (the bus root driver may not be
                 * initialized yet). So we blindly assume something was
-                * found, and let the sysfs magic happend...
+                * found, and let the sysfs magic happened...
                 */
                eisa_found = 1;
        }
@@ -1739,7 +1744,7 @@ vortex_open(struct net_device *dev)
 
        /* Use the now-standard shared IRQ implementation. */
        if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
-                               &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
+                               boomerang_interrupt : vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
                pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
                goto err;
        }
@@ -1994,10 +1999,9 @@ vortex_error(struct net_device *dev, int status)
                }
        }
 
-       if (status & RxEarly) {                         /* Rx early is unused. */
-               vortex_rx(dev);
+       if (status & RxEarly)                           /* Rx early is unused. */
                iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD);
-       }
+
        if (status & StatsFull) {                       /* Empty statistics. */
                static int DoneDidThat;
                if (vortex_debug > 4)
@@ -2298,7 +2302,12 @@ vortex_interrupt(int irq, void *dev_id)
                if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
                        if (status == 0xffff)
                                break;
+                       if (status & RxEarly)
+                               vortex_rx(dev);
+                       spin_unlock(&vp->window_lock);
                        vortex_error(dev, status);
+                       spin_lock(&vp->window_lock);
+                       window_set(vp, 7);
                }
 
                if (--work_done < 0) {
@@ -2935,28 +2944,31 @@ static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct vortex_private *vp = netdev_priv(dev);
 
-       spin_lock_irq(&vp->lock);
+       if (!VORTEX_PCI(vp))
+               return;
+
        wol->supported = WAKE_MAGIC;
 
        wol->wolopts = 0;
        if (vp->enable_wol)
                wol->wolopts |= WAKE_MAGIC;
-       spin_unlock_irq(&vp->lock);
 }
 
 static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct vortex_private *vp = netdev_priv(dev);
+
+       if (!VORTEX_PCI(vp))
+               return -EOPNOTSUPP;
+
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
 
-       spin_lock_irq(&vp->lock);
        if (wol->wolopts & WAKE_MAGIC)
                vp->enable_wol = 1;
        else
                vp->enable_wol = 0;
        acpi_set_WOL(dev);
-       spin_unlock_irq(&vp->lock);
 
        return 0;
 }
@@ -3198,6 +3210,9 @@ static void acpi_set_WOL(struct net_device *dev)
                        return;
                }
 
+               if (VORTEX_PCI(vp)->current_state < PCI_D3hot)
+                       return;
+
                /* Change the power state to D3; RxEnable doesn't take effect. */
                pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
        }