Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/pci/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 181 kB image not shown  

Quelle  pci.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * PCI Bus Services, see include/linux/pci.h for further explanation.
 *
 * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
 * David Mosberger-Tang
 *
 * Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
 */


#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/msi.h>
#include <linux/of.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/log2.h>
#include <linux/logic_pio.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h>
#include <linux/vmalloc.h>
#include <asm/dma.h>
#include <linux/aer.h>
#include <linux/bitfield.h>
#include "pci.h"

DEFINE_MUTEX(pci_slot_mutex);

const char *pci_power_names[] = {
 "error""D0""D1""D2""D3hot""D3cold""unknown",
};
EXPORT_SYMBOL_GPL(pci_power_names);

#ifdef CONFIG_X86_32
int isa_dma_bridge_buggy;
EXPORT_SYMBOL(isa_dma_bridge_buggy);
#endif

int pci_pci_problems;
EXPORT_SYMBOL(pci_pci_problems);

unsigned int pci_pm_d3hot_delay;

static void pci_pme_list_scan(struct work_struct *work);

static LIST_HEAD(pci_pme_list);
static DEFINE_MUTEX(pci_pme_list_mutex);
static DECLARE_DELAYED_WORK(pci_pme_work, pci_pme_list_scan);

struct pci_pme_device {
 struct list_head list;
 struct pci_dev *dev;
};

#define PME_TIMEOUT 1000 /* How long between PME checks */

/*
 * Following exit from Conventional Reset, devices must be ready within 1 sec
 * (PCIe r6.0 sec 6.6.1).  A D3cold to D0 transition implies a Conventional
 * Reset (PCIe r6.0 sec 5.8).
 */

#define PCI_RESET_WAIT 1000 /* msec */

/*
 * Devices may extend the 1 sec period through Request Retry Status
 * completions (PCIe r6.0 sec 2.3.1).  The spec does not provide an upper
 * limit, but 60 sec ought to be enough for any device to become
 * responsive.
 */

#define PCIE_RESET_READY_POLL_MS 60000 /* msec */

static void pci_dev_d3_sleep(struct pci_dev *dev)
{
 unsigned int delay_ms = max(dev->d3hot_delay, pci_pm_d3hot_delay);
 unsigned int upper;

 if (delay_ms) {
  /* Use a 20% upper bound, 1ms minimum */
  upper = max(DIV_ROUND_CLOSEST(delay_ms, 5), 1U);
  usleep_range(delay_ms * USEC_PER_MSEC,
        (delay_ms + upper) * USEC_PER_MSEC);
 }
}

bool pci_reset_supported(struct pci_dev *dev)
{
 return dev->reset_methods[0] != 0;
}

#ifdef CONFIG_PCI_DOMAINS
int pci_domains_supported = 1;
#endif

#define DEFAULT_CARDBUS_IO_SIZE  (256)
#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
unsigned long pci_cardbus_io_size = DEFAULT_CARDBUS_IO_SIZE;
unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;

#define DEFAULT_HOTPLUG_IO_SIZE  (256)
#define DEFAULT_HOTPLUG_MMIO_SIZE (2*1024*1024)
#define DEFAULT_HOTPLUG_MMIO_PREF_SIZE (2*1024*1024)
/* hpiosize=nn can override this */
unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;
/*
 * pci=hpmmiosize=nnM overrides non-prefetchable MMIO size,
 * pci=hpmmioprefsize=nnM overrides prefetchable MMIO size;
 * pci=hpmemsize=nnM overrides both
 */

unsigned long pci_hotplug_mmio_size = DEFAULT_HOTPLUG_MMIO_SIZE;
unsigned long pci_hotplug_mmio_pref_size = DEFAULT_HOTPLUG_MMIO_PREF_SIZE;

#define DEFAULT_HOTPLUG_BUS_SIZE 1
unsigned long pci_hotplug_bus_size = DEFAULT_HOTPLUG_BUS_SIZE;


/* PCIe MPS/MRRS strategy; can be overridden by kernel command-line param */
#ifdef CONFIG_PCIE_BUS_TUNE_OFF
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF;
#elif defined CONFIG_PCIE_BUS_SAFE
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
#elif defined CONFIG_PCIE_BUS_PERFORMANCE
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
#elif defined CONFIG_PCIE_BUS_PEER2PEER
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PEER2PEER;
#else
enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT;
#endif

/*
 * The default CLS is used if arch didn't set CLS explicitly and not
 * all pci devices agree on the same value.  Arch can override either
 * the dfl or actual value as it sees fit.  Don't forget this is
 * measured in 32-bit words, not bytes.
 */

u8 pci_dfl_cache_line_size __ro_after_init = L1_CACHE_BYTES >> 2;
u8 pci_cache_line_size __ro_after_init ;

/*
 * If we set up a device for bus mastering, we need to check the latency
 * timer as certain BIOSes forget to set it properly.
 */

unsigned int pcibios_max_latency = 255;

/* If set, the PCIe ARI capability will not be used. */
static bool pcie_ari_disabled;

/* If set, the PCIe ATS capability will not be used. */
static bool pcie_ats_disabled;

/* If set, the PCI config space of each device is printed during boot. */
bool pci_early_dump;

bool pci_ats_disabled(void)
{
 return pcie_ats_disabled;
}
EXPORT_SYMBOL_GPL(pci_ats_disabled);

/* Disable bridge_d3 for all PCIe ports */
static bool pci_bridge_d3_disable;
/* Force bridge_d3 for all PCIe ports */
static bool pci_bridge_d3_force;

static int __init pcie_port_pm_setup(char *str)
{
 if (!strcmp(str, "off"))
  pci_bridge_d3_disable = true;
 else if (!strcmp(str, "force"))
  pci_bridge_d3_force = true;
 return 1;
}
__setup("pcie_port_pm=", pcie_port_pm_setup);

/**
 * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
 * @bus: pointer to PCI bus structure to search
 *
 * Given a PCI bus, returns the highest PCI bus number present in the set
 * including the given PCI bus and its list of child PCI buses.
 */

unsigned char pci_bus_max_busnr(struct pci_bus *bus)
{
 struct pci_bus *tmp;
 unsigned char max, n;

 max = bus->busn_res.end;
 list_for_each_entry(tmp, &bus->children, node) {
  n = pci_bus_max_busnr(tmp);
  if (n > max)
   max = n;
 }
 return max;
}
EXPORT_SYMBOL_GPL(pci_bus_max_busnr);

/**
 * pci_status_get_and_clear_errors - return and clear error bits in PCI_STATUS
 * @pdev: the PCI device
 *
 * Returns error bits set in PCI_STATUS and clears them.
 */

int pci_status_get_and_clear_errors(struct pci_dev *pdev)
{
 u16 status;
 int ret;

 ret = pci_read_config_word(pdev, PCI_STATUS, &status);
 if (ret != PCIBIOS_SUCCESSFUL)
  return -EIO;

 status &= PCI_STATUS_ERROR_BITS;
 if (status)
  pci_write_config_word(pdev, PCI_STATUS, status);

 return status;
}
EXPORT_SYMBOL_GPL(pci_status_get_and_clear_errors);

#ifdef CONFIG_HAS_IOMEM
static void __iomem *__pci_ioremap_resource(struct pci_dev *pdev, int bar,
         bool write_combine)
{
 struct resource *res = &pdev->resource[bar];
 resource_size_t start = res->start;
 resource_size_t size = resource_size(res);

 /*
 * Make sure the BAR is actually a memory resource, not an IO resource
 */

 if (res->flags & IORESOURCE_UNSET || !(res->flags & IORESOURCE_MEM)) {
  pci_err(pdev, "can't ioremap BAR %d: %pR\n", bar, res);
  return NULL;
 }

 if (write_combine)
  return ioremap_wc(start, size);

 return ioremap(start, size);
}

void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
{
 return __pci_ioremap_resource(pdev, bar, false);
}
EXPORT_SYMBOL_GPL(pci_ioremap_bar);

void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
{
 return __pci_ioremap_resource(pdev, bar, true);
}
EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
#endif

/**
 * pci_dev_str_match_path - test if a path string matches a device
 * @dev: the PCI device to test
 * @path: string to match the device against
 * @endptr: pointer to the string after the match
 *
 * Test if a string (typically from a kernel parameter) formatted as a
 * path of device/function addresses matches a PCI device. The string must
 * be of the form:
 *
 *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
 *
 * A path for a device can be obtained using 'lspci -t'.  Using a path
 * is more robust against bus renumbering than using only a single bus,
 * device and function address.
 *
 * Returns 1 if the string matches the device, 0 if it does not and
 * a negative error code if it fails to parse the string.
 */

static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
      const char **endptr)
{
 int ret;
 unsigned int seg, bus, slot, func;
 char *wpath, *p;
 char end;

 *endptr = strchrnul(path, ';');

 wpath = kmemdup_nul(path, *endptr - path, GFP_ATOMIC);
 if (!wpath)
  return -ENOMEM;

 while (1) {
  p = strrchr(wpath, '/');
  if (!p)
   break;
  ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
  if (ret != 2) {
   ret = -EINVAL;
   goto free_and_exit;
  }

  if (dev->devfn != PCI_DEVFN(slot, func)) {
   ret = 0;
   goto free_and_exit;
  }

  /*
 * Note: we don't need to get a reference to the upstream
 * bridge because we hold a reference to the top level
 * device which should hold a reference to the bridge,
 * and so on.
 */

  dev = pci_upstream_bridge(dev);
  if (!dev) {
   ret = 0;
   goto free_and_exit;
  }

  *p = 0;
 }

 ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
       &func, &end);
 if (ret != 4) {
  seg = 0;
  ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
  if (ret != 3) {
   ret = -EINVAL;
   goto free_and_exit;
  }
 }

 ret = (seg == pci_domain_nr(dev->bus) &&
        bus == dev->bus->number &&
        dev->devfn == PCI_DEVFN(slot, func));

free_and_exit:
 kfree(wpath);
 return ret;
}

/**
 * pci_dev_str_match - test if a string matches a device
 * @dev: the PCI device to test
 * @p: string to match the device against
 * @endptr: pointer to the string after the match
 *
 * Test if a string (typically from a kernel parameter) matches a specified
 * PCI device. The string may be of one of the following formats:
 *
 *   [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
 *   pci:<vendor>:<device>[:<subvendor>:<subdevice>]
 *
 * The first format specifies a PCI bus/device/function address which
 * may change if new hardware is inserted, if motherboard firmware changes,
 * or due to changes caused in kernel parameters. If the domain is
 * left unspecified, it is taken to be 0.  In order to be robust against
 * bus renumbering issues, a path of PCI device/function numbers may be used
 * to address the specific device.  The path for a device can be determined
 * through the use of 'lspci -t'.
 *
 * The second format matches devices using IDs in the configuration
 * space which may match multiple devices in the system. A value of 0
 * for any field will match all devices. (Note: this differs from
 * in-kernel code that uses PCI_ANY_ID which is ~0; this is for
 * legacy reasons and convenience so users don't have to specify
 * FFFFFFFFs on the command line.)
 *
 * Returns 1 if the string matches the device, 0 if it does not and
 * a negative error code if the string cannot be parsed.
 */

static int pci_dev_str_match(struct pci_dev *dev, const char *p,
        const char **endptr)
{
 int ret;
 int count;
 unsigned short vendor, device, subsystem_vendor, subsystem_device;

 if (strncmp(p, "pci:", 4) == 0) {
  /* PCI vendor/device (subvendor/subdevice) IDs are specified */
  p += 4;
  ret = sscanf(p, "%hx:%hx:%hx:%hx%n", &vendor, &device,
        &subsystem_vendor, &subsystem_device, &count);
  if (ret != 4) {
   ret = sscanf(p, "%hx:%hx%n", &vendor, &device, &count);
   if (ret != 2)
    return -EINVAL;

   subsystem_vendor = 0;
   subsystem_device = 0;
  }

  p += count;

  if ((!vendor || vendor == dev->vendor) &&
      (!device || device == dev->device) &&
      (!subsystem_vendor ||
       subsystem_vendor == dev->subsystem_vendor) &&
      (!subsystem_device ||
       subsystem_device == dev->subsystem_device))
   goto found;
 } else {
  /*
 * PCI Bus, Device, Function IDs are specified
 * (optionally, may include a path of devfns following it)
 */

  ret = pci_dev_str_match_path(dev, p, &p);
  if (ret < 0)
   return ret;
  else if (ret)
   goto found;
 }

 *endptr = p;
 return 0;

found:
 *endptr = p;
 return 1;
}

static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
      u8 pos, int cap, int *ttl)
{
 u8 id;
 u16 ent;

 pci_bus_read_config_byte(bus, devfn, pos, &pos);

 while ((*ttl)--) {
  if (pos < 0x40)
   break;
  pos &= ~3;
  pci_bus_read_config_word(bus, devfn, pos, &ent);

  id = ent & 0xff;
  if (id == 0xff)
   break;
  if (id == cap)
   return pos;
  pos = (ent >> 8);
 }
 return 0;
}

static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
         u8 pos, int cap)
{
 int ttl = PCI_FIND_CAP_TTL;

 return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
}

u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
{
 return __pci_find_next_cap(dev->bus, dev->devfn,
       pos + PCI_CAP_LIST_NEXT, cap);
}
EXPORT_SYMBOL_GPL(pci_find_next_capability);

static u8 __pci_bus_find_cap_start(struct pci_bus *bus,
        unsigned int devfn, u8 hdr_type)
{
 u16 status;

 pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
 if (!(status & PCI_STATUS_CAP_LIST))
  return 0;

 switch (hdr_type) {
 case PCI_HEADER_TYPE_NORMAL:
 case PCI_HEADER_TYPE_BRIDGE:
  return PCI_CAPABILITY_LIST;
 case PCI_HEADER_TYPE_CARDBUS:
  return PCI_CB_CAPABILITY_LIST;
 }

 return 0;
}

/**
 * pci_find_capability - query for devices' capabilities
 * @dev: PCI device to query
 * @cap: capability code
 *
 * Tell if a device supports a given PCI capability.
 * Returns the address of the requested capability structure within the
 * device's PCI configuration space or 0 in case the device does not
 * support it.  Possible values for @cap include:
 *
 *  %PCI_CAP_ID_PM           Power Management
 *  %PCI_CAP_ID_AGP          Accelerated Graphics Port
 *  %PCI_CAP_ID_VPD          Vital Product Data
 *  %PCI_CAP_ID_SLOTID       Slot Identification
 *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
 *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap
 *  %PCI_CAP_ID_PCIX         PCI-X
 *  %PCI_CAP_ID_EXP          PCI Express
 */

u8 pci_find_capability(struct pci_dev *dev, int cap)
{
 u8 pos;

 pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
 if (pos)
  pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);

 return pos;
}
EXPORT_SYMBOL(pci_find_capability);

/**
 * pci_bus_find_capability - query for devices' capabilities
 * @bus: the PCI bus to query
 * @devfn: PCI device to query
 * @cap: capability code
 *
 * Like pci_find_capability() but works for PCI devices that do not have a
 * pci_dev structure set up yet.
 *
 * Returns the address of the requested capability structure within the
 * device's PCI configuration space or 0 in case the device does not
 * support it.
 */

u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
 u8 hdr_type, pos;

 pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);

 pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & PCI_HEADER_TYPE_MASK);
 if (pos)
  pos = __pci_find_next_cap(bus, devfn, pos, cap);

 return pos;
}
EXPORT_SYMBOL(pci_bus_find_capability);

/**
 * pci_find_next_ext_capability - Find an extended capability
 * @dev: PCI device to query
 * @start: address at which to start looking (0 to start at beginning of list)
 * @cap: capability code
 *
 * Returns the address of the next matching extended capability structure
 * within the device's PCI configuration space or 0 if the device does
 * not support it.  Some capabilities can occur several times, e.g., the
 * vendor-specific capability, and this provides a way to find them all.
 */

u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
{
 u32 header;
 int ttl;
 u16 pos = PCI_CFG_SPACE_SIZE;

 /* minimum 8 bytes per capability */
 ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;

 if (dev->cfg_size <= PCI_CFG_SPACE_SIZE)
  return 0;

 if (start)
  pos = start;

 if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
  return 0;

 /*
 * If we have no capabilities, this is indicated by cap ID,
 * cap version and next pointer all being 0.
 */

 if (header == 0)
  return 0;

 while (ttl-- > 0) {
  if (PCI_EXT_CAP_ID(header) == cap && pos != start)
   return pos;

  pos = PCI_EXT_CAP_NEXT(header);
  if (pos < PCI_CFG_SPACE_SIZE)
   break;

  if (pci_read_config_dword(dev, pos, &header) != PCIBIOS_SUCCESSFUL)
   break;
 }

 return 0;
}
EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);

/**
 * pci_find_ext_capability - Find an extended capability
 * @dev: PCI device to query
 * @cap: capability code
 *
 * Returns the address of the requested extended capability structure
 * within the device's PCI configuration space or 0 if the device does
 * not support it.  Possible values for @cap include:
 *
 *  %PCI_EXT_CAP_ID_ERR Advanced Error Reporting
 *  %PCI_EXT_CAP_ID_VC Virtual Channel
 *  %PCI_EXT_CAP_ID_DSN Device Serial Number
 *  %PCI_EXT_CAP_ID_PWR Power Budgeting
 */

u16 pci_find_ext_capability(struct pci_dev *dev, int cap)
{
 return pci_find_next_ext_capability(dev, 0, cap);
}
EXPORT_SYMBOL_GPL(pci_find_ext_capability);

/**
 * pci_get_dsn - Read and return the 8-byte Device Serial Number
 * @dev: PCI device to query
 *
 * Looks up the PCI_EXT_CAP_ID_DSN and reads the 8 bytes of the Device Serial
 * Number.
 *
 * Returns the DSN, or zero if the capability does not exist.
 */

u64 pci_get_dsn(struct pci_dev *dev)
{
 u32 dword;
 u64 dsn;
 int pos;

 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DSN);
 if (!pos)
  return 0;

 /*
 * The Device Serial Number is two dwords offset 4 bytes from the
 * capability position. The specification says that the first dword is
 * the lower half, and the second dword is the upper half.
 */

 pos += 4;
 pci_read_config_dword(dev, pos, &dword);
 dsn = (u64)dword;
 pci_read_config_dword(dev, pos + 4, &dword);
 dsn |= ((u64)dword) << 32;

 return dsn;
}
EXPORT_SYMBOL_GPL(pci_get_dsn);

static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
{
 int rc, ttl = PCI_FIND_CAP_TTL;
 u8 cap, mask;

 if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
  mask = HT_3BIT_CAP_MASK;
 else
  mask = HT_5BIT_CAP_MASK;

 pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
          PCI_CAP_ID_HT, &ttl);
 while (pos) {
  rc = pci_read_config_byte(dev, pos + 3, &cap);
  if (rc != PCIBIOS_SUCCESSFUL)
   return 0;

  if ((cap & mask) == ht_cap)
   return pos;

  pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
           pos + PCI_CAP_LIST_NEXT,
           PCI_CAP_ID_HT, &ttl);
 }

 return 0;
}

/**
 * pci_find_next_ht_capability - query a device's HyperTransport capabilities
 * @dev: PCI device to query
 * @pos: Position from which to continue searching
 * @ht_cap: HyperTransport capability code
 *
 * To be used in conjunction with pci_find_ht_capability() to search for
 * all capabilities matching @ht_cap. @pos should always be a value returned
 * from pci_find_ht_capability().
 *
 * NB. To be 100% safe against broken PCI devices, the caller should take
 * steps to avoid an infinite loop.
 */

u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap)
{
 return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
}
EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);

/**
 * pci_find_ht_capability - query a device's HyperTransport capabilities
 * @dev: PCI device to query
 * @ht_cap: HyperTransport capability code
 *
 * Tell if a device supports a given HyperTransport capability.
 * Returns an address within the device's PCI configuration space
 * or 0 in case the device does not support the request capability.
 * The address points to the PCI capability, of type PCI_CAP_ID_HT,
 * which has a HyperTransport capability matching @ht_cap.
 */

u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
{
 u8 pos;

 pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
 if (pos)
  pos = __pci_find_next_ht_cap(dev, pos, ht_cap);

 return pos;
}
EXPORT_SYMBOL_GPL(pci_find_ht_capability);

/**
 * pci_find_vsec_capability - Find a vendor-specific extended capability
 * @dev: PCI device to query
 * @vendor: Vendor ID for which capability is defined
 * @cap: Vendor-specific capability ID
 *
 * If @dev has Vendor ID @vendor, search for a VSEC capability with
 * VSEC ID @cap. If found, return the capability offset in
 * config space; otherwise return 0.
 */

u16 pci_find_vsec_capability(struct pci_dev *dev, u16 vendor, int cap)
{
 u16 vsec = 0;
 u32 header;
 int ret;

 if (vendor != dev->vendor)
  return 0;

 while ((vsec = pci_find_next_ext_capability(dev, vsec,
           PCI_EXT_CAP_ID_VNDR))) {
  ret = pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER, &header);
  if (ret != PCIBIOS_SUCCESSFUL)
   continue;

  if (PCI_VNDR_HEADER_ID(header) == cap)
   return vsec;
 }

 return 0;
}
EXPORT_SYMBOL_GPL(pci_find_vsec_capability);

/**
 * pci_find_dvsec_capability - Find DVSEC for vendor
 * @dev: PCI device to query
 * @vendor: Vendor ID to match for the DVSEC
 * @dvsec: Designated Vendor-specific capability ID
 *
 * If DVSEC has Vendor ID @vendor and DVSEC ID @dvsec return the capability
 * offset in config space; otherwise return 0.
 */

u16 pci_find_dvsec_capability(struct pci_dev *dev, u16 vendor, u16 dvsec)
{
 int pos;

 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DVSEC);
 if (!pos)
  return 0;

 while (pos) {
  u16 v, id;

  pci_read_config_word(dev, pos + PCI_DVSEC_HEADER1, &v);
  pci_read_config_word(dev, pos + PCI_DVSEC_HEADER2, &id);
  if (vendor == v && dvsec == id)
   return pos;

  pos = pci_find_next_ext_capability(dev, pos, PCI_EXT_CAP_ID_DVSEC);
 }

 return 0;
}
EXPORT_SYMBOL_GPL(pci_find_dvsec_capability);

/**
 * pci_find_parent_resource - return resource region of parent bus of given
 *       region
 * @dev: PCI device structure contains resources to be searched
 * @res: child resource record for which parent is sought
 *
 * For given resource region of given device, return the resource region of
 * parent bus the given region is contained in.
 */

struct resource *pci_find_parent_resource(const struct pci_dev *dev,
       struct resource *res)
{
 const struct pci_bus *bus = dev->bus;
 struct resource *r;

 pci_bus_for_each_resource(bus, r) {
  if (!r)
   continue;
  if (resource_contains(r, res)) {

   /*
 * If the window is prefetchable but the BAR is
 * not, the allocator made a mistake.
 */

   if (r->flags & IORESOURCE_PREFETCH &&
       !(res->flags & IORESOURCE_PREFETCH))
    return NULL;

   /*
 * If we're below a transparent bridge, there may
 * be both a positively-decoded aperture and a
 * subtractively-decoded region that contain the BAR.
 * We want the positively-decoded one, so this depends
 * on pci_bus_for_each_resource() giving us those
 * first.
 */

   return r;
  }
 }
 return NULL;
}
EXPORT_SYMBOL(pci_find_parent_resource);

/**
 * pci_find_resource - Return matching PCI device resource
 * @dev: PCI device to query
 * @res: Resource to look for
 *
 * Goes over standard PCI resources (BARs) and checks if the given resource
 * is partially or fully contained in any of them. In that case the
 * matching resource is returned, %NULL otherwise.
 */

struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res)
{
 int i;

 for (i = 0; i < PCI_STD_NUM_BARS; i++) {
  struct resource *r = &dev->resource[i];

  if (r->start && resource_contains(r, res))
   return r;
 }

 return NULL;
}
EXPORT_SYMBOL(pci_find_resource);

/**
 * pci_resource_name - Return the name of the PCI resource
 * @dev: PCI device to query
 * @i: index of the resource
 *
 * Return the standard PCI resource (BAR) name according to their index.
 */

const char *pci_resource_name(struct pci_dev *dev, unsigned int i)
{
 static const char * const bar_name[] = {
  "BAR 0",
  "BAR 1",
  "BAR 2",
  "BAR 3",
  "BAR 4",
  "BAR 5",
  "ROM",
#ifdef CONFIG_PCI_IOV
  "VF BAR 0",
  "VF BAR 1",
  "VF BAR 2",
  "VF BAR 3",
  "VF BAR 4",
  "VF BAR 5",
#endif
  "bridge window"/* "io" included in %pR */
  "bridge window"/* "mem" included in %pR */
  "bridge window"/* "mem pref" included in %pR */
 };
 static const char * const cardbus_name[] = {
  "BAR 1",
  "unknown",
  "unknown",
  "unknown",
  "unknown",
  "unknown",
#ifdef CONFIG_PCI_IOV
  "unknown",
  "unknown",
  "unknown",
  "unknown",
  "unknown",
  "unknown",
#endif
  "CardBus bridge window 0"/* I/O */
  "CardBus bridge window 1"/* I/O */
  "CardBus bridge window 0"/* mem */
  "CardBus bridge window 1"/* mem */
 };

 if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS &&
     i < ARRAY_SIZE(cardbus_name))
  return cardbus_name[i];

 if (i < ARRAY_SIZE(bar_name))
  return bar_name[i];

 return "unknown";
}

/**
 * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
 * @dev: the PCI device to operate on
 * @pos: config space offset of status word
 * @mask: mask of bit(s) to care about in status word
 *
 * Return 1 when mask bit(s) in status word clear, 0 otherwise.
 */

int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask)
{
 int i;

 /* Wait for Transaction Pending bit clean */
 for (i = 0; i < 4; i++) {
  u16 status;
  if (i)
   msleep((1 << (i - 1)) * 100);

  pci_read_config_word(dev, pos, &status);
  if (!(status & mask))
   return 1;
 }

 return 0;
}

static int pci_acs_enable;

/**
 * pci_request_acs - ask for ACS to be enabled if supported
 */

void pci_request_acs(void)
{
 pci_acs_enable = 1;
}

static const char *disable_acs_redir_param;
static const char *config_acs_param;

struct pci_acs {
 u16 cap;
 u16 ctrl;
 u16 fw_ctrl;
};

static void __pci_config_acs(struct pci_dev *dev, struct pci_acs *caps,
        const char *p, const u16 acs_mask, const u16 acs_flags)
{
 u16 flags = acs_flags;
 u16 mask = acs_mask;
 char *delimit;
 int ret = 0;

 if (!p)
  return;

 while (*p) {
  if (!acs_mask) {
   /* Check for ACS flags */
   delimit = strstr(p, "@");
   if (delimit) {
    int end;
    u32 shift = 0;

    end = delimit - p - 1;
    mask = 0;
    flags = 0;

    while (end > -1) {
     if (*(p + end) == '0') {
      mask |= 1 << shift;
      shift++;
      end--;
     } else if (*(p + end) == '1') {
      mask |= 1 << shift;
      flags |= 1 << shift;
      shift++;
      end--;
     } else if ((*(p + end) == 'x') || (*(p + end) == 'X')) {
      shift++;
      end--;
     } else {
      pci_err(dev, "Invalid ACS flags... Ignoring\n");
      return;
     }
    }
    p = delimit + 1;
   } else {
    pci_err(dev, "ACS Flags missing\n");
    return;
   }
  }

  if (mask & ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | PCI_ACS_CR |
       PCI_ACS_UF | PCI_ACS_EC | PCI_ACS_DT)) {
   pci_err(dev, "Invalid ACS flags specified\n");
   return;
  }

  ret = pci_dev_str_match(dev, p, &p);
  if (ret < 0) {
   pr_info_once("PCI: Can't parse ACS command line parameter\n");
   break;
  } else if (ret == 1) {
   /* Found a match */
   break;
  }

  if (*p != ';' && *p != ',') {
   /* End of param or invalid format */
   break;
  }
  p++;
 }

 if (ret != 1)
  return;

 if (!pci_dev_specific_disable_acs_redir(dev))
  return;

 pci_dbg(dev, "ACS mask = %#06x\n", mask);
 pci_dbg(dev, "ACS flags = %#06x\n", flags);
 pci_dbg(dev, "ACS control = %#06x\n", caps->ctrl);
 pci_dbg(dev, "ACS fw_ctrl = %#06x\n", caps->fw_ctrl);

 /*
 * For mask bits that are 0, copy them from the firmware setting
 * and apply flags for all the mask bits that are 1.
 */

 caps->ctrl = (caps->fw_ctrl & ~mask) | (flags & mask);

 pci_info(dev, "Configured ACS to %#06x\n", caps->ctrl);
}

/**
 * pci_std_enable_acs - enable ACS on devices using standard ACS capabilities
 * @dev: the PCI device
 * @caps: default ACS controls
 */

static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps)
{
 /* Source Validation */
 caps->ctrl |= (caps->cap & PCI_ACS_SV);

 /* P2P Request Redirect */
 caps->ctrl |= (caps->cap & PCI_ACS_RR);

 /* P2P Completion Redirect */
 caps->ctrl |= (caps->cap & PCI_ACS_CR);

 /* Upstream Forwarding */
 caps->ctrl |= (caps->cap & PCI_ACS_UF);

 /* Enable Translation Blocking for external devices and noats */
 if (pci_ats_disabled() || dev->external_facing || dev->untrusted)
  caps->ctrl |= (caps->cap & PCI_ACS_TB);
}

/**
 * pci_enable_acs - enable ACS if hardware support it
 * @dev: the PCI device
 */

static void pci_enable_acs(struct pci_dev *dev)
{
 struct pci_acs caps;
 bool enable_acs = false;
 int pos;

 /* If an iommu is present we start with kernel default caps */
 if (pci_acs_enable) {
  if (pci_dev_specific_enable_acs(dev))
   enable_acs = true;
 }

 pos = dev->acs_cap;
 if (!pos)
  return;

 pci_read_config_word(dev, pos + PCI_ACS_CAP, &caps.cap);
 pci_read_config_word(dev, pos + PCI_ACS_CTRL, &caps.ctrl);
 caps.fw_ctrl = caps.ctrl;

 if (enable_acs)
  pci_std_enable_acs(dev, &caps);

 /*
 * Always apply caps from the command line, even if there is no iommu.
 * Trust that the admin has a reason to change the ACS settings.
 */

 __pci_config_acs(dev, &caps, disable_acs_redir_param,
    PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC,
    ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC));
 __pci_config_acs(dev, &caps, config_acs_param, 0, 0);

 pci_write_config_word(dev, pos + PCI_ACS_CTRL, caps.ctrl);
}

/**
 * pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
 * @dev: PCI device to have its BARs restored
 *
 * Restore the BAR values for a given device, so as to make it
 * accessible by its driver.
 */

static void pci_restore_bars(struct pci_dev *dev)
{
 int i;

 for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
  pci_update_resource(dev, i);
}

static inline bool platform_pci_power_manageable(struct pci_dev *dev)
{
 if (pci_use_mid_pm())
  return true;

 return acpi_pci_power_manageable(dev);
}

static inline int platform_pci_set_power_state(struct pci_dev *dev,
            pci_power_t t)
{
 if (pci_use_mid_pm())
  return mid_pci_set_power_state(dev, t);

 return acpi_pci_set_power_state(dev, t);
}

static inline pci_power_t platform_pci_get_power_state(struct pci_dev *dev)
{
 if (pci_use_mid_pm())
  return mid_pci_get_power_state(dev);

 return acpi_pci_get_power_state(dev);
}

static inline void platform_pci_refresh_power_state(struct pci_dev *dev)
{
 if (!pci_use_mid_pm())
  acpi_pci_refresh_power_state(dev);
}

static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev)
{
 if (pci_use_mid_pm())
  return PCI_POWER_ERROR;

 return acpi_pci_choose_state(dev);
}

static inline int platform_pci_set_wakeup(struct pci_dev *dev, bool enable)
{
 if (pci_use_mid_pm())
  return PCI_POWER_ERROR;

 return acpi_pci_wakeup(dev, enable);
}

static inline bool platform_pci_need_resume(struct pci_dev *dev)
{
 if (pci_use_mid_pm())
  return false;

 return acpi_pci_need_resume(dev);
}

static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
{
 if (pci_use_mid_pm())
  return false;

 return acpi_pci_bridge_d3(dev);
}

/**
 * pci_update_current_state - Read power state of given device and cache it
 * @dev: PCI device to handle.
 * @state: State to cache in case the device doesn't have the PM capability
 *
 * The power state is read from the PMCSR register, which however is
 * inaccessible in D3cold.  The platform firmware is therefore queried first
 * to detect accessibility of the register.  In case the platform firmware
 * reports an incorrect state or the device isn't power manageable by the
 * platform at all, we try to detect D3cold by testing accessibility of the
 * vendor ID in config space.
 */

void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
{
 if (platform_pci_get_power_state(dev) == PCI_D3cold) {
  dev->current_state = PCI_D3cold;
 } else if (dev->pm_cap) {
  u16 pmcsr;

  pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
  if (PCI_POSSIBLE_ERROR(pmcsr)) {
   dev->current_state = PCI_D3cold;
   return;
  }
  dev->current_state = pmcsr & PCI_PM_CTRL_STATE_MASK;
 } else {
  dev->current_state = state;
 }
}

/**
 * pci_refresh_power_state - Refresh the given device's power state data
 * @dev: Target PCI device.
 *
 * Ask the platform to refresh the devices power state information and invoke
 * pci_update_current_state() to update its current PCI power state.
 */

void pci_refresh_power_state(struct pci_dev *dev)
{
 platform_pci_refresh_power_state(dev);
 pci_update_current_state(dev, dev->current_state);
}

/**
 * pci_platform_power_transition - Use platform to change device power state
 * @dev: PCI device to handle.
 * @state: State to put the device into.
 */

int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
{
 int error;

 error = platform_pci_set_power_state(dev, state);
 if (!error)
  pci_update_current_state(dev, state);
 else if (!dev->pm_cap) /* Fall back to PCI_D0 */
  dev->current_state = PCI_D0;

 return error;
}
EXPORT_SYMBOL_GPL(pci_platform_power_transition);

static int pci_resume_one(struct pci_dev *pci_dev, void *ign)
{
 pm_request_resume(&pci_dev->dev);
 return 0;
}

/**
 * pci_resume_bus - Walk given bus and runtime resume devices on it
 * @bus: Top bus of the subtree to walk.
 */

void pci_resume_bus(struct pci_bus *bus)
{
 if (bus)
  pci_walk_bus(bus, pci_resume_one, NULL);
}

static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
{
 int delay = 1;
 bool retrain = false;
 struct pci_dev *root, *bridge;

 root = pcie_find_root_port(dev);

 if (pci_is_pcie(dev)) {
  bridge = pci_upstream_bridge(dev);
  if (bridge)
   retrain = true;
 }

 /*
 * The caller has already waited long enough after a reset that the
 * device should respond to config requests, but it may respond
 * with Request Retry Status (RRS) if it needs more time to
 * initialize.
 *
 * If the device is below a Root Port with Configuration RRS
 * Software Visibility enabled, reading the Vendor ID returns a
 * special data value if the device responded with RRS.  Read the
 * Vendor ID until we get non-RRS status.
 *
 * If there's no Root Port or Configuration RRS Software Visibility
 * is not enabled, the device may still respond with RRS, but
 * hardware may retry the config request.  If no retries receive
 * Successful Completion, hardware generally synthesizes ~0
 * (PCI_ERROR_RESPONSE) data to complete the read.  Reading Vendor
 * ID for VFs and non-existent devices also returns ~0, so read the
 * Command register until it returns something other than ~0.
 */

 for (;;) {
  u32 id;

  if (pci_dev_is_disconnected(dev)) {
   pci_dbg(dev, "disconnected; not waiting\n");
   return -ENOTTY;
  }

  if (root && root->config_rrs_sv) {
   pci_read_config_dword(dev, PCI_VENDOR_ID, &id);
   if (!pci_bus_rrs_vendor_id(id))
    break;
  } else {
   pci_read_config_dword(dev, PCI_COMMAND, &id);
   if (!PCI_POSSIBLE_ERROR(id))
    break;
  }

  if (delay > timeout) {
   pci_warn(dev, "not ready %dms after %s; giving up\n",
     delay - 1, reset_type);
   return -ENOTTY;
  }

  if (delay > PCI_RESET_WAIT) {
   if (retrain) {
    retrain = false;
    if (pcie_failed_link_retrain(bridge) == 0) {
     delay = 1;
     continue;
    }
   }
   pci_info(dev, "not ready %dms after %s; waiting\n",
     delay - 1, reset_type);
  }

  msleep(delay);
  delay *= 2;
 }

 if (delay > PCI_RESET_WAIT)
  pci_info(dev, "ready %dms after %s\n", delay - 1,
    reset_type);
 else
  pci_dbg(dev, "ready %dms after %s\n", delay - 1,
   reset_type);

 return 0;
}

/**
 * pci_power_up - Put the given device into D0
 * @dev: PCI device to power up
 *
 * On success, return 0 or 1, depending on whether or not it is necessary to
 * restore the device's BARs subsequently (1 is returned in that case).
 *
 * On failure, return a negative error code.  Always return failure if @dev
 * lacks a Power Management Capability, even if the platform was able to
 * put the device in D0 via non-PCI means.
 */

int pci_power_up(struct pci_dev *dev)
{
 bool need_restore;
 pci_power_t state;
 u16 pmcsr;

 platform_pci_set_power_state(dev, PCI_D0);

 if (!dev->pm_cap) {
  state = platform_pci_get_power_state(dev);
  if (state == PCI_UNKNOWN)
   dev->current_state = PCI_D0;
  else
   dev->current_state = state;

  return -EIO;
 }

 if (pci_dev_is_disconnected(dev)) {
  dev->current_state = PCI_D3cold;
  return -EIO;
 }

 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 if (PCI_POSSIBLE_ERROR(pmcsr)) {
  pci_err(dev, "Unable to change power state from %s to D0, device inaccessible\n",
   pci_power_name(dev->current_state));
  dev->current_state = PCI_D3cold;
  return -EIO;
 }

 state = pmcsr & PCI_PM_CTRL_STATE_MASK;

 need_restore = (state == PCI_D3hot || dev->current_state >= PCI_D3hot) &&
   !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET);

 if (state == PCI_D0)
  goto end;

 /*
 * Force the entire word to 0. This doesn't affect PME_Status, disables
 * PME_En, and sets PowerState to 0.
 */

 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, 0);

 /* Mandatory transition delays; see PCI PM 1.2. */
 if (state == PCI_D3hot)
  pci_dev_d3_sleep(dev);
 else if (state == PCI_D2)
  udelay(PCI_PM_D2_DELAY);

end:
 dev->current_state = PCI_D0;
 if (need_restore)
  return 1;

 return 0;
}

/**
 * pci_set_full_power_state - Put a PCI device into D0 and update its state
 * @dev: PCI device to power up
 * @locked: whether pci_bus_sem is held
 *
 * Call pci_power_up() to put @dev into D0, read from its PCI_PM_CTRL register
 * to confirm the state change, restore its BARs if they might be lost and
 * reconfigure ASPM in accordance with the new power state.
 *
 * If pci_restore_state() is going to be called right after a power state change
 * to D0, it is more efficient to use pci_power_up() directly instead of this
 * function.
 */

static int pci_set_full_power_state(struct pci_dev *dev, bool locked)
{
 u16 pmcsr;
 int ret;

 ret = pci_power_up(dev);
 if (ret < 0) {
  if (dev->current_state == PCI_D0)
   return 0;

  return ret;
 }

 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 dev->current_state = pmcsr & PCI_PM_CTRL_STATE_MASK;
 if (dev->current_state != PCI_D0) {
  pci_info_ratelimited(dev, "Refused to change power state from %s to D0\n",
         pci_power_name(dev->current_state));
 } else if (ret > 0) {
  /*
 * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
 * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning
 * from D3hot to D0 _may_ perform an internal reset, thereby
 * going to "D0 Uninitialized" rather than "D0 Initialized".
 * For example, at least some versions of the 3c905B and the
 * 3c556B exhibit this behaviour.
 *
 * At least some laptop BIOSen (e.g. the Thinkpad T21) leave
 * devices in a D3hot state at boot.  Consequently, we need to
 * restore at least the BARs so that the device will be
 * accessible to its driver.
 */

  pci_restore_bars(dev);
 }

 if (dev->bus->self)
  pcie_aspm_pm_state_change(dev->bus->self, locked);

 return 0;
}

/**
 * __pci_dev_set_current_state - Set current state of a PCI device
 * @dev: Device to handle
 * @data: pointer to state to be set
 */

static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
{
 pci_power_t state = *(pci_power_t *)data;

 dev->current_state = state;
 return 0;
}

/**
 * pci_bus_set_current_state - Walk given bus and set current state of devices
 * @bus: Top bus of the subtree to walk.
 * @state: state to be set
 */

void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
{
 if (bus)
  pci_walk_bus(bus, __pci_dev_set_current_state, &state);
}

static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state, bool locked)
{
 if (!bus)
  return;

 if (locked)
  pci_walk_bus_locked(bus, __pci_dev_set_current_state, &state);
 else
  pci_walk_bus(bus, __pci_dev_set_current_state, &state);
}

/**
 * pci_set_low_power_state - Put a PCI device into a low-power state.
 * @dev: PCI device to handle.
 * @state: PCI power state (D1, D2, D3hot) to put the device into.
 * @locked: whether pci_bus_sem is held
 *
 * Use the device's PCI_PM_CTRL register to put it into a low-power state.
 *
 * RETURN VALUE:
 * -EINVAL if the requested state is invalid.
 * -EIO if device does not support PCI PM or its PM capabilities register has a
 * wrong version, or device doesn't support the requested state.
 * 0 if device already is in the requested state.
 * 0 if device's power state has been successfully changed.
 */

static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
{
 u16 pmcsr;

 if (!dev->pm_cap)
  return -EIO;

 /*
 * Validate transition: We can enter D0 from any state, but if
 * we're already in a low-power state, we can only go deeper.  E.g.,
 * we can go from D1 to D3, but we can't go directly from D3 to D1;
 * we'd have to go from D3 to D0, then to D1.
 */

 if (dev->current_state <= PCI_D3cold && dev->current_state > state) {
  pci_dbg(dev, "Invalid power transition (from %s to %s)\n",
   pci_power_name(dev->current_state),
   pci_power_name(state));
  return -EINVAL;
 }

 /* Check if this device supports the desired state */
 if ((state == PCI_D1 && !dev->d1_support)
    || (state == PCI_D2 && !dev->d2_support))
  return -EIO;

 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 if (PCI_POSSIBLE_ERROR(pmcsr)) {
  pci_err(dev, "Unable to change power state from %s to %s, device inaccessible\n",
   pci_power_name(dev->current_state),
   pci_power_name(state));
  dev->current_state = PCI_D3cold;
  return -EIO;
 }

 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
 pmcsr |= state;

 /* Enter specified state */
 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);

 /* Mandatory power management transition delays; see PCI PM 1.2. */
 if (state == PCI_D3hot)
  pci_dev_d3_sleep(dev);
 else if (state == PCI_D2)
  udelay(PCI_PM_D2_DELAY);

 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 dev->current_state = pmcsr & PCI_PM_CTRL_STATE_MASK;
 if (dev->current_state != state)
  pci_info_ratelimited(dev, "Refused to change power state from %s to %s\n",
         pci_power_name(dev->current_state),
         pci_power_name(state));

 if (dev->bus->self)
  pcie_aspm_pm_state_change(dev->bus->self, locked);

 return 0;
}

static int __pci_set_power_state(struct pci_dev *dev, pci_power_t state, bool locked)
{
 int error;

 /* Bound the state we're entering */
 if (state > PCI_D3cold)
  state = PCI_D3cold;
 else if (state < PCI_D0)
  state = PCI_D0;
 else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))

  /*
 * If the device or the parent bridge do not support PCI
 * PM, ignore the request if we're doing anything other
 * than putting it into D0 (which would only happen on
 * boot).
 */

  return 0;

 /* Check if we're already there */
 if (dev->current_state == state)
  return 0;

 if (state == PCI_D0)
  return pci_set_full_power_state(dev, locked);

 /*
 * This device is quirked not to be put into D3, so don't put it in
 * D3
 */

 if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
  return 0;

 if (state == PCI_D3cold) {
  /*
 * To put the device in D3cold, put it into D3hot in the native
 * way, then put it into D3cold using platform ops.
 */

  error = pci_set_low_power_state(dev, PCI_D3hot, locked);

  if (pci_platform_power_transition(dev, PCI_D3cold))
   return error;

  /* Powering off a bridge may power off the whole hierarchy */
  if (dev->current_state == PCI_D3cold)
   __pci_bus_set_current_state(dev->subordinate, PCI_D3cold, locked);
 } else {
  error = pci_set_low_power_state(dev, state, locked);

  if (pci_platform_power_transition(dev, state))
   return error;
 }

 return 0;
}

/**
 * pci_set_power_state - Set the power state of a PCI device
 * @dev: PCI device to handle.
 * @state: PCI power state (D0, D1, D2, D3hot) to put the device into.
 *
 * Transition a device to a new power state, using the platform firmware and/or
 * the device's PCI PM registers.
 *
 * RETURN VALUE:
 * -EINVAL if the requested state is invalid.
 * -EIO if device does not support PCI PM or its PM capabilities register has a
 * wrong version, or device doesn't support the requested state.
 * 0 if the transition is to D1 or D2 but D1 and D2 are not supported.
 * 0 if device already is in the requested state.
 * 0 if the transition is to D3 but D3 is not supported.
 * 0 if device's power state has been successfully changed.
 */

int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
 return __pci_set_power_state(dev, state, false);
}
EXPORT_SYMBOL(pci_set_power_state);

int pci_set_power_state_locked(struct pci_dev *dev, pci_power_t state)
{
 lockdep_assert_held(&pci_bus_sem);

 return __pci_set_power_state(dev, state, true);
}
EXPORT_SYMBOL(pci_set_power_state_locked);

#define PCI_EXP_SAVE_REGS 7

static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
             u16 cap, bool extended)
{
 struct pci_cap_saved_state *tmp;

 hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) {
  if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap)
   return tmp;
 }
 return NULL;
}

struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap)
{
 return _pci_find_saved_cap(dev, cap, false);
}

struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap)
{
 return _pci_find_saved_cap(dev, cap, true);
}

static int pci_save_pcie_state(struct pci_dev *dev)
{
 int i = 0;
 struct pci_cap_saved_state *save_state;
 u16 *cap;

 if (!pci_is_pcie(dev))
  return 0;

 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
 if (!save_state) {
  pci_err(dev, "buffer not found in %s\n", __func__);
  return -ENOMEM;
 }

 cap = (u16 *)&save_state->cap.data[0];
 pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_SLTCTL, &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_RTCTL,  &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
 pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);

 pci_save_aspm_l1ss_state(dev);
 pci_save_ltr_state(dev);

 return 0;
}

static void pci_restore_pcie_state(struct pci_dev *dev)
{
 int i = 0;
 struct pci_cap_saved_state *save_state;
 u16 *cap;

 /*
 * Restore max latencies (in the LTR capability) before enabling
 * LTR itself in PCI_EXP_DEVCTL2.
 */

 pci_restore_ltr_state(dev);
 pci_restore_aspm_l1ss_state(dev);

 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
 if (!save_state)
  return;

 /*
 * Downstream ports reset the LTR enable bit when link goes down.
 * Check and re-configure the bit here before restoring device.
 * PCIe r5.0, sec 7.5.3.16.
 */

 pci_bridge_reconfigure_ltr(dev);

 cap = (u16 *)&save_state->cap.data[0];
 pcie_capability_write_word(dev, PCI_EXP_DEVCTL, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_LNKCTL, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_SLTCTL, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_RTCTL, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, cap[i++]);
 pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, cap[i++]);
}

static int pci_save_pcix_state(struct pci_dev *dev)
{
 int pos;
 struct pci_cap_saved_state *save_state;

 pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
 if (!pos)
  return 0;

 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
 if (!save_state) {
  pci_err(dev, "buffer not found in %s\n", __func__);
  return -ENOMEM;
 }

 pci_read_config_word(dev, pos + PCI_X_CMD,
        (u16 *)save_state->cap.data);

 return 0;
}

static void pci_restore_pcix_state(struct pci_dev *dev)
{
 int i = 0, pos;
 struct pci_cap_saved_state *save_state;
 u16 *cap;

 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
 pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
 if (!save_state || !pos)
  return;
 cap = (u16 *)&save_state->cap.data[0];

 pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
}

/**
 * pci_save_state - save the PCI configuration space of a device before
 *     suspending
 * @dev: PCI device that we're dealing with
 */

int pci_save_state(struct pci_dev *dev)
{
 int i;
 /* XXX: 100% dword access ok here? */
 for (i = 0; i < 16; i++) {
  pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);
  pci_dbg(dev, "save config %#04x: %#010x\n",
   i * 4, dev->saved_config_space[i]);
 }
 dev->state_saved = true;

 i = pci_save_pcie_state(dev);
 if (i != 0)
  return i;

 i = pci_save_pcix_state(dev);
 if (i != 0)
  return i;

 pci_save_dpc_state(dev);
 pci_save_aer_state(dev);
 pci_save_ptm_state(dev);
 pci_save_tph_state(dev);
 return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);

static void pci_restore_config_dword(struct pci_dev *pdev, int offset,
         u32 saved_val, int retry, bool force)
{
 u32 val;

 pci_read_config_dword(pdev, offset, &val);
 if (!force && val == saved_val)
  return;

 for (;;) {
  pci_dbg(pdev, "restore config %#04x: %#010x -> %#010x\n",
   offset, val, saved_val);
  pci_write_config_dword(pdev, offset, saved_val);
  if (retry-- <= 0)
   return;

  pci_read_config_dword(pdev, offset, &val);
  if (val == saved_val)
   return;

  mdelay(1);
 }
}

static void pci_restore_config_space_range(struct pci_dev *pdev,
        int start, int end, int retry,
        bool force)
{
 int index;

 for (index = end; index >= start; index--)
  pci_restore_config_dword(pdev, 4 * index,
      pdev->saved_config_space[index],
      retry, force);
}

static void pci_restore_config_space(struct pci_dev *pdev)
{
 if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
  pci_restore_config_space_range(pdev, 10, 15, 0, false);
  /* Restore BARs before the command register. */
  pci_restore_config_space_range(pdev, 4, 9, 10, false);
  pci_restore_config_space_range(pdev, 0, 3, 0, false);
 } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
  pci_restore_config_space_range(pdev, 12, 15, 0, false);

  /*
 * Force rewriting of prefetch registers to avoid S3 resume
 * issues on Intel PCI bridges that occur when these
 * registers are not explicitly written.
 */

  pci_restore_config_space_range(pdev, 9, 11, 0, true);
  pci_restore_config_space_range(pdev, 0, 8, 0, false);
 } else {
  pci_restore_config_space_range(pdev, 0, 15, 0, false);
 }
}

static void pci_restore_rebar_state(struct pci_dev *pdev)
{
 unsigned int pos, nbars, i;
 u32 ctrl;

 pos = pdev->rebar_cap;
 if (!pos)
  return;

 pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
 nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);

 for (i = 0; i < nbars; i++, pos += 8) {
  struct resource *res;
  int bar_idx, size;

  pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
  bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
  res = pci_resource_n(pdev, bar_idx);
  size = pci_rebar_bytes_to_size(resource_size(res));
  ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
  ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
  pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
 }
}

/**
 * pci_restore_state - Restore the saved state of a PCI device
 * @dev: PCI device that we're dealing with
 */

void pci_restore_state(struct pci_dev *dev)
{
 if (!dev->state_saved)
  return;

 pci_restore_pcie_state(dev);
 pci_restore_pasid_state(dev);
 pci_restore_pri_state(dev);
 pci_restore_ats_state(dev);
 pci_restore_vc_state(dev);
 pci_restore_rebar_state(dev);
 pci_restore_dpc_state(dev);
 pci_restore_ptm_state(dev);
 pci_restore_tph_state(dev);

 pci_aer_clear_status(dev);
 pci_restore_aer_state(dev);

 pci_restore_config_space(dev);

 pci_restore_pcix_state(dev);
 pci_restore_msi_state(dev);

 /* Restore ACS and IOV configuration state */
 pci_enable_acs(dev);
 pci_restore_iov_state(dev);

 dev->state_saved = false;
}
EXPORT_SYMBOL(pci_restore_state);

struct pci_saved_state {
 u32 config_space[16];
 struct pci_cap_saved_data cap[];
};

/**
 * pci_store_saved_state - Allocate and return an opaque struct containing
 *    the device saved state.
 * @dev: PCI device that we're dealing with
 *
 * Return NULL if no state or error.
 */

struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev)
{
 struct pci_saved_state *state;
 struct pci_cap_saved_state *tmp;
 struct pci_cap_saved_data *cap;
 size_t size;

 if (!dev->state_saved)
  return NULL;

 size = sizeof(*state) + sizeof(struct pci_cap_saved_data);

 hlist_for_each_entry(tmp, &dev->saved_cap_space, next)
  size += sizeof(struct pci_cap_saved_data) + tmp->cap.size;

 state = kzalloc(size, GFP_KERNEL);
 if (!state)
  return NULL;

 memcpy(state->config_space, dev->saved_config_space,
        sizeof(state->config_space));

 cap = state->cap;
 hlist_for_each_entry(tmp, &dev->saved_cap_space, next) {
  size_t len = sizeof(struct pci_cap_saved_data) + tmp->cap.size;
  memcpy(cap, &tmp->cap, len);
  cap = (struct pci_cap_saved_data *)((u8 *)cap + len);
 }
 /* Empty cap_save terminates list */

 return state;
}
EXPORT_SYMBOL_GPL(pci_store_saved_state);

/**
 * pci_load_saved_state - Reload the provided save state into struct pci_dev.
 * @dev: PCI device that we're dealing with
 * @state: Saved state returned from pci_store_saved_state()
 */

int pci_load_saved_state(struct pci_dev *dev,
    struct pci_saved_state *state)
{
 struct pci_cap_saved_data *cap;

 dev->state_saved = false;

 if (!state)
  return 0;

 memcpy(dev->saved_config_space, state->config_space,
        sizeof(state->config_space));

 cap = state->cap;
 while (cap->size) {
  struct pci_cap_saved_state *tmp;

  tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended);
  if (!tmp || tmp->cap.size != cap->size)
   return -EINVAL;

  memcpy(tmp->cap.data, cap->data, tmp->cap.size);
  cap = (struct pci_cap_saved_data *)((u8 *)cap +
         sizeof(struct pci_cap_saved_data) + cap->size);
 }

 dev->state_saved = true;
 return 0;
}
EXPORT_SYMBOL_GPL(pci_load_saved_state);

/**
 * pci_load_and_free_saved_state - Reload the save state pointed to by state,
 *    and free the memory allocated for it.
 * @dev: PCI device that we're dealing with
 * @state: Pointer to saved state returned from pci_store_saved_state()
 */

int pci_load_and_free_saved_state(struct pci_dev *dev,
      struct pci_saved_state **state)
{
 int ret = pci_load_saved_state(dev, *state);
 kfree(*state);
 *state = NULL;
 return ret;
}
EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);

int __weak pcibios_enable_device(struct pci_dev *dev, int bars)
{
 return pci_enable_resources(dev, bars);
}

static int pci_host_bridge_enable_device(struct pci_dev *dev)
{
 struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);
 int err;

 if (host_bridge && host_bridge->enable_device) {
  err = host_bridge->enable_device(host_bridge, dev);
  if (err)
   return err;
 }

 return 0;
}

static void pci_host_bridge_disable_device(struct pci_dev *dev)
{
 struct pci_host_bridge *host_bridge = pci_find_host_bridge(dev->bus);

 if (host_bridge && host_bridge->disable_device)
  host_bridge->disable_device(host_bridge, dev);
}

static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
 int err;
 struct pci_dev *bridge;
 u16 cmd;
 u8 pin;

 err = pci_set_power_state(dev, PCI_D0);
 if (err < 0 && err != -EIO)
  return err;

 bridge = pci_upstream_bridge(dev);
 if (bridge)
  pcie_aspm_powersave_config_link(bridge);

 err = pci_host_bridge_enable_device(dev);
 if (err)
  return err;

 err = pcibios_enable_device(dev, bars);
 if (err < 0)
  goto err_enable;
 pci_fixup_device(pci_fixup_enable, dev);

 if (dev->msi_enabled || dev->msix_enabled)
  return 0;

 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 if (pin) {
  pci_read_config_word(dev, PCI_COMMAND, &cmd);
  if (cmd & PCI_COMMAND_INTX_DISABLE)
   pci_write_config_word(dev, PCI_COMMAND,
           cmd & ~PCI_COMMAND_INTX_DISABLE);
 }

 return 0;

err_enable:
 pci_host_bridge_disable_device(dev);

 return err;

}

/**
 * pci_reenable_device - Resume abandoned device
 * @dev: PCI device to be resumed
 *
 * NOTE: This function is a backend of pci_default_resume() and is not supposed
 * to be called by normal code, write proper resume handler and use it instead.
 */

int pci_reenable_device(struct pci_dev *dev)
{
 if (pci_is_enabled(dev))
  return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
 return 0;
}
EXPORT_SYMBOL(pci_reenable_device);

static void pci_enable_bridge(struct pci_dev *dev)
{
 struct pci_dev *bridge;
 int retval;

 bridge = pci_upstream_bridge(dev);
 if (bridge)
  pci_enable_bridge(bridge);

 if (pci_is_enabled(dev)) {
  if (!dev->is_busmaster)
   pci_set_master(dev);
  return;
 }

 retval = pci_enable_device(dev);
 if (retval)
  pci_err(dev, "Error enabling bridge (%d), continuing\n",
   retval);
 pci_set_master(dev);
}

static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
{
 struct pci_dev *bridge;
 int err;
 int i, bars = 0;

 /*
 * Power state could be unknown at this point, either due to a fresh
 * boot or a device removal call.  So get the current power state
 * so that things like MSI message writing will behave as expected
 * (e.g. if the device really is in D0 at enable time).
 */

 pci_update_current_state(dev, dev->current_state);

 if (atomic_inc_return(&dev->enable_cnt) > 1)
  return 0;  /* already enabled */

 bridge = pci_upstream_bridge(dev);
 if (bridge)
  pci_enable_bridge(bridge);

 /* only skip sriov related */
 for (i = 0; i <= PCI_ROM_RESOURCE; i++)
  if (dev->resource[i].flags & flags)
   bars |= (1 << i);
 for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++)
  if (dev->resource[i].flags & flags)
   bars |= (1 << i);

 err = do_pci_enable_device(dev, bars);
 if (err < 0)
  atomic_dec(&dev->enable_cnt);
 return err;
}

/**
 * pci_enable_device_mem - Initialize a device for use with Memory space
 * @dev: PCI device to be initialized
 *
 * Initialize device before it's used by a driver. Ask low-level code
 * to enable Memory resources. Wake up the device if it was suspended.
 * Beware, this function can fail.
 */

int pci_enable_device_mem(struct pci_dev *dev)
{
 return pci_enable_device_flags(dev, IORESOURCE_MEM);
}
EXPORT_SYMBOL(pci_enable_device_mem);

/**
 * pci_enable_device - Initialize device before it's used by a driver.
 * @dev: PCI device to be initialized
 *
 * Initialize device before it's used by a driver. Ask low-level code
 * to enable I/O and memory. Wake up the device if it was suspended.
 * Beware, this function can fail.
 *
 * Note we don't actually enable the device many times if we call
 * this function repeatedly (we just increment the count).
 */

int pci_enable_device(struct pci_dev *dev)
{
 return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
}
EXPORT_SYMBOL(pci_enable_device);

/*
 * pcibios_device_add - provide arch specific hooks when adding device dev
 * @dev: the PCI device being added
 *
 * Permits the platform to provide architecture specific functionality when
 * devices are added. This is the default implementation. Architecture
 * implementations can override this.
 */

int __weak pcibios_device_add(struct pci_dev *dev)
{
 return 0;
}

/**
 * pcibios_release_device - provide arch specific hooks when releasing
 *     device dev
 * @dev: the PCI device being released
 *
 * Permits the platform to provide architecture specific functionality when
 * devices are released. This is the default implementation. Architecture
 * implementations can override this.
 */

void __weak pcibios_release_device(struct pci_dev *dev) {}

/**
 * pcibios_disable_device - disable arch specific PCI resources for device dev
 * @dev: the PCI device to disable
 *
 * Disables architecture specific PCI resources for the device. This
 * is the default implementation. Architecture implementations can
 * override this.
 */

void __weak pcibios_disable_device(struct pci_dev *dev) {}

static void do_pci_disable_device(struct pci_dev *dev)
{
 u16 pci_command;

 pci_read_config_word(dev, PCI_COMMAND, &pci_command);
 if (pci_command & PCI_COMMAND_MASTER) {
  pci_command &= ~PCI_COMMAND_MASTER;
  pci_write_config_word(dev, PCI_COMMAND, pci_command);
 }

 pcibios_disable_device(dev);
}

/**
 * pci_disable_enabled_device - Disable device without updating enable_cnt
 * @dev: PCI device to disable
 *
 * NOTE: This function is a backend of PCI power management routines and is
 * not supposed to be called drivers.
 */

void pci_disable_enabled_device(struct pci_dev *dev)
{
 if (pci_is_enabled(dev))
  do_pci_disable_device(dev);
}

/**
 * pci_disable_device - Disable PCI device after use
 * @dev: PCI device to be disabled
 *
 * Signal to the system that the PCI device is not in use by the system
 * anymore.  This only involves disabling PCI bus-mastering, if active.
 *
 * Note we don't actually disable the device until all callers of
 * pci_enable_device() have called pci_disable_device().
 */

void pci_disable_device(struct pci_dev *dev)
{
 dev_WARN_ONCE(&dev->dev, atomic_read(&dev->enable_cnt) <= 0,
        "disabling already-disabled device");

 if (atomic_dec_return(&dev->enable_cnt) != 0)
  return;

 pci_host_bridge_disable_device(dev);

 do_pci_disable_device(dev);

 dev->is_busmaster = 0;
}
EXPORT_SYMBOL(pci_disable_device);

/**
 * pcibios_set_pcie_reset_state - set reset state for device dev
 * @dev: the PCIe device reset
 * @state: Reset state to enter into
 *
 * Set the PCIe reset state for the device. This is the default
 * implementation. Architecture implementations can override this.
 */

int __weak pcibios_set_pcie_reset_state(struct pci_dev *dev,
     enum pcie_reset_state state)
{
 return -EINVAL;
}

/**
 * pci_set_pcie_reset_state - set reset state for device dev
 * @dev: the PCIe device reset
 * @state: Reset state to enter into
 *
 * Sets the PCI reset state for the device.
 */

int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
{
 return pcibios_set_pcie_reset_state(dev, state);
}
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);

#ifdef CONFIG_PCIEAER
void pcie_clear_device_status(struct pci_dev *dev)
{
 u16 sta;

 pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
 pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
}
#endif

/**
 * pcie_clear_root_pme_status - Clear root port PME interrupt status.
 * @dev: PCIe root port or event collector.
 */

void pcie_clear_root_pme_status(struct pci_dev *dev)
{
 pcie_capability_set_dword(dev, PCI_EXP_RTSTA, PCI_EXP_RTSTA_PME);
}

/**
 * pci_check_pme_status - Check if given device has generated PME.
 * @dev: Device to check.
 *
 * Check the PME status of the device and if set, clear it and clear PME enable
 * (if set).  Return 'true' if PME status and PME enable were both set or
 * 'false' otherwise.
 */

bool pci_check_pme_status(struct pci_dev *dev)
{
 int pmcsr_pos;
 u16 pmcsr;
 bool ret = false;

 if (!dev->pm_cap)
  return false;

 pmcsr_pos = dev->pm_cap + PCI_PM_CTRL;
 pci_read_config_word(dev, pmcsr_pos, &pmcsr);
 if (!(pmcsr & PCI_PM_CTRL_PME_STATUS))
  return false;

 /* Clear PME status. */
 pmcsr |= PCI_PM_CTRL_PME_STATUS;
 if (pmcsr & PCI_PM_CTRL_PME_ENABLE) {
  /* Disable PME to avoid interrupt flood. */
  pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
  ret = true;
 }

 pci_write_config_word(dev, pmcsr_pos, pmcsr);

 return ret;
}

/**
 * pci_pme_wakeup - Wake up a PCI device if its PME Status bit is set.
 * @dev: Device to handle.
 * @pme_poll_reset: Whether or not to reset the device's pme_poll flag.
 *
 * Check if @dev has generated PME and queue a resume request for it in that
 * case.
 */

static int pci_pme_wakeup(struct pci_dev *dev, void *pme_poll_reset)
{
 if (pme_poll_reset && dev->pme_poll)
  dev->pme_poll = false;

 if (pci_check_pme_status(dev)) {
  pci_wakeup_event(dev);
  pm_request_resume(&dev->dev);
 }
 return 0;
}

/**
 * pci_pme_wakeup_bus - Walk given bus and wake up devices on it, if necessary.
 * @bus: Top bus of the subtree to walk.
 */

void pci_pme_wakeup_bus(struct pci_bus *bus)
{
 if (bus)
  pci_walk_bus(bus, pci_pme_wakeup, (void *)true);
}


/**
 * pci_pme_capable - check the capability of PCI device to generate PME#
 * @dev: PCI device to handle.
 * @state: PCI state from which device will issue PME#.
 */

bool pci_pme_capable(struct pci_dev *dev, pci_power_t state)
{
 if (!dev->pm_cap)
  return false;

 return !!(dev->pme_support & (1 << state));
}
EXPORT_SYMBOL(pci_pme_capable);

static void pci_pme_list_scan(struct work_struct *work)
{
 struct pci_pme_device *pme_dev, *n;

 mutex_lock(&pci_pme_list_mutex);
 list_for_each_entry_safe(pme_dev, n, &pci_pme_list, list) {
  struct pci_dev *pdev = pme_dev->dev;

  if (pdev->pme_poll) {
   struct pci_dev *bridge = pdev->bus->self;
   struct device *dev = &pdev->dev;
   struct device *bdev = bridge ? &bridge->dev : NULL;
   int bref = 0;

   /*
 * If we have a bridge, it should be in an active/D0
 * state or the configuration space of subordinate
 * devices may not be accessible or stable over the
 * course of the call.
 */

   if (bdev) {
    bref = pm_runtime_get_if_active(bdev);
    if (!bref)
     continue;

    if (bridge->current_state != PCI_D0)
     goto put_bridge;
   }

   /*
 * The device itself should be suspended but config
 * space must be accessible, therefore it cannot be in
 * D3cold.
 */

   if (pm_runtime_suspended(dev) &&
       pdev->current_state != PCI_D3cold)
    pci_pme_wakeup(pdev, NULL);

put_bridge:
   if (bref > 0)
    pm_runtime_put(bdev);
  } else {
   list_del(&pme_dev->list);
   kfree(pme_dev);
  }
 }
 if (!list_empty(&pci_pme_list))
  queue_delayed_work(system_freezable_wq, &pci_pme_work,
       msecs_to_jiffies(PME_TIMEOUT));
 mutex_unlock(&pci_pme_list_mutex);
}

static void __pci_pme_active(struct pci_dev *dev, bool enable)
{
 u16 pmcsr;

 if (!dev->pme_support)
  return;

 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
 /* Clear PME_Status by writing 1 to it and enable PME# */
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.