diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-09-24 04:31:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-24 18:39:26 -0400 |
commit | 704cc92e9ffe29458ea8831ae097c631b1160c01 (patch) | |
tree | 5ef8846d23a73deb54e9694a936185402986e250 /drivers/net/3c59x.c | |
parent | a43912ab1925788765208da5cd664b6f8e011d08 (diff) |
3c59x: Get rid of "Trying to free already-free IRQ"
Following trace pops up if we try to suspend with 3c59x ethernet NIC
brought down:
root@b1:~# ifconfig eth16 down
root@b1:~# echo mem > /sys/power/state
...
3c59x 0000:00:10.0: suspend
3c59x 0000:00:10.0: PME# disabled
Trying to free already-free IRQ 48
------------[ cut here ]------------
Badness at c00554e4 [verbose debug info unavailable]
NIP: c00554e4 LR: c00554e4 CTR: c019a098
REGS: c7975c60 TRAP: 0700 Not tainted (2.6.31-rc4)
MSR: 00021032 <ME,CE,IR,DR> CR: 28242422 XER: 20000000
TASK = c79cb0c0[1746] 'bash' THREAD: c7974000
...
NIP [c00554e4] __free_irq+0x108/0x1b0
LR [c00554e4] __free_irq+0x108/0x1b0
Call Trace:
[c7975d10] [c00554e4] __free_irq+0x108/0x1b0 (unreliable)
[c7975d30] [c005559c] free_irq+0x10/0x24
[c7975d40] [c01e21ec] vortex_suspend+0x70/0xc4
[c7975d60] [c017e584] pci_legacy_suspend+0x58/0x100
This is because the driver manages interrupts without checking for
netif_running().
Though, there are few other issues with suspend/resume in this driver.
The intention of calling free_irq() in suspend() was to avoid any
possible spurious interrupts (see commit 5b039e681b8c5f30aac9cc04385
"3c59x PM fixes"). But,
- On resume, the driver was requesting IRQ just after pci_set_master(),
but before vortex_up() (which actually resets 3c59x chips).
- Issuing free_irq() on a shared IRQ doesn't guarantee that a buggy
HW won't trigger spurious interrupts in another driver that
requested the same interrupt. So, if we want to protect from
unexpected interrupts, then on suspend we should issue disable_irq(),
not free_irq().
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/3c59x.c')
-rw-r--r-- | drivers/net/3c59x.c | 12 |
1 files changed, 3 insertions, 9 deletions
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 7adff4d0960d..b9eeadf01b74 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c | |||
@@ -813,10 +813,10 @@ static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) | |||
813 | if (netif_running(dev)) { | 813 | if (netif_running(dev)) { |
814 | netif_device_detach(dev); | 814 | netif_device_detach(dev); |
815 | vortex_down(dev, 1); | 815 | vortex_down(dev, 1); |
816 | disable_irq(dev->irq); | ||
816 | } | 817 | } |
817 | pci_save_state(pdev); | 818 | pci_save_state(pdev); |
818 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | 819 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); |
819 | free_irq(dev->irq, dev); | ||
820 | pci_disable_device(pdev); | 820 | pci_disable_device(pdev); |
821 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 821 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); |
822 | } | 822 | } |
@@ -839,18 +839,12 @@ static int vortex_resume(struct pci_dev *pdev) | |||
839 | return err; | 839 | return err; |
840 | } | 840 | } |
841 | pci_set_master(pdev); | 841 | pci_set_master(pdev); |
842 | if (request_irq(dev->irq, vp->full_bus_master_rx ? | ||
843 | &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) { | ||
844 | pr_warning("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); | ||
845 | pci_disable_device(pdev); | ||
846 | return -EBUSY; | ||
847 | } | ||
848 | if (netif_running(dev)) { | 842 | if (netif_running(dev)) { |
849 | err = vortex_up(dev); | 843 | err = vortex_up(dev); |
850 | if (err) | 844 | if (err) |
851 | return err; | 845 | return err; |
852 | else | 846 | enable_irq(dev->irq); |
853 | netif_device_attach(dev); | 847 | netif_device_attach(dev); |
854 | } | 848 | } |
855 | } | 849 | } |
856 | return 0; | 850 | return 0; |