pme.c revision 271fb719cc472af3b1e96d8c527bb0da7060a172
1c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/* 2c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * PCIe Native PME support 3c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * 4c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Copyright (C) 2007 - 2009 Intel Corp 5c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Copyright (C) 2007 - 2009 Shaohua Li <shaohua.li@intel.com> 6c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. 7c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * 8c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * This file is subject to the terms and conditions of the GNU General Public 9c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * License V2. See the file "COPYING" in the main directory of this archive 10c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * for more details. 11c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 12c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 13c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/module.h> 14c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/pci.h> 15c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/kernel.h> 16c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/errno.h> 175a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 18c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/init.h> 19c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/interrupt.h> 20c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/device.h> 21c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/pcieport_if.h> 22c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/acpi.h> 23c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/pci-acpi.h> 24c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#include <linux/pm_runtime.h> 25c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 26271fb719cc472af3b1e96d8c527bb0da7060a172Rafael J. Wysocki#include "../pci.h" 27271fb719cc472af3b1e96d8c527bb0da7060a172Rafael J. Wysocki#include "portdrv.h" 28c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 29c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#define PCI_EXP_RTSTA_PME 0x10000 /* PME status */ 30c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki#define PCI_EXP_RTSTA_PENDING 0x20000 /* PME pending */ 31c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 32c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/* 33c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki * If this switch is set, MSI will not be used for PCIe PME signaling. This 34c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki * causes the PCIe port driver to use INTx interrupts only, but it turns out 35c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki * that using MSI for PCIe PME signaling doesn't play well with PCIe PME-based 36c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki * wake-up from system sleep states. 37c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki */ 38c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysockibool pcie_pme_msi_disabled; 39c39fae1416d59fd565606793f090cebe3720d50dRafael J. Wysocki 40c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int __init pcie_pme_setup(char *str) 41c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 4228eb5f274a305bf3a13b2c80c4804d4515d05c64Rafael J. Wysocki if (!strncmp(str, "nomsi", 5)) 4328eb5f274a305bf3a13b2c80c4804d4515d05c64Rafael J. Wysocki pcie_pme_msi_disabled = true; 44b27759f880018b0cd43543dc94c921341b64b5ecRafael J. Wysocki 45c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return 1; 46c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 47c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki__setup("pcie_pme=", pcie_pme_setup); 48c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 49c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistruct pcie_pme_service_data { 50c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spinlock_t lock; 51c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_device *srv; 52c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct work_struct work; 53c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki bool noirq; /* Don't enable the PME interrupt used by this service. */ 54c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki}; 55c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 56c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 57c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_interrupt_enable - Enable/disable PCIe PME interrupt generation. 58c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @dev: PCIe root port or event collector. 59c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @enable: Enable or disable the interrupt. 60c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 6128eb5f274a305bf3a13b2c80c4804d4515d05c64Rafael J. Wysockivoid pcie_pme_interrupt_enable(struct pci_dev *dev, bool enable) 62c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 63c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki int rtctl_pos; 64c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki u16 rtctl; 65c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 66b16694f70c40ea8d539cdc93a422039771e85870Kenji Kaneshige rtctl_pos = pci_pcie_cap(dev) + PCI_EXP_RTCTL; 67c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 68c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_read_config_word(dev, rtctl_pos, &rtctl); 69c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (enable) 70c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki rtctl |= PCI_EXP_RTCTL_PMEIE; 71c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki else 72c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki rtctl &= ~PCI_EXP_RTCTL_PMEIE; 73c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_write_config_word(dev, rtctl_pos, rtctl); 74c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 75c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 76c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 77c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_clear_status - Clear root port PME interrupt status. 78c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @dev: PCIe root port or event collector. 79c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 80c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic void pcie_pme_clear_status(struct pci_dev *dev) 81c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 82c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki int rtsta_pos; 83c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki u32 rtsta; 84c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 85b16694f70c40ea8d539cdc93a422039771e85870Kenji Kaneshige rtsta_pos = pci_pcie_cap(dev) + PCI_EXP_RTSTA; 86c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 87c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_read_config_dword(dev, rtsta_pos, &rtsta); 88c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki rtsta |= PCI_EXP_RTSTA_PME; 89c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_write_config_dword(dev, rtsta_pos, rtsta); 90c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 91c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 92c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 93c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_walk_bus - Scan a PCI bus for devices asserting PME#. 94c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @bus: PCI bus to scan. 95c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * 96c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Scan given PCI bus and all buses under it for devices asserting PME#. 97c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 98c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic bool pcie_pme_walk_bus(struct pci_bus *bus) 99c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 100c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *dev; 101c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki bool ret = false; 102c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 103c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki list_for_each_entry(dev, &bus->devices, bus_list) { 104c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* Skip PCIe devices in case we started from a root port. */ 105552be54cc4232dc5acc49ccb372129d6f1b6923fKenji Kaneshige if (!pci_is_pcie(dev) && pci_check_pme_status(dev)) { 106c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pm_request_resume(&dev->dev); 107c125e96f044427f38d106fab7bc5e4a5e6a18262Rafael J. Wysocki pci_wakeup_event(dev); 108c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki ret = true; 109c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 110c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 111c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (dev->subordinate && pcie_pme_walk_bus(dev->subordinate)) 112c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki ret = true; 113c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 114c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 115c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return ret; 116c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 117c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 118c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 119c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_from_pci_bridge - Check if PCIe-PCI bridge generated a PME. 120c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @bus: Secondary bus of the bridge. 121c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @devfn: Device/function number to check. 122c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * 123c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * PME from PCI devices under a PCIe-PCI bridge may be converted to an in-band 124c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * PCIe PME message. In such that case the bridge should use the Requester ID 125c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * of device/function number 0 on its secondary bus. 126c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 127c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic bool pcie_pme_from_pci_bridge(struct pci_bus *bus, u8 devfn) 128c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 129c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *dev; 130c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki bool found = false; 131c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 132c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (devfn) 133c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return false; 134c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 135c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki dev = pci_dev_get(bus->self); 136c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!dev) 137c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return false; 138c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 139552be54cc4232dc5acc49ccb372129d6f1b6923fKenji Kaneshige if (pci_is_pcie(dev) && dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { 140c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki down_read(&pci_bus_sem); 141c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (pcie_pme_walk_bus(bus)) 142c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = true; 143c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki up_read(&pci_bus_sem); 144c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 145c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 146c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_dev_put(dev); 147c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return found; 148c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 149c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 150c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 151c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_handle_request - Find device that generated PME and handle it. 152c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @port: Root port or event collector that generated the PME interrupt. 153c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @req_id: PCIe Requester ID of the device that generated the PME. 154c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 155c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic void pcie_pme_handle_request(struct pci_dev *port, u16 req_id) 156c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 157c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki u8 busnr = req_id >> 8, devfn = req_id & 0xff; 158c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_bus *bus; 159c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *dev; 160c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki bool found = false; 161c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 162c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* First, check if the PME is from the root port itself. */ 163c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (port->devfn == devfn && port->bus->number == busnr) { 164c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (pci_check_pme_status(port)) { 165c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pm_request_resume(&port->dev); 166c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = true; 167c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } else { 168c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* 169c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Apparently, the root port generated the PME on behalf 170c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * of a non-PCIe device downstream. If this is done by 171c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * a root port, the Requester ID field in its status 172c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * register may contain either the root port's, or the 173c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * source device's information (PCI Express Base 174c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Specification, Rev. 2.0, Section 6.1.9). 175c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 176c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki down_read(&pci_bus_sem); 177c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = pcie_pme_walk_bus(port->subordinate); 178c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki up_read(&pci_bus_sem); 179c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 180c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki goto out; 181c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 182c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 183c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* Second, find the bus the source device is on. */ 184c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki bus = pci_find_bus(pci_domain_nr(port->bus), busnr); 185c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!bus) 186c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki goto out; 187c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 188c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* Next, check if the PME is from a PCIe-PCI bridge. */ 189c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = pcie_pme_from_pci_bridge(bus, devfn); 190c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (found) 191c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki goto out; 192c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 193c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* Finally, try to find the PME source on the bus. */ 194c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki down_read(&pci_bus_sem); 195c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki list_for_each_entry(dev, &bus->devices, bus_list) { 196c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_dev_get(dev); 197c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (dev->devfn == devfn) { 198c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = true; 199c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki break; 200c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 201c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_dev_put(dev); 202c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 203c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki up_read(&pci_bus_sem); 204c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 205c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (found) { 206c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* The device is there, but we have to check its PME status. */ 207c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = pci_check_pme_status(dev); 208c125e96f044427f38d106fab7bc5e4a5e6a18262Rafael J. Wysocki if (found) { 209c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pm_request_resume(&dev->dev); 210c125e96f044427f38d106fab7bc5e4a5e6a18262Rafael J. Wysocki pci_wakeup_event(dev); 211c125e96f044427f38d106fab7bc5e4a5e6a18262Rafael J. Wysocki } 212c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_dev_put(dev); 213c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } else if (devfn) { 214c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* 215c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * The device is not there, but we can still try to recover by 216c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * assuming that the PME was reported by a PCIe-PCI bridge that 217c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * used devfn different from zero. 218c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 219c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki dev_dbg(&port->dev, "PME interrupt generated for " 220c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki "non-existent device %02x:%02x.%d\n", 221c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); 222c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki found = pcie_pme_from_pci_bridge(bus, 0); 223c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 224c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 225c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki out: 226c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!found) 227c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki dev_dbg(&port->dev, "Spurious native PME interrupt!\n"); 228c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 229c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 230c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 231c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_work_fn - Work handler for PCIe PME interrupt. 232c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @work: Work structure giving access to service data. 233c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 234c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic void pcie_pme_work_fn(struct work_struct *work) 235c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 236c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_pme_service_data *data = 237c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki container_of(work, struct pcie_pme_service_data, work); 238c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *port = data->srv->port; 239c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki int rtsta_pos; 240c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki u32 rtsta; 241c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 242b16694f70c40ea8d539cdc93a422039771e85870Kenji Kaneshige rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; 243c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 244c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irq(&data->lock); 245c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 246c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki for (;;) { 247c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (data->noirq) 248c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki break; 249c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 250c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_read_config_dword(port, rtsta_pos, &rtsta); 251c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (rtsta & PCI_EXP_RTSTA_PME) { 252c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* 253c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * Clear PME status of the port. If there are other 254c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pending PMEs, the status will be set again. 255c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 256c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_clear_status(port); 257c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 258c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irq(&data->lock); 259c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_handle_request(port, rtsta & 0xffff); 260c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irq(&data->lock); 261c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 262c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki continue; 263c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 264c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 265c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* No need to loop if there are no more PMEs pending. */ 266c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!(rtsta & PCI_EXP_RTSTA_PENDING)) 267c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki break; 268c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 269c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irq(&data->lock); 270c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki cpu_relax(); 271c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irq(&data->lock); 272c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 273c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 274c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!data->noirq) 275c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, true); 276c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 277c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irq(&data->lock); 278c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 279c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 280c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 281c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_irq - Interrupt handler for PCIe root port PME interrupt. 282c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @irq: Interrupt vector. 283c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @context: Interrupt context pointer. 284c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 285c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic irqreturn_t pcie_pme_irq(int irq, void *context) 286c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 287c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *port; 288c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_pme_service_data *data; 289c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki int rtsta_pos; 290c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki u32 rtsta; 291c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki unsigned long flags; 292c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 293c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki port = ((struct pcie_device *)context)->port; 294c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki data = get_service_data((struct pcie_device *)context); 295c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 296b16694f70c40ea8d539cdc93a422039771e85870Kenji Kaneshige rtsta_pos = pci_pcie_cap(port) + PCI_EXP_RTSTA; 297c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 298c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irqsave(&data->lock, flags); 299c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_read_config_dword(port, rtsta_pos, &rtsta); 300c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 301c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!(rtsta & PCI_EXP_RTSTA_PME)) { 302c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irqrestore(&data->lock, flags); 303c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return IRQ_NONE; 304c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 305c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 306c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, false); 307c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irqrestore(&data->lock, flags); 308c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 309c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* We don't use pm_wq, because it's freezable. */ 310c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki schedule_work(&data->work); 311c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 312c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return IRQ_HANDLED; 313c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 314c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 315c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 316c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_set_native - Set the PME interrupt flag for given device. 317c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @dev: PCI device to handle. 318c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @ign: Ignored. 319c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 320c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int pcie_pme_set_native(struct pci_dev *dev, void *ign) 321c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 322c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n"); 323c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 324c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki device_set_run_wake(&dev->dev, true); 325c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki dev->pme_interrupt = true; 326c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return 0; 327c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 328c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 329c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 330c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_mark_devices - Set the PME interrupt flag for devices below a port. 331c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @port: PCIe root port or event collector to handle. 332c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * 333c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * For each device below given root port, including the port itself (or for each 334c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * root complex integrated endpoint if @port is a root complex event collector) 335c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * set the flag indicating that it can signal run-time wake-up events via PCIe 336c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * PME interrupts. 337c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 338c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic void pcie_pme_mark_devices(struct pci_dev *port) 339c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 340c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_set_native(port, NULL); 341c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (port->subordinate) { 342c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL); 343c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } else { 344c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_bus *bus = port->bus; 345c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *dev; 346c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 347c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki /* Check if this is a root port event collector. */ 348c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (port->pcie_type != PCI_EXP_TYPE_RC_EC || !bus) 349c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return; 350c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 351c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki down_read(&pci_bus_sem); 352c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki list_for_each_entry(dev, &bus->devices, bus_list) 353552be54cc4232dc5acc49ccb372129d6f1b6923fKenji Kaneshige if (pci_is_pcie(dev) 354c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki && dev->pcie_type == PCI_EXP_TYPE_RC_END) 355c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_set_native(dev, NULL); 356c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki up_read(&pci_bus_sem); 357c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 358c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 359c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 360c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 361c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_probe - Initialize PCIe PME service for given root port. 362c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @srv: PCIe service to initialize. 363c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 364c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int pcie_pme_probe(struct pcie_device *srv) 365c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 366c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *port; 367c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_pme_service_data *data; 368c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki int ret; 369c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 370c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki data = kzalloc(sizeof(*data), GFP_KERNEL); 371c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (!data) 372c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return -ENOMEM; 373c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 374c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_init(&data->lock); 375c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki INIT_WORK(&data->work, pcie_pme_work_fn); 376c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki data->srv = srv; 377c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki set_service_data(srv, data); 378c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 379c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki port = srv->port; 380c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, false); 381c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_clear_status(port); 382c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 383c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); 384c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki if (ret) { 385c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki kfree(data); 386c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } else { 387c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_mark_devices(port); 388c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, true); 389c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki } 390c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 391c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return ret; 392c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 393c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 394c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 395c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_suspend - Suspend PCIe PME service device. 396c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @srv: PCIe service device to suspend. 397c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 398c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int pcie_pme_suspend(struct pcie_device *srv) 399c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 400c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_pme_service_data *data = get_service_data(srv); 401c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *port = srv->port; 402c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 403c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irq(&data->lock); 404c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, false); 405c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_clear_status(port); 406c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki data->noirq = true; 407c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irq(&data->lock); 408c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 409c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki synchronize_irq(srv->irq); 410c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 411c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return 0; 412c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 413c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 414c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 415c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_resume - Resume PCIe PME service device. 416c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @srv - PCIe service device to resume. 417c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 418c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int pcie_pme_resume(struct pcie_device *srv) 419c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 420c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pcie_pme_service_data *data = get_service_data(srv); 421c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki struct pci_dev *port = srv->port; 422c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 423c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_lock_irq(&data->lock); 424c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki data->noirq = false; 425c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_clear_status(port); 426c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_interrupt_enable(port, true); 427c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki spin_unlock_irq(&data->lock); 428c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 429c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki return 0; 430c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 431c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 432c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 433c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_remove - Prepare PCIe PME service device for removal. 434c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * @srv - PCIe service device to resume. 435c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 436c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic void pcie_pme_remove(struct pcie_device *srv) 437c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 438c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki pcie_pme_suspend(srv); 439c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki free_irq(srv->irq, srv); 440c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki kfree(get_service_data(srv)); 441c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 442c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 443c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic struct pcie_port_service_driver pcie_pme_driver = { 444c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .name = "pcie_pme", 445c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .port_type = PCI_EXP_TYPE_ROOT_PORT, 446c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .service = PCIE_PORT_SERVICE_PME, 447c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 448c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .probe = pcie_pme_probe, 449c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .suspend = pcie_pme_suspend, 450c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .resume = pcie_pme_resume, 451c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki .remove = pcie_pme_remove, 452c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki}; 453c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 454c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki/** 455c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki * pcie_pme_service_init - Register the PCIe PME service driver. 456c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki */ 457c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockistatic int __init pcie_pme_service_init(void) 458c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki{ 45928eb5f274a305bf3a13b2c80c4804d4515d05c64Rafael J. Wysocki return pcie_port_service_register(&pcie_pme_driver); 460c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki} 461c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysocki 462c7f486567c1d0acd2e4166c47069835b9f75e77bRafael J. Wysockimodule_init(pcie_pme_service_init); 463