diff options
Diffstat (limited to 'drivers/net/3c59x.c')
| -rw-r--r-- | drivers/net/3c59x.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index c754d88e5ec9..179871d9e71f 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c | |||
| @@ -633,7 +633,11 @@ struct vortex_private { | |||
| 633 | open:1, | 633 | open:1, |
| 634 | medialock:1, | 634 | medialock:1, |
| 635 | must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ | 635 | must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ |
| 636 | large_frames:1; /* accept large frames */ | 636 | large_frames:1, /* accept large frames */ |
| 637 | handling_irq:1; /* private in_irq indicator */ | ||
| 638 | /* {get|set}_wol operations are already serialized by rtnl. | ||
| 639 | * no additional locking is required for the enable_wol and acpi_set_WOL() | ||
| 640 | */ | ||
| 637 | int drv_flags; | 641 | int drv_flags; |
| 638 | u16 status_enable; | 642 | u16 status_enable; |
| 639 | u16 intr_enable; | 643 | u16 intr_enable; |
| @@ -646,7 +650,7 @@ struct vortex_private { | |||
| 646 | u16 io_size; /* Size of PCI region (for release_region) */ | 650 | u16 io_size; /* Size of PCI region (for release_region) */ |
| 647 | 651 | ||
| 648 | /* Serialises access to hardware other than MII and variables below. | 652 | /* Serialises access to hardware other than MII and variables below. |
| 649 | * The lock hierarchy is rtnl_lock > lock > mii_lock > window_lock. */ | 653 | * The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */ |
| 650 | spinlock_t lock; | 654 | spinlock_t lock; |
| 651 | 655 | ||
| 652 | spinlock_t mii_lock; /* Serialises access to MII */ | 656 | spinlock_t mii_lock; /* Serialises access to MII */ |
| @@ -1993,10 +1997,9 @@ vortex_error(struct net_device *dev, int status) | |||
| 1993 | } | 1997 | } |
| 1994 | } | 1998 | } |
| 1995 | 1999 | ||
| 1996 | if (status & RxEarly) { /* Rx early is unused. */ | 2000 | if (status & RxEarly) /* Rx early is unused. */ |
| 1997 | vortex_rx(dev); | ||
| 1998 | iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD); | 2001 | iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD); |
| 1999 | } | 2002 | |
| 2000 | if (status & StatsFull) { /* Empty statistics. */ | 2003 | if (status & StatsFull) { /* Empty statistics. */ |
| 2001 | static int DoneDidThat; | 2004 | static int DoneDidThat; |
| 2002 | if (vortex_debug > 4) | 2005 | if (vortex_debug > 4) |
| @@ -2133,6 +2136,15 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 2133 | dev->name, vp->cur_tx); | 2136 | dev->name, vp->cur_tx); |
| 2134 | } | 2137 | } |
| 2135 | 2138 | ||
| 2139 | /* | ||
| 2140 | * We can't allow a recursion from our interrupt handler back into the | ||
| 2141 | * tx routine, as they take the same spin lock, and that causes | ||
| 2142 | * deadlock. Just return NETDEV_TX_BUSY and let the stack try again in | ||
| 2143 | * a bit | ||
| 2144 | */ | ||
| 2145 | if (vp->handling_irq) | ||
| 2146 | return NETDEV_TX_BUSY; | ||
| 2147 | |||
| 2136 | if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { | 2148 | if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { |
| 2137 | if (vortex_debug > 0) | 2149 | if (vortex_debug > 0) |
| 2138 | pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", | 2150 | pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", |
| @@ -2288,7 +2300,12 @@ vortex_interrupt(int irq, void *dev_id) | |||
| 2288 | if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { | 2300 | if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { |
| 2289 | if (status == 0xffff) | 2301 | if (status == 0xffff) |
| 2290 | break; | 2302 | break; |
| 2303 | if (status & RxEarly) | ||
| 2304 | vortex_rx(dev); | ||
| 2305 | spin_unlock(&vp->window_lock); | ||
| 2291 | vortex_error(dev, status); | 2306 | vortex_error(dev, status); |
| 2307 | spin_lock(&vp->window_lock); | ||
| 2308 | window_set(vp, 7); | ||
| 2292 | } | 2309 | } |
| 2293 | 2310 | ||
| 2294 | if (--work_done < 0) { | 2311 | if (--work_done < 0) { |
| @@ -2335,11 +2352,13 @@ boomerang_interrupt(int irq, void *dev_id) | |||
| 2335 | 2352 | ||
| 2336 | ioaddr = vp->ioaddr; | 2353 | ioaddr = vp->ioaddr; |
| 2337 | 2354 | ||
| 2355 | |||
| 2338 | /* | 2356 | /* |
| 2339 | * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout | 2357 | * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout |
| 2340 | * and boomerang_start_xmit | 2358 | * and boomerang_start_xmit |
| 2341 | */ | 2359 | */ |
| 2342 | spin_lock(&vp->lock); | 2360 | spin_lock(&vp->lock); |
| 2361 | vp->handling_irq = 1; | ||
| 2343 | 2362 | ||
| 2344 | status = ioread16(ioaddr + EL3_STATUS); | 2363 | status = ioread16(ioaddr + EL3_STATUS); |
| 2345 | 2364 | ||
| @@ -2447,6 +2466,7 @@ boomerang_interrupt(int irq, void *dev_id) | |||
| 2447 | pr_debug("%s: exiting interrupt, status %4.4x.\n", | 2466 | pr_debug("%s: exiting interrupt, status %4.4x.\n", |
| 2448 | dev->name, status); | 2467 | dev->name, status); |
| 2449 | handler_exit: | 2468 | handler_exit: |
| 2469 | vp->handling_irq = 0; | ||
| 2450 | spin_unlock(&vp->lock); | 2470 | spin_unlock(&vp->lock); |
| 2451 | return IRQ_HANDLED; | 2471 | return IRQ_HANDLED; |
| 2452 | } | 2472 | } |
| @@ -2922,28 +2942,31 @@ static void vortex_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | |||
| 2922 | { | 2942 | { |
| 2923 | struct vortex_private *vp = netdev_priv(dev); | 2943 | struct vortex_private *vp = netdev_priv(dev); |
| 2924 | 2944 | ||
| 2925 | spin_lock_irq(&vp->lock); | 2945 | if (!VORTEX_PCI(vp)) |
| 2946 | return; | ||
| 2947 | |||
| 2926 | wol->supported = WAKE_MAGIC; | 2948 | wol->supported = WAKE_MAGIC; |
| 2927 | 2949 | ||
| 2928 | wol->wolopts = 0; | 2950 | wol->wolopts = 0; |
| 2929 | if (vp->enable_wol) | 2951 | if (vp->enable_wol) |
| 2930 | wol->wolopts |= WAKE_MAGIC; | 2952 | wol->wolopts |= WAKE_MAGIC; |
| 2931 | spin_unlock_irq(&vp->lock); | ||
| 2932 | } | 2953 | } |
| 2933 | 2954 | ||
| 2934 | static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | 2955 | static int vortex_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) |
| 2935 | { | 2956 | { |
| 2936 | struct vortex_private *vp = netdev_priv(dev); | 2957 | struct vortex_private *vp = netdev_priv(dev); |
| 2958 | |||
| 2959 | if (!VORTEX_PCI(vp)) | ||
| 2960 | return -EOPNOTSUPP; | ||
| 2961 | |||
| 2937 | if (wol->wolopts & ~WAKE_MAGIC) | 2962 | if (wol->wolopts & ~WAKE_MAGIC) |
| 2938 | return -EINVAL; | 2963 | return -EINVAL; |
| 2939 | 2964 | ||
| 2940 | spin_lock_irq(&vp->lock); | ||
| 2941 | if (wol->wolopts & WAKE_MAGIC) | 2965 | if (wol->wolopts & WAKE_MAGIC) |
| 2942 | vp->enable_wol = 1; | 2966 | vp->enable_wol = 1; |
| 2943 | else | 2967 | else |
| 2944 | vp->enable_wol = 0; | 2968 | vp->enable_wol = 0; |
| 2945 | acpi_set_WOL(dev); | 2969 | acpi_set_WOL(dev); |
| 2946 | spin_unlock_irq(&vp->lock); | ||
| 2947 | 2970 | ||
| 2948 | return 0; | 2971 | return 0; |
| 2949 | } | 2972 | } |
| @@ -2971,7 +2994,6 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
| 2971 | { | 2994 | { |
| 2972 | int err; | 2995 | int err; |
| 2973 | struct vortex_private *vp = netdev_priv(dev); | 2996 | struct vortex_private *vp = netdev_priv(dev); |
| 2974 | unsigned long flags; | ||
| 2975 | pci_power_t state = 0; | 2997 | pci_power_t state = 0; |
| 2976 | 2998 | ||
| 2977 | if(VORTEX_PCI(vp)) | 2999 | if(VORTEX_PCI(vp)) |
| @@ -2981,9 +3003,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
| 2981 | 3003 | ||
| 2982 | if(state != 0) | 3004 | if(state != 0) |
| 2983 | pci_set_power_state(VORTEX_PCI(vp), PCI_D0); | 3005 | pci_set_power_state(VORTEX_PCI(vp), PCI_D0); |
| 2984 | spin_lock_irqsave(&vp->lock, flags); | ||
| 2985 | err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL); | 3006 | err = generic_mii_ioctl(&vp->mii, if_mii(rq), cmd, NULL); |
| 2986 | spin_unlock_irqrestore(&vp->lock, flags); | ||
| 2987 | if(state != 0) | 3007 | if(state != 0) |
| 2988 | pci_set_power_state(VORTEX_PCI(vp), state); | 3008 | pci_set_power_state(VORTEX_PCI(vp), state); |
| 2989 | 3009 | ||
| @@ -3188,6 +3208,9 @@ static void acpi_set_WOL(struct net_device *dev) | |||
| 3188 | return; | 3208 | return; |
| 3189 | } | 3209 | } |
| 3190 | 3210 | ||
| 3211 | if (VORTEX_PCI(vp)->current_state < PCI_D3hot) | ||
| 3212 | return; | ||
| 3213 | |||
| 3191 | /* Change the power state to D3; RxEnable doesn't take effect. */ | 3214 | /* Change the power state to D3; RxEnable doesn't take effect. */ |
| 3192 | pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot); | 3215 | pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot); |
| 3193 | } | 3216 | } |
