linux/drivers/pci/pcie/portdrv.h
Rafael J. Wysocki fe31e69740 PCI/PCIe: Clear Root PME Status bits early during system resume
I noticed that PCI Express PMEs don't work on my Toshiba Portege R500
after the system has been woken up from a sleep state by a PME
(through Wake-on-LAN).  After some investigation it turned out that
the BIOS didn't clear the Root PME Status bit in the root port that
received the wakeup PME and since the Requester ID was also set in
the port's Root Status register, any subsequent PMEs didn't trigger
interrupts.

This problem can be avoided by clearing the Root PME Status bits in
all PCI Express root ports during early resume.  For this purpose,
add an early resume routine to the PCIe port driver and make this
driver be always registered, even if pci_ports_disable is set (in
which case the driver's only function is to provide the early
resume callback).

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
2010-12-23 12:54:03 -08:00

75 lines
2.0 KiB
C

/*
* 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 bool pcie_ports_disabled;
extern bool pcie_ports_auto;
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_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_ */