diff options
author | Kyle McMartin <kyle@redhat.com> | 2009-03-18 21:49:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-18 21:49:01 -0400 |
commit | 69145635d4db0a0382885b14634aa5b721f3aa1a (patch) | |
tree | 3221b6a995853fe0a29887c1f83c158477845cd3 | |
parent | 4783256ef92f5aecd6d54693b16386f2a0021c2a (diff) |
tulip: fix crash on iface up with shirq debug
Tulip is currently doing request_irq before it has done its
initialization. This is usually not a problem because it hasn't
enable interrupts yet, but with DEBUG_SHIRQ on, we call the irq handler
when registering the interrupt as a sanity check.
This can result in a NULL ptr dereference, so call tulip_init_ring
before request_irq, and add a free_ring function to do the freeing
now shared with tulip_close.
Tested with a shell loop running ifup, ifdown in a loop a few hundred
times with DEBUG_SHIRQ on.
Signed-off-by: Kyle McMartin <kyle@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/tulip/tulip_core.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index bee75fa87a9c..2abb5d3becc6 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c | |||
@@ -255,6 +255,7 @@ const char tulip_media_cap[32] = | |||
255 | 255 | ||
256 | static void tulip_tx_timeout(struct net_device *dev); | 256 | static void tulip_tx_timeout(struct net_device *dev); |
257 | static void tulip_init_ring(struct net_device *dev); | 257 | static void tulip_init_ring(struct net_device *dev); |
258 | static void tulip_free_ring(struct net_device *dev); | ||
258 | static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); | 259 | static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev); |
259 | static int tulip_open(struct net_device *dev); | 260 | static int tulip_open(struct net_device *dev); |
260 | static int tulip_close(struct net_device *dev); | 261 | static int tulip_close(struct net_device *dev); |
@@ -502,16 +503,21 @@ tulip_open(struct net_device *dev) | |||
502 | { | 503 | { |
503 | int retval; | 504 | int retval; |
504 | 505 | ||
505 | if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev))) | ||
506 | return retval; | ||
507 | |||
508 | tulip_init_ring (dev); | 506 | tulip_init_ring (dev); |
509 | 507 | ||
508 | retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev); | ||
509 | if (retval) | ||
510 | goto free_ring; | ||
511 | |||
510 | tulip_up (dev); | 512 | tulip_up (dev); |
511 | 513 | ||
512 | netif_start_queue (dev); | 514 | netif_start_queue (dev); |
513 | 515 | ||
514 | return 0; | 516 | return 0; |
517 | |||
518 | free_ring: | ||
519 | tulip_free_ring (dev); | ||
520 | return retval; | ||
515 | } | 521 | } |
516 | 522 | ||
517 | 523 | ||
@@ -768,23 +774,11 @@ static void tulip_down (struct net_device *dev) | |||
768 | tulip_set_power_state (tp, 0, 1); | 774 | tulip_set_power_state (tp, 0, 1); |
769 | } | 775 | } |
770 | 776 | ||
771 | 777 | static void tulip_free_ring (struct net_device *dev) | |
772 | static int tulip_close (struct net_device *dev) | ||
773 | { | 778 | { |
774 | struct tulip_private *tp = netdev_priv(dev); | 779 | struct tulip_private *tp = netdev_priv(dev); |
775 | void __iomem *ioaddr = tp->base_addr; | ||
776 | int i; | 780 | int i; |
777 | 781 | ||
778 | netif_stop_queue (dev); | ||
779 | |||
780 | tulip_down (dev); | ||
781 | |||
782 | if (tulip_debug > 1) | ||
783 | printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", | ||
784 | dev->name, ioread32 (ioaddr + CSR5)); | ||
785 | |||
786 | free_irq (dev->irq, dev); | ||
787 | |||
788 | /* Free all the skbuffs in the Rx queue. */ | 782 | /* Free all the skbuffs in the Rx queue. */ |
789 | for (i = 0; i < RX_RING_SIZE; i++) { | 783 | for (i = 0; i < RX_RING_SIZE; i++) { |
790 | struct sk_buff *skb = tp->rx_buffers[i].skb; | 784 | struct sk_buff *skb = tp->rx_buffers[i].skb; |
@@ -803,6 +797,7 @@ static int tulip_close (struct net_device *dev) | |||
803 | dev_kfree_skb (skb); | 797 | dev_kfree_skb (skb); |
804 | } | 798 | } |
805 | } | 799 | } |
800 | |||
806 | for (i = 0; i < TX_RING_SIZE; i++) { | 801 | for (i = 0; i < TX_RING_SIZE; i++) { |
807 | struct sk_buff *skb = tp->tx_buffers[i].skb; | 802 | struct sk_buff *skb = tp->tx_buffers[i].skb; |
808 | 803 | ||
@@ -814,6 +809,24 @@ static int tulip_close (struct net_device *dev) | |||
814 | tp->tx_buffers[i].skb = NULL; | 809 | tp->tx_buffers[i].skb = NULL; |
815 | tp->tx_buffers[i].mapping = 0; | 810 | tp->tx_buffers[i].mapping = 0; |
816 | } | 811 | } |
812 | } | ||
813 | |||
814 | static int tulip_close (struct net_device *dev) | ||
815 | { | ||
816 | struct tulip_private *tp = netdev_priv(dev); | ||
817 | void __iomem *ioaddr = tp->base_addr; | ||
818 | |||
819 | netif_stop_queue (dev); | ||
820 | |||
821 | tulip_down (dev); | ||
822 | |||
823 | if (tulip_debug > 1) | ||
824 | printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", | ||
825 | dev->name, ioread32 (ioaddr + CSR5)); | ||
826 | |||
827 | free_irq (dev->irq, dev); | ||
828 | |||
829 | tulip_free_ring (dev); | ||
817 | 830 | ||
818 | return 0; | 831 | return 0; |
819 | } | 832 | } |