aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-03-27 06:59:58 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2013-04-28 17:36:44 -0400
commit247fd50b5953d2b07832a07bd1d1c3b8e221fe9e (patch)
treeaad078070164b29a68e9f681ce34617d335eee31 /drivers/firewire
parentcfb0c9d1ffbf930a4a852f178b161c522b21b0ab (diff)
firewire: ohci: Fix double free_irq()
A pci device can be removed while in its suspended state. Because the ohci driver freed the irq to suspend, free_irq() is called twice; once from pci_remove() and again from pci_suspend(), which issues the warning below [1]. Rather than allocate the irq in the .enable() path, move the allocation to .probe(). Consequently, the irq is not reallocated upon pci_resume() and thus is not freed upon pci_suspend(). [1] Warning reported by Mark Einon <mark.einon@gmail.com> when suspending an MSI MS-1727 GT740 laptop on Ubuntu 3.5.0-22-generic WARNING: at ./kernel/irq/manage.c:1198 __free_irq+0xa3/0x1e0() Hardware name: MS-1727 Trying to free already-free IRQ 16 Modules linked in: ip6table_filter ip6_tables ebtable_nat ebtables <...snip...> Pid: 4, comm: kworker/0:0 Tainted: P O 3.5.0-22-generic #34-Ubuntu Call Trace: [<ffffffff81051c1f>] warn_slowpath_common+0x7f/0xc0 [<ffffffff81051d16>] warn_slowpath_fmt+0x46/0x50 [<ffffffff8103fa39>] ? default_spin_lock_flags+0x9/0x10 [<ffffffff810df6b3>] __free_irq+0xa3/0x1e0 [<ffffffff810df844>] free_irq+0x54/0xc0 [<ffffffffa005a27e>] pci_remove+0x6e/0x210 [firewire_ohci] [<ffffffff8135ae7f>] pci_device_remove+0x3f/0x110 [<ffffffff8141fdbc>] __device_release_driver+0x7c/0xe0 [<ffffffff8141fe4c>] device_release_driver+0x2c/0x40 [<ffffffff8141f5f1>] bus_remove_device+0xe1/0x120 [<ffffffff8141cd1a>] device_del+0x12a/0x1c0 [<ffffffff8141cdc6>] device_unregister+0x16/0x30 [<ffffffff81354784>] pci_stop_bus_device+0x94/0xa0 [<ffffffffa0091c67>] acpiphp_disable_slot+0xb7/0x1a0 [acpiphp] [<ffffffffa0090716>] ? get_slot_status+0x46/0xc0 [acpiphp] [<ffffffffa0091d7d>] acpiphp_check_bridge.isra.15+0x2d/0xf0 [acpiphp] [<ffffffffa0092442>] _handle_hotplug_event_bridge+0x372/0x4d0 [acpiphp] [<ffffffff81390f8c>] ? acpi_os_execute_deferred+0x2f/0x34 [<ffffffff8116e22d>] ? kfree+0xed/0x110 [<ffffffff8107086a>] process_one_work+0x12a/0x420 [<ffffffffa00920d0>] ? _handle_hotplug_event_func+0x1d0/0x1d0 [acpiphp] [<ffffffff8107141e>] worker_thread+0x12e/0x2f0 [<ffffffff810712f0>] ? manage_workers.isra.26+0x200/0x200 [<ffffffff81075f13>] kthread+0x93/0xa0 [<ffffffff8168d024>] kernel_thread_helper+0x4/0x10 [<ffffffff81075e80>] ? kthread_freezable_should_stop+0x70/0x70 [<ffffffff8168d020>] ? gs_change+0x13/0x13 Reported-by: Mark Einon <mark.einon@gmail.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/ohci.c38
1 files changed, 16 insertions, 22 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index d9be53c1d806..48889353723f 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2246,7 +2246,6 @@ static int ohci_enable(struct fw_card *card,
2246 const __be32 *config_rom, size_t length) 2246 const __be32 *config_rom, size_t length)
2247{ 2247{
2248 struct fw_ohci *ohci = fw_ohci(card); 2248 struct fw_ohci *ohci = fw_ohci(card);
2249 struct pci_dev *dev = to_pci_dev(card->device);
2250 u32 lps, version, irqs; 2249 u32 lps, version, irqs;
2251 int i, ret; 2250 int i, ret;
2252 2251
@@ -2382,24 +2381,6 @@ static int ohci_enable(struct fw_card *card,
2382 2381
2383 reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000); 2382 reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
2384 2383
2385 if (!(ohci->quirks & QUIRK_NO_MSI))
2386 pci_enable_msi(dev);
2387 if (request_irq(dev->irq, irq_handler,
2388 pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
2389 ohci_driver_name, ohci)) {
2390 dev_err(card->device, "failed to allocate interrupt %d\n",
2391 dev->irq);
2392 pci_disable_msi(dev);
2393
2394 if (config_rom) {
2395 dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
2396 ohci->next_config_rom,
2397 ohci->next_config_rom_bus);
2398 ohci->next_config_rom = NULL;
2399 }
2400 return -EIO;
2401 }
2402
2403 irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete | 2384 irqs = OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
2404 OHCI1394_RQPkt | OHCI1394_RSPkt | 2385 OHCI1394_RQPkt | OHCI1394_RSPkt |
2405 OHCI1394_isochTx | OHCI1394_isochRx | 2386 OHCI1394_isochTx | OHCI1394_isochRx |
@@ -3675,9 +3656,20 @@ static int pci_probe(struct pci_dev *dev,
3675 guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) | 3656 guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) |
3676 reg_read(ohci, OHCI1394_GUIDLo); 3657 reg_read(ohci, OHCI1394_GUIDLo);
3677 3658
3659 if (!(ohci->quirks & QUIRK_NO_MSI))
3660 pci_enable_msi(dev);
3661 if (request_irq(dev->irq, irq_handler,
3662 pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
3663 ohci_driver_name, ohci)) {
3664 dev_err(&dev->dev, "failed to allocate interrupt %d\n",
3665 dev->irq);
3666 err = -EIO;
3667 goto fail_msi;
3668 }
3669
3678 err = fw_card_add(&ohci->card, max_receive, link_speed, guid); 3670 err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
3679 if (err) 3671 if (err)
3680 goto fail_contexts; 3672 goto fail_irq;
3681 3673
3682 version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; 3674 version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
3683 dev_notice(&dev->dev, 3675 dev_notice(&dev->dev,
@@ -3688,6 +3680,10 @@ static int pci_probe(struct pci_dev *dev,
3688 3680
3689 return 0; 3681 return 0;
3690 3682
3683 fail_irq:
3684 free_irq(dev->irq, ohci);
3685 fail_msi:
3686 pci_disable_msi(dev);
3691 fail_contexts: 3687 fail_contexts:
3692 kfree(ohci->ir_context_list); 3688 kfree(ohci->ir_context_list);
3693 kfree(ohci->it_context_list); 3689 kfree(ohci->it_context_list);
@@ -3763,8 +3759,6 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
3763 int err; 3759 int err;
3764 3760
3765 software_reset(ohci); 3761 software_reset(ohci);
3766 free_irq(dev->irq, ohci);
3767 pci_disable_msi(dev);
3768 err = pci_save_state(dev); 3762 err = pci_save_state(dev);
3769 if (err) { 3763 if (err) {
3770 dev_err(&dev->dev, "pci_save_state failed\n"); 3764 dev_err(&dev->dev, "pci_save_state failed\n");