mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 00:24:12 +08:00
Merge branch 'pm-pci'
* pm-pci: PCI / PM: Fix native PME handling during system suspend/resume PCI / PM: Restore PME Enable after config space restoration
This commit is contained in:
commit
ec4b8ddcd3
@ -511,6 +511,7 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
|
||||
}
|
||||
|
||||
pci_restore_state(pci_dev);
|
||||
pci_pme_restore(pci_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -522,6 +523,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
|
||||
{
|
||||
pci_power_up(pci_dev);
|
||||
pci_restore_state(pci_dev);
|
||||
pci_pme_restore(pci_dev);
|
||||
pci_fixup_device(pci_fixup_resume_early, pci_dev);
|
||||
}
|
||||
|
||||
|
@ -1801,7 +1801,11 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
|
||||
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
|
||||
}
|
||||
|
||||
static void pci_pme_restore(struct pci_dev *dev)
|
||||
/**
|
||||
* pci_pme_restore - Restore PME configuration after config space restore.
|
||||
* @dev: PCI device to update.
|
||||
*/
|
||||
void pci_pme_restore(struct pci_dev *dev)
|
||||
{
|
||||
u16 pmcsr;
|
||||
|
||||
@ -1811,6 +1815,7 @@ static void pci_pme_restore(struct pci_dev *dev)
|
||||
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
|
||||
if (dev->wakeup_prepared) {
|
||||
pmcsr |= PCI_PM_CTRL_PME_ENABLE;
|
||||
pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
|
||||
} else {
|
||||
pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
|
||||
pmcsr |= PCI_PM_CTRL_PME_STATUS;
|
||||
@ -1907,14 +1912,9 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Don't do the same thing twice in a row for one device, but restore
|
||||
* PME Enable in case it has been updated by config space restoration.
|
||||
*/
|
||||
if (!!enable == !!dev->wakeup_prepared) {
|
||||
pci_pme_restore(dev);
|
||||
/* Don't do the same thing twice in a row for one device. */
|
||||
if (!!enable == !!dev->wakeup_prepared)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
|
||||
|
@ -71,6 +71,7 @@ void pci_power_up(struct pci_dev *dev);
|
||||
void pci_disable_enabled_device(struct pci_dev *dev);
|
||||
int pci_finish_runtime_suspend(struct pci_dev *dev);
|
||||
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
|
||||
void pci_pme_restore(struct pci_dev *dev);
|
||||
bool pci_dev_keep_suspended(struct pci_dev *dev);
|
||||
void pci_dev_complete_resume(struct pci_dev *pci_dev);
|
||||
void pci_config_pm_runtime_get(struct pci_dev *dev);
|
||||
|
@ -40,17 +40,11 @@ static int __init pcie_pme_setup(char *str)
|
||||
}
|
||||
__setup("pcie_pme=", pcie_pme_setup);
|
||||
|
||||
enum pme_suspend_level {
|
||||
PME_SUSPEND_NONE = 0,
|
||||
PME_SUSPEND_WAKEUP,
|
||||
PME_SUSPEND_NOIRQ,
|
||||
};
|
||||
|
||||
struct pcie_pme_service_data {
|
||||
spinlock_t lock;
|
||||
struct pcie_device *srv;
|
||||
struct work_struct work;
|
||||
enum pme_suspend_level suspend_level;
|
||||
bool noirq; /* If set, keep the PME interrupt disabled. */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -228,7 +222,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
|
||||
spin_lock_irq(&data->lock);
|
||||
|
||||
for (;;) {
|
||||
if (data->suspend_level != PME_SUSPEND_NONE)
|
||||
if (data->noirq)
|
||||
break;
|
||||
|
||||
pcie_capability_read_dword(port, PCI_EXP_RTSTA, &rtsta);
|
||||
@ -255,7 +249,7 @@ static void pcie_pme_work_fn(struct work_struct *work)
|
||||
spin_lock_irq(&data->lock);
|
||||
}
|
||||
|
||||
if (data->suspend_level == PME_SUSPEND_NONE)
|
||||
if (!data->noirq)
|
||||
pcie_pme_interrupt_enable(port, true);
|
||||
|
||||
spin_unlock_irq(&data->lock);
|
||||
@ -378,7 +372,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
|
||||
{
|
||||
struct pcie_pme_service_data *data = get_service_data(srv);
|
||||
struct pci_dev *port = srv->port;
|
||||
bool wakeup, wake_irq_enabled = false;
|
||||
bool wakeup;
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(&port->dev)) {
|
||||
@ -388,19 +382,16 @@ static int pcie_pme_suspend(struct pcie_device *srv)
|
||||
wakeup = pcie_pme_check_wakeup(port->subordinate);
|
||||
up_read(&pci_bus_sem);
|
||||
}
|
||||
spin_lock_irq(&data->lock);
|
||||
if (wakeup) {
|
||||
ret = enable_irq_wake(srv->irq);
|
||||
if (ret == 0) {
|
||||
data->suspend_level = PME_SUSPEND_WAKEUP;
|
||||
wake_irq_enabled = true;
|
||||
}
|
||||
}
|
||||
if (!wake_irq_enabled) {
|
||||
pcie_pme_interrupt_enable(port, false);
|
||||
pcie_clear_root_pme_status(port);
|
||||
data->suspend_level = PME_SUSPEND_NOIRQ;
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_irq(&data->lock);
|
||||
pcie_pme_interrupt_enable(port, false);
|
||||
pcie_clear_root_pme_status(port);
|
||||
data->noirq = true;
|
||||
spin_unlock_irq(&data->lock);
|
||||
|
||||
synchronize_irq(srv->irq);
|
||||
@ -417,15 +408,15 @@ static int pcie_pme_resume(struct pcie_device *srv)
|
||||
struct pcie_pme_service_data *data = get_service_data(srv);
|
||||
|
||||
spin_lock_irq(&data->lock);
|
||||
if (data->suspend_level == PME_SUSPEND_NOIRQ) {
|
||||
if (data->noirq) {
|
||||
struct pci_dev *port = srv->port;
|
||||
|
||||
pcie_clear_root_pme_status(port);
|
||||
pcie_pme_interrupt_enable(port, true);
|
||||
data->noirq = false;
|
||||
} else {
|
||||
disable_irq_wake(srv->irq);
|
||||
}
|
||||
data->suspend_level = PME_SUSPEND_NONE;
|
||||
spin_unlock_irq(&data->lock);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user