diff options
author | MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com> | 2012-02-02 11:09:22 -0500 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-02-23 15:29:35 -0500 |
commit | 7570a333d8b00e7fd4b05d898e353000a70210ce (patch) | |
tree | 0454e2690a7efb093ffe7764ea9dd235e9babf9b /drivers/pci/pcie | |
parent | 34a4876e3071ddebf3c98c99ba01c14b059a1361 (diff) |
PCI: Add pcie_hp=nomsi to disable MSI/MSI-X for pciehp driver
Add a parameter to avoid using MSI/MSI-X for PCIe native hotplug; it's
known to be buggy on some platforms.
In my environment, while shutting down, following stack trace is shown
sometimes.
irq 16: nobody cared (try booting with the "irqpoll" option)
Pid: 1081, comm: reboot Not tainted 3.2.0 #1
Call Trace:
<IRQ> [<ffffffff810cec1d>] __report_bad_irq+0x3d/0xe0
[<ffffffff810cee1c>] note_interrupt+0x15c/0x210
[<ffffffff810cc485>] handle_irq_event_percpu+0xb5/0x210
[<ffffffff810cc621>] handle_irq_event+0x41/0x70
[<ffffffff810cf675>] handle_fasteoi_irq+0x55/0xc0
[<ffffffff81015356>] handle_irq+0x46/0xb0
[<ffffffff814fbe9d>] do_IRQ+0x5d/0xe0
[<ffffffff814f146e>] common_interrupt+0x6e/0x6e
[<ffffffff8106b040>] ? __do_softirq+0x60/0x210
[<ffffffff8108aeb1>] ? hrtimer_interrupt+0x151/0x240
[<ffffffff814fb5ec>] call_softirq+0x1c/0x30
[<ffffffff810152d5>] do_softirq+0x65/0xa0
[<ffffffff8106ae9d>] irq_exit+0xbd/0xe0
[<ffffffff814fbf8e>] smp_apic_timer_interrupt+0x6e/0x99
[<ffffffff814f9e5e>] apic_timer_interrupt+0x6e/0x80
<EOI> [<ffffffff814f0fb1>] ? _raw_spin_unlock_irqrestore+0x11/0x20
[<ffffffff812629fc>] pci_bus_write_config_word+0x6c/0x80
[<ffffffff81266fc2>] pci_intx+0x52/0xa0
[<ffffffff8127de3d>] pci_intx_for_msi+0x1d/0x30
[<ffffffff8127e4fb>] pci_msi_shutdown+0x7b/0x110
[<ffffffff81269d34>] pci_device_shutdown+0x34/0x50
[<ffffffff81326c4f>] device_shutdown+0x2f/0x140
[<ffffffff8107b981>] kernel_restart_prepare+0x31/0x40
[<ffffffff8107b9e6>] kernel_restart+0x16/0x60
[<ffffffff8107bbfd>] sys_reboot+0x1ad/0x220
[<ffffffff814f4b90>] ? do_page_fault+0x1e0/0x460
[<ffffffff811942d0>] ? __sync_filesystem+0x90/0x90
[<ffffffff8105c9aa>] ? __cond_resched+0x2a/0x40
[<ffffffff814ef090>] ? _cond_resched+0x30/0x40
[<ffffffff81169e17>] ? iterate_supers+0xb7/0xd0
[<ffffffff814f9382>] system_call_fastpath+0x16/0x1b
handlers:
[<ffffffff8138a0f0>] usb_hcd_irq
[<ffffffff8138a0f0>] usb_hcd_irq
[<ffffffff8138a0f0>] usb_hcd_irq
Disabling IRQ #16
An un-wanted interrupt is generated when PCI driver switches from
MSI/MSI-X to INTx while shutting down the device. The interrupt does
not happen if MSI/MSI-X is not used on the device.
I confirmed that this problem does not happen if pcie_hp=nomsi was
specified and hotplug operation worked fine as usual.
v2: Automatically disable MSI/MSI-X against following device:
PCI bridge: Integrated Device Technology, Inc. Device 807f (rev 02)
v3: Based on the review comment, combile the if statements.
v4: Removed module parameter.
Move some code to build pciehp as a module.
Move device specific code to driver/pci/quirks.c.
v5: Drop a device specific code until getting a vendor statement.
Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: MUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/portdrv.h | 12 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_core.c | 16 |
2 files changed, 26 insertions, 2 deletions
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index bd00a01aef14..eea2ca2375e6 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h | |||
@@ -34,6 +34,18 @@ struct pci_dev; | |||
34 | 34 | ||
35 | extern void pcie_clear_root_pme_status(struct pci_dev *dev); | 35 | extern void pcie_clear_root_pme_status(struct pci_dev *dev); |
36 | 36 | ||
37 | #ifdef CONFIG_HOTPLUG_PCI_PCIE | ||
38 | extern bool pciehp_msi_disabled; | ||
39 | |||
40 | static inline bool pciehp_no_msi(void) | ||
41 | { | ||
42 | return pciehp_msi_disabled; | ||
43 | } | ||
44 | |||
45 | #else /* !CONFIG_HOTPLUG_PCI_PCIE */ | ||
46 | static inline bool pciehp_no_msi(void) { return false; } | ||
47 | #endif /* !CONFIG_HOTPLUG_PCI_PCIE */ | ||
48 | |||
37 | #ifdef CONFIG_PCIE_PME | 49 | #ifdef CONFIG_PCIE_PME |
38 | extern bool pcie_pme_msi_disabled; | 50 | extern bool pcie_pme_msi_disabled; |
39 | 51 | ||
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 595654a1a6a6..2f589a54f9bd 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c | |||
@@ -19,6 +19,17 @@ | |||
19 | #include "../pci.h" | 19 | #include "../pci.h" |
20 | #include "portdrv.h" | 20 | #include "portdrv.h" |
21 | 21 | ||
22 | bool pciehp_msi_disabled; | ||
23 | |||
24 | static int __init pciehp_setup(char *str) | ||
25 | { | ||
26 | if (!strncmp(str, "nomsi", 5)) | ||
27 | pciehp_msi_disabled = true; | ||
28 | |||
29 | return 1; | ||
30 | } | ||
31 | __setup("pcie_hp=", pciehp_setup); | ||
32 | |||
22 | /** | 33 | /** |
23 | * release_pcie_device - free PCI Express port service device structure | 34 | * release_pcie_device - free PCI Express port service device structure |
24 | * @dev: Port service device to release | 35 | * @dev: Port service device to release |
@@ -189,8 +200,9 @@ static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) | |||
189 | { | 200 | { |
190 | int i, irq = -1; | 201 | int i, irq = -1; |
191 | 202 | ||
192 | /* We have to use INTx if MSI cannot be used for PCIe PME. */ | 203 | /* We have to use INTx if MSI cannot be used for PCIe PME or pciehp. */ |
193 | if ((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) { | 204 | if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) || |
205 | ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) { | ||
194 | if (dev->pin) | 206 | if (dev->pin) |
195 | irq = dev->irq; | 207 | irq = dev->irq; |
196 | goto no_msi; | 208 | goto no_msi; |