Skip to content
Snippets Groups Projects
  • MUNEDA Takahiro's avatar
    7570a333
    PCI: Add pcie_hp=nomsi to disable MSI/MSI-X for pciehp driver · 7570a333
    MUNEDA Takahiro authored
    
    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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
    Signed-off-by: default avatarMUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
    Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
    7570a333
    History
    PCI: Add pcie_hp=nomsi to disable MSI/MSI-X for pciehp driver
    MUNEDA Takahiro authored
    
    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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
    Signed-off-by: default avatarMUNEDA Takahiro <muneda.takahiro@jp.fujitsu.com>
    Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
portdrv.h 2.16 KiB
/*
 * File:	portdrv.h
 * Purpose:	PCI Express Port Bus Driver's Internal Data Structures
 *
 * Copyright (C) 2004 Intel
 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
 */

#ifndef _PORTDRV_H_
#define _PORTDRV_H_

#include <linux/compiler.h>

#define PCIE_PORT_DEVICE_MAXSERVICES   4
/*
 * According to the PCI Express Base Specification 2.0, the indices of
 * the MSI-X table entires used by port services must not exceed 31
 */
#define PCIE_PORT_MAX_MSIX_ENTRIES	32

#define get_descriptor_id(type, service) (((type - 4) << 4) | service)

extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM
extern int pcie_port_device_suspend(struct device *dev);
extern int pcie_port_device_resume(struct device *dev);
#endif
extern void pcie_port_device_remove(struct pci_dev *dev);
extern int __must_check pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);

struct pci_dev;

extern void pcie_clear_root_pme_status(struct pci_dev *dev);

#ifdef CONFIG_HOTPLUG_PCI_PCIE
extern bool pciehp_msi_disabled;

static inline bool pciehp_no_msi(void)
{
	return pciehp_msi_disabled;
}

#else  /* !CONFIG_HOTPLUG_PCI_PCIE */
static inline bool pciehp_no_msi(void) { return false; }
#endif /* !CONFIG_HOTPLUG_PCI_PCIE */

#ifdef CONFIG_PCIE_PME
extern bool pcie_pme_msi_disabled;

static inline void pcie_pme_disable_msi(void)
{
	pcie_pme_msi_disabled = true;
}

static inline bool pcie_pme_no_msi(void)
{
	return pcie_pme_msi_disabled;
}

extern void pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable);
#else /* !CONFIG_PCIE_PME */
static inline void pcie_pme_disable_msi(void) {}
static inline bool pcie_pme_no_msi(void) { return false; }
static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
#endif /* !CONFIG_PCIE_PME */

#ifdef CONFIG_ACPI
extern int pcie_port_acpi_setup(struct pci_dev *port, int *mask);

static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
{
	return pcie_port_acpi_setup(port, mask);
}
#else /* !CONFIG_ACPI */
static inline int pcie_port_platform_notify(struct pci_dev *port, int *mask)
{
	return 0;
}
#endif /* !CONFIG_ACPI */

#endif /* _PORTDRV_H_ */