PCI changes for the v3.14 merge window:

Resource management
     - Change pci_bus_region addresses to dma_addr_t (Bjorn Helgaas)
     - Support 64-bit AGP BARs (Bjorn Helgaas, Yinghai Lu)
     - Add pci_bus_address() to get bus address of a BAR (Bjorn Helgaas)
     - Use pci_resource_start() for CPU address of AGP BARs (Bjorn Helgaas)
     - Enforce bus address limits in resource allocation (Yinghai Lu)
     - Allocate 64-bit BARs above 4G when possible (Yinghai Lu)
     - Convert pcibios_resource_to_bus() to take pci_bus, not pci_dev (Yinghai Lu)
 
   PCI device hotplug
     - Major rescan/remove locking update (Rafael J. Wysocki)
     - Make ioapic builtin only (not modular) (Yinghai Lu)
     - Fix release/free issues (Yinghai Lu)
     - Clean up pciehp (Bjorn Helgaas)
     - Announce pciehp slot info during enumeration (Bjorn Helgaas)
 
   MSI
     - Add pci_msi_vec_count(), pci_msix_vec_count() (Alexander Gordeev)
     - Add pci_enable_msi_range(), pci_enable_msix_range() (Alexander Gordeev)
     - Deprecate "tri-state" interfaces: fail/success/fail+info (Alexander Gordeev)
     - Export MSI mode using attributes, not kobjects (Greg Kroah-Hartman)
     - Drop "irq" param from *_restore_msi_irqs() (DuanZhenzhong)
 
   SR-IOV
     - Clear NumVFs when disabling SR-IOV in sriov_init() (ethan.zhao)
 
   Virtualization
     - Add support for save/restore of extended capabilities (Alex Williamson)
     - Add Virtual Channel to save/restore support (Alex Williamson)
     - Never treat a VF as a multifunction device (Alex Williamson)
     - Add pci_try_reset_function(), et al (Alex Williamson)
 
   AER
     - Ignore non-PCIe error sources (Betty Dall)
     - Support ACPI HEST error sources for domains other than 0 (Betty Dall)
     - Consolidate HEST error source parsers (Bjorn Helgaas)
     - Add a TLP header print helper (Borislav Petkov)
 
   Freescale i.MX6
     - Remove unnecessary code (Fabio Estevam)
     - Make reset-gpio optional (Marek Vasut)
     - Report "link up" only after link training completes (Marek Vasut)
     - Start link in Gen1 before negotiating for Gen2 mode (Marek Vasut)
     - Fix PCIe startup code (Richard Zhu)
 
   Marvell MVEBU
     - Remove duplicate of_clk_get_by_name() call (Andrew Lunn)
     - Drop writes to bridge Secondary Status register (Jason Gunthorpe)
     - Obey bridge PCI_COMMAND_MEM and PCI_COMMAND_IO bits (Jason Gunthorpe)
     - Support a bridge with no IO port window (Jason Gunthorpe)
     - Use max_t() instead of max(resource_size_t,) (Jingoo Han)
     - Remove redundant of_match_ptr (Sachin Kamat)
     - Call pci_ioremap_io() at startup instead of dynamically (Thomas Petazzoni)
 
   NVIDIA Tegra
     - Disable Gen2 for Tegra20 and Tegra30 (Eric Brower)
 
   Renesas R-Car
     - Add runtime PM support (Valentine Barshak)
     - Fix rcar_pci_probe() return value check (Wei Yongjun)
 
   Synopsys DesignWare
     - Fix crash in dw_msi_teardown_irq() (Bjørn Erik Nilsen)
     - Remove redundant call to pci_write_config_word() (Bjørn Erik Nilsen)
     - Fix missing MSI IRQs (Harro Haan)
     - Add dw_pcie prefix before cfg_read/write (Pratyush Anand)
     - Fix I/O transfers by using CPU (not realio) address (Pratyush Anand)
     - Whitespace cleanup (Jingoo Han)
 
   EISA
     - Call put_device() if device_register() fails (Levente Kurusa)
     - Revert EISA initialization breakage ((Bjorn Helgaas)
 
   Miscellaneous
     - Remove unused code, including PCIe 3.0 interfaces (Stephen Hemminger)
     - Prevent bus conflicts while checking for bridge apertures (Bjorn Helgaas)
     - Stop clearing bridge Secondary Status when setting up I/O aperture (Bjorn Helgaas)
     - Use dev_is_pci() to identify PCI devices (Yijing Wang)
     - Deprecate DEFINE_PCI_DEVICE_TABLE (Joe Perches)
     - Update documentation 00-INDEX (Erik Ekman)
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJS3ujEAAoJEFmIoMA60/r8A4EQAK9AZSUSVNWvlKdC1PrBfT3w
 7fVILx5A4KWsOU8eoFwCPQLrgvUtMltg16yN2tbCjqpKEdrVc36biMO9bwhnXSyZ
 KopHKMWnn0sza/z2H8mcGy+0azGdWcIjcErX/a8WeS6zyWBjm+yzckrHNVpPu4Ca
 SpCBhfgBMjKyIZyLtP6juFSH34S2DfQex4oUSyPC+gjqPy5wW/xw/kBxZfOXl+yU
 P9pQT+geMIc31pETMdG9wd/TT+47YAui4ieSggoVxfVrphCXv6S8mOMCMuQc2bAy
 MHy9uFm1jbvKZZIYrzJ+9HFiiU/6MNiOO3Ygua52xuSp1Zrcjwi2CLD9/QBXbDVs
 pTKU5JIO7q43llkQUpIXTwBvEApSZRhuqzXegsMAYIg4AWmbfm/2fXkfWlQThYMp
 J48blAJZ4t0vhMr9usgwbtdBe8F5euExOxpwH0QMCMABbuu8/B3TLm39+LTcIbsw
 Efgm3N9iUTyiV5fe9Rr62nflhyqXjTevPl4wbZZe4OOdm0MXZY+/BzuNJhg3wyY8
 QKz2J3FB6OR7BCLHCp80l50s5+Ih4F5kmOXwFKjT1D1MFRaNaPDmp9BY6TitU6hg
 zj55gP4c8x6n3alakbf972Yhgs/4oi1va8cZL+pCYWb8nPO5ldaMiT7QBBLUreQV
 BtDtC7u/AFWJ5e73+jVO
 =La1R
 -----END PGP SIGNATURE-----

Merge tag 'pci-v3.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI updates from Bjorn Helgaas:
 "PCI changes for the v3.14 merge window:

  Resource management
    - Change pci_bus_region addresses to dma_addr_t (Bjorn Helgaas)
    - Support 64-bit AGP BARs (Bjorn Helgaas, Yinghai Lu)
    - Add pci_bus_address() to get bus address of a BAR (Bjorn Helgaas)
    - Use pci_resource_start() for CPU address of AGP BARs (Bjorn Helgaas)
    - Enforce bus address limits in resource allocation (Yinghai Lu)
    - Allocate 64-bit BARs above 4G when possible (Yinghai Lu)
    - Convert pcibios_resource_to_bus() to take pci_bus, not pci_dev (Yinghai Lu)

  PCI device hotplug
    - Major rescan/remove locking update (Rafael J. Wysocki)
    - Make ioapic builtin only (not modular) (Yinghai Lu)
    - Fix release/free issues (Yinghai Lu)
    - Clean up pciehp (Bjorn Helgaas)
    - Announce pciehp slot info during enumeration (Bjorn Helgaas)

  MSI
    - Add pci_msi_vec_count(), pci_msix_vec_count() (Alexander Gordeev)
    - Add pci_enable_msi_range(), pci_enable_msix_range() (Alexander Gordeev)
    - Deprecate "tri-state" interfaces: fail/success/fail+info (Alexander Gordeev)
    - Export MSI mode using attributes, not kobjects (Greg Kroah-Hartman)
    - Drop "irq" param from *_restore_msi_irqs() (DuanZhenzhong)

  SR-IOV
    - Clear NumVFs when disabling SR-IOV in sriov_init() (ethan.zhao)

  Virtualization
    - Add support for save/restore of extended capabilities (Alex Williamson)
    - Add Virtual Channel to save/restore support (Alex Williamson)
    - Never treat a VF as a multifunction device (Alex Williamson)
    - Add pci_try_reset_function(), et al (Alex Williamson)

  AER
    - Ignore non-PCIe error sources (Betty Dall)
    - Support ACPI HEST error sources for domains other than 0 (Betty Dall)
    - Consolidate HEST error source parsers (Bjorn Helgaas)
    - Add a TLP header print helper (Borislav Petkov)

  Freescale i.MX6
    - Remove unnecessary code (Fabio Estevam)
    - Make reset-gpio optional (Marek Vasut)
    - Report "link up" only after link training completes (Marek Vasut)
    - Start link in Gen1 before negotiating for Gen2 mode (Marek Vasut)
    - Fix PCIe startup code (Richard Zhu)

  Marvell MVEBU
    - Remove duplicate of_clk_get_by_name() call (Andrew Lunn)
    - Drop writes to bridge Secondary Status register (Jason Gunthorpe)
    - Obey bridge PCI_COMMAND_MEM and PCI_COMMAND_IO bits (Jason Gunthorpe)
    - Support a bridge with no IO port window (Jason Gunthorpe)
    - Use max_t() instead of max(resource_size_t,) (Jingoo Han)
    - Remove redundant of_match_ptr (Sachin Kamat)
    - Call pci_ioremap_io() at startup instead of dynamically (Thomas Petazzoni)

  NVIDIA Tegra
    - Disable Gen2 for Tegra20 and Tegra30 (Eric Brower)

  Renesas R-Car
    - Add runtime PM support (Valentine Barshak)
    - Fix rcar_pci_probe() return value check (Wei Yongjun)

  Synopsys DesignWare
    - Fix crash in dw_msi_teardown_irq() (Bjørn Erik Nilsen)
    - Remove redundant call to pci_write_config_word() (Bjørn Erik Nilsen)
    - Fix missing MSI IRQs (Harro Haan)
    - Add dw_pcie prefix before cfg_read/write (Pratyush Anand)
    - Fix I/O transfers by using CPU (not realio) address (Pratyush Anand)
    - Whitespace cleanup (Jingoo Han)

  EISA
    - Call put_device() if device_register() fails (Levente Kurusa)
    - Revert EISA initialization breakage ((Bjorn Helgaas)

  Miscellaneous
    - Remove unused code, including PCIe 3.0 interfaces (Stephen Hemminger)
    - Prevent bus conflicts while checking for bridge apertures (Bjorn Helgaas)
    - Stop clearing bridge Secondary Status when setting up I/O aperture (Bjorn Helgaas)
    - Use dev_is_pci() to identify PCI devices (Yijing Wang)
    - Deprecate DEFINE_PCI_DEVICE_TABLE (Joe Perches)
    - Update documentation 00-INDEX (Erik Ekman)"

* tag 'pci-v3.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (119 commits)
  Revert "EISA: Initialize device before its resources"
  Revert "EISA: Log device resources in dmesg"
  vfio-pci: Use pci "try" reset interface
  PCI: Check parent kobject in pci_destroy_dev()
  xen/pcifront: Use global PCI rescan-remove locking
  powerpc/eeh: Use global PCI rescan-remove locking
  PCI: Fix pci_check_and_unmask_intx() comment typos
  PCI: Add pci_try_reset_function(), pci_try_reset_slot(), pci_try_reset_bus()
  MPT / PCI: Use pci_stop_and_remove_bus_device_locked()
  platform / x86: Use global PCI rescan-remove locking
  PCI: hotplug: Use global PCI rescan-remove locking
  pcmcia: Use global PCI rescan-remove locking
  ACPI / hotplug / PCI: Use global PCI rescan-remove locking
  ACPI / PCI: Use global PCI rescan-remove locking in PCI root hotplug
  PCI: Add global pci_lock_rescan_remove()
  PCI: Cleanup pci.h whitespace
  PCI: Reorder so actual code comes before stubs
  PCI/AER: Support ACPI HEST AER error sources for PCI domains other than 0
  ACPICA: Add helper macros to extract bus/segment numbers from HEST table.
  PCI: Make local functions static
  ...
This commit is contained in:
Linus Torvalds 2014-01-22 16:39:28 -08:00
commit e1ba84597c
109 changed files with 2523 additions and 1998 deletions

View file

@ -430,6 +430,32 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
return best;
}
/**
* 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;
}
/**
* pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored
@ -656,6 +682,28 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
return error;
}
/**
* pci_wakeup - Wake up a PCI device
* @pci_dev: Device to handle.
* @ign: ignored parameter
*/
static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
{
pci_wakeup_event(pci_dev);
pm_request_resume(&pci_dev->dev);
return 0;
}
/**
* pci_wakeup_bus - Walk given bus and wake up devices on it
* @bus: Top bus of the subtree to walk.
*/
static void pci_wakeup_bus(struct pci_bus *bus)
{
if (bus)
pci_walk_bus(bus, pci_wakeup, NULL);
}
/**
* __pci_start_power_transition - Start power transition of a PCI device
* @dev: PCI device to handle.
@ -835,18 +883,28 @@ EXPORT_SYMBOL(pci_choose_state);
#define PCI_EXP_SAVE_REGS 7
static struct pci_cap_saved_state *pci_find_saved_cap(
struct pci_dev *pci_dev, char cap)
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_nr == cap)
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;
@ -948,6 +1006,8 @@ pci_save_state(struct pci_dev *dev)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
return i;
if ((i = pci_save_vc_state(dev)) != 0)
return i;
return 0;
}
@ -1010,6 +1070,7 @@ void pci_restore_state(struct pci_dev *dev)
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
pci_restore_config_space(dev);
@ -1071,7 +1132,8 @@ EXPORT_SYMBOL_GPL(pci_store_saved_state);
* @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)
static int pci_load_saved_state(struct pci_dev *dev,
struct pci_saved_state *state)
{
struct pci_cap_saved_data *cap;
@ -1087,7 +1149,7 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
while (cap->size) {
struct pci_cap_saved_state *tmp;
tmp = pci_find_saved_cap(dev, cap->cap_nr);
tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended);
if (!tmp || tmp->cap.size != cap->size)
return -EINVAL;
@ -1099,7 +1161,6 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
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,
@ -1531,27 +1592,6 @@ void pci_pme_wakeup_bus(struct pci_bus *bus)
pci_walk_bus(bus, pci_pme_wakeup, (void *)true);
}
/**
* pci_wakeup - Wake up a PCI device
* @pci_dev: Device to handle.
* @ign: ignored parameter
*/
static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
{
pci_wakeup_event(pci_dev);
pm_request_resume(&pci_dev->dev);
return 0;
}
/**
* pci_wakeup_bus - Walk given bus and wake up devices on it
* @bus: Top bus of the subtree to walk.
*/
void pci_wakeup_bus(struct pci_bus *bus)
{
if (bus)
pci_walk_bus(bus, pci_wakeup, NULL);
}
/**
* pci_pme_capable - check the capability of PCI device to generate PME#
@ -1765,7 +1805,7 @@ int pci_wake_from_d3(struct pci_dev *dev, bool enable)
* If the platform can't manage @dev, return the deepest state from which it
* can generate wake events, based on any available PME info.
*/
pci_power_t pci_target_state(struct pci_dev *dev)
static pci_power_t pci_target_state(struct pci_dev *dev)
{
pci_power_t target_state = PCI_D3hot;
@ -2021,18 +2061,24 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev,
}
/**
* pci_add_cap_save_buffer - allocate buffer for saving given capability registers
* _pci_add_cap_save_buffer - allocate buffer for saving given
* capability registers
* @dev: the PCI device
* @cap: the capability to allocate the buffer for
* @extended: Standard or Extended capability ID
* @size: requested size of the buffer
*/
static int pci_add_cap_save_buffer(
struct pci_dev *dev, char cap, unsigned int size)
static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
bool extended, unsigned int size)
{
int pos;
struct pci_cap_saved_state *save_state;
pos = pci_find_capability(dev, cap);
if (extended)
pos = pci_find_ext_capability(dev, cap);
else
pos = pci_find_capability(dev, cap);
if (pos <= 0)
return 0;
@ -2041,12 +2087,23 @@ static int pci_add_cap_save_buffer(
return -ENOMEM;
save_state->cap.cap_nr = cap;
save_state->cap.cap_extended = extended;
save_state->cap.size = size;
pci_add_saved_cap(dev, save_state);
return 0;
}
int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, false, size);
}
int pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size)
{
return _pci_add_cap_save_buffer(dev, cap, true, size);
}
/**
* pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
* @dev: the PCI device
@ -2065,6 +2122,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error)
dev_err(&dev->dev,
"unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
}
void pci_free_cap_save_buffers(struct pci_dev *dev)
@ -2110,242 +2169,6 @@ void pci_configure_ari(struct pci_dev *dev)
}
}
/**
* pci_enable_ido - enable ID-based Ordering on a device
* @dev: the PCI device
* @type: which types of IDO to enable
*
* Enable ID-based ordering on @dev. @type can contain the bits
* %PCI_EXP_IDO_REQUEST and/or %PCI_EXP_IDO_COMPLETION to indicate
* which types of transactions are allowed to be re-ordered.
*/
void pci_enable_ido(struct pci_dev *dev, unsigned long type)
{
u16 ctrl = 0;
if (type & PCI_EXP_IDO_REQUEST)
ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
if (type & PCI_EXP_IDO_COMPLETION)
ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
if (ctrl)
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, ctrl);
}
EXPORT_SYMBOL(pci_enable_ido);
/**
* pci_disable_ido - disable ID-based ordering on a device
* @dev: the PCI device
* @type: which types of IDO to disable
*/
void pci_disable_ido(struct pci_dev *dev, unsigned long type)
{
u16 ctrl = 0;
if (type & PCI_EXP_IDO_REQUEST)
ctrl |= PCI_EXP_DEVCTL2_IDO_REQ_EN;
if (type & PCI_EXP_IDO_COMPLETION)
ctrl |= PCI_EXP_DEVCTL2_IDO_CMP_EN;
if (ctrl)
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2, ctrl);
}
EXPORT_SYMBOL(pci_disable_ido);
/**
* pci_enable_obff - enable optimized buffer flush/fill
* @dev: PCI device
* @type: type of signaling to use
*
* Try to enable @type OBFF signaling on @dev. It will try using WAKE#
* signaling if possible, falling back to message signaling only if
* WAKE# isn't supported. @type should indicate whether the PCIe link
* be brought out of L0s or L1 to send the message. It should be either
* %PCI_EXP_OBFF_SIGNAL_ALWAYS or %PCI_OBFF_SIGNAL_L0.
*
* If your device can benefit from receiving all messages, even at the
* power cost of bringing the link back up from a low power state, use
* %PCI_EXP_OBFF_SIGNAL_ALWAYS. Otherwise, use %PCI_OBFF_SIGNAL_L0 (the
* preferred type).
*
* RETURNS:
* Zero on success, appropriate error number on failure.
*/
int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
{
u32 cap;
u16 ctrl;
int ret;
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_OBFF_MASK))
return -ENOTSUPP; /* no OBFF support at all */
/* Make sure the topology supports OBFF as well */
if (dev->bus->self) {
ret = pci_enable_obff(dev->bus->self, type);
if (ret)
return ret;
}
pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &ctrl);
if (cap & PCI_EXP_DEVCAP2_OBFF_WAKE)
ctrl |= PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
else {
switch (type) {
case PCI_EXP_OBFF_SIGNAL_L0:
if (!(ctrl & PCI_EXP_DEVCTL2_OBFF_WAKE_EN))
ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGA_EN;
break;
case PCI_EXP_OBFF_SIGNAL_ALWAYS:
ctrl &= ~PCI_EXP_DEVCTL2_OBFF_WAKE_EN;
ctrl |= PCI_EXP_DEVCTL2_OBFF_MSGB_EN;
break;
default:
WARN(1, "bad OBFF signal type\n");
return -ENOTSUPP;
}
}
pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, ctrl);
return 0;
}
EXPORT_SYMBOL(pci_enable_obff);
/**
* pci_disable_obff - disable optimized buffer flush/fill
* @dev: PCI device
*
* Disable OBFF on @dev.
*/
void pci_disable_obff(struct pci_dev *dev)
{
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_OBFF_WAKE_EN);
}
EXPORT_SYMBOL(pci_disable_obff);
/**
* pci_ltr_supported - check whether a device supports LTR
* @dev: PCI device
*
* RETURNS:
* True if @dev supports latency tolerance reporting, false otherwise.
*/
static bool pci_ltr_supported(struct pci_dev *dev)
{
u32 cap;
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
return cap & PCI_EXP_DEVCAP2_LTR;
}
/**
* pci_enable_ltr - enable latency tolerance reporting
* @dev: PCI device
*
* Enable LTR on @dev if possible, which means enabling it first on
* upstream ports.
*
* RETURNS:
* Zero on success, errno on failure.
*/
int pci_enable_ltr(struct pci_dev *dev)
{
int ret;
/* Only primary function can enable/disable LTR */
if (PCI_FUNC(dev->devfn) != 0)
return -EINVAL;
if (!pci_ltr_supported(dev))
return -ENOTSUPP;
/* Enable upstream ports first */
if (dev->bus->self) {
ret = pci_enable_ltr(dev->bus->self);
if (ret)
return ret;
}
return pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
}
EXPORT_SYMBOL(pci_enable_ltr);
/**
* pci_disable_ltr - disable latency tolerance reporting
* @dev: PCI device
*/
void pci_disable_ltr(struct pci_dev *dev)
{
/* Only primary function can enable/disable LTR */
if (PCI_FUNC(dev->devfn) != 0)
return;
if (!pci_ltr_supported(dev))
return;
pcie_capability_clear_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
}
EXPORT_SYMBOL(pci_disable_ltr);
static int __pci_ltr_scale(int *val)
{
int scale = 0;
while (*val > 1023) {
*val = (*val + 31) / 32;
scale++;
}
return scale;
}
/**
* pci_set_ltr - set LTR latency values
* @dev: PCI device
* @snoop_lat_ns: snoop latency in nanoseconds
* @nosnoop_lat_ns: nosnoop latency in nanoseconds
*
* Figure out the scale and set the LTR values accordingly.
*/
int pci_set_ltr(struct pci_dev *dev, int snoop_lat_ns, int nosnoop_lat_ns)
{
int pos, ret, snoop_scale, nosnoop_scale;
u16 val;
if (!pci_ltr_supported(dev))
return -ENOTSUPP;
snoop_scale = __pci_ltr_scale(&snoop_lat_ns);
nosnoop_scale = __pci_ltr_scale(&nosnoop_lat_ns);
if (snoop_lat_ns > PCI_LTR_VALUE_MASK ||
nosnoop_lat_ns > PCI_LTR_VALUE_MASK)
return -EINVAL;
if ((snoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT)) ||
(nosnoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT)))
return -EINVAL;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!pos)
return -ENOTSUPP;
val = (snoop_scale << PCI_LTR_SCALE_SHIFT) | snoop_lat_ns;
ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_SNOOP_LAT, val);
if (ret != 4)
return -EIO;
val = (nosnoop_scale << PCI_LTR_SCALE_SHIFT) | nosnoop_lat_ns;
ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_NOSNOOP_LAT, val);
if (ret != 4)
return -EIO;
return 0;
}
EXPORT_SYMBOL(pci_set_ltr);
static int pci_acs_enable;
/**
@ -3138,7 +2961,7 @@ bool pci_check_and_mask_intx(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
/**
* pci_check_and_mask_intx - unmask INTx of no interrupt is pending
* pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, unmask it if not
@ -3204,20 +3027,10 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary);
*/
int pci_wait_for_pending_transaction(struct pci_dev *dev)
{
int i;
u16 status;
if (!pci_is_pcie(dev))
return 1;
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
if (!(status & PCI_EXP_DEVSTA_TRPND))
return 1;
}
return 0;
return pci_wait_for_pending(dev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_TRPND);
}
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
@ -3244,10 +3057,8 @@ static int pcie_flr(struct pci_dev *dev, int probe)
static int pci_af_flr(struct pci_dev *dev, int probe)
{
int i;
int pos;
u8 cap;
u8 status;
pos = pci_find_capability(dev, PCI_CAP_ID_AF);
if (!pos)
@ -3261,14 +3072,8 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
return 0;
/* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) {
if (i)
msleep((1 << (i - 1)) * 100);
pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status);
if (!(status & PCI_AF_STATUS_TP))
goto clear;
}
if (pci_wait_for_pending(dev, PCI_AF_STATUS, PCI_AF_STATUS_TP))
goto clear;
dev_err(&dev->dev, "transaction is not cleared; "
"proceeding with reset anyway\n");
@ -3445,6 +3250,18 @@ static void pci_dev_lock(struct pci_dev *dev)
device_lock(&dev->dev);
}
/* Return 1 on successful lock, 0 on contention */
static int pci_dev_trylock(struct pci_dev *dev)
{
if (pci_cfg_access_trylock(dev)) {
if (device_trylock(&dev->dev))
return 1;
pci_cfg_access_unlock(dev);
}
return 0;
}
static void pci_dev_unlock(struct pci_dev *dev)
{
device_unlock(&dev->dev);
@ -3588,6 +3405,34 @@ int pci_reset_function(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_reset_function);
/**
* pci_try_reset_function - quiesce and reset a PCI device function
* @dev: PCI device to reset
*
* Same as above, except return -EAGAIN if unable to lock device.
*/
int pci_try_reset_function(struct pci_dev *dev)
{
int rc;
rc = pci_dev_reset(dev, 1);
if (rc)
return rc;
pci_dev_save_and_disable(dev);
if (pci_dev_trylock(dev)) {
rc = __pci_dev_reset(dev, 0);
pci_dev_unlock(dev);
} else
rc = -EAGAIN;
pci_dev_restore(dev);
return rc;
}
EXPORT_SYMBOL_GPL(pci_try_reset_function);
/* Lock devices from the top of the tree down */
static void pci_bus_lock(struct pci_bus *bus)
{
@ -3612,6 +3457,32 @@ static void pci_bus_unlock(struct pci_bus *bus)
}
}
/* Return 1 on successful lock, 0 on contention */
static int pci_bus_trylock(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
if (!pci_dev_trylock(dev))
goto unlock;
if (dev->subordinate) {
if (!pci_bus_trylock(dev->subordinate)) {
pci_dev_unlock(dev);
goto unlock;
}
}
}
return 1;
unlock:
list_for_each_entry_continue_reverse(dev, &bus->devices, bus_list) {
if (dev->subordinate)
pci_bus_unlock(dev->subordinate);
pci_dev_unlock(dev);
}
return 0;
}
/* Lock devices from the top of the tree down */
static void pci_slot_lock(struct pci_slot *slot)
{
@ -3640,6 +3511,37 @@ static void pci_slot_unlock(struct pci_slot *slot)
}
}
/* Return 1 on successful lock, 0 on contention */
static int pci_slot_trylock(struct pci_slot *slot)
{
struct pci_dev *dev;
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
continue;
if (!pci_dev_trylock(dev))
goto unlock;
if (dev->subordinate) {
if (!pci_bus_trylock(dev->subordinate)) {
pci_dev_unlock(dev);
goto unlock;
}
}
}
return 1;
unlock:
list_for_each_entry_continue_reverse(dev,
&slot->bus->devices, bus_list) {
if (!dev->slot || dev->slot != slot)
continue;
if (dev->subordinate)
pci_bus_unlock(dev->subordinate);
pci_dev_unlock(dev);
}
return 0;
}
/* Save and disable devices from the top of the tree down */
static void pci_bus_save_and_disable(struct pci_bus *bus)
{
@ -3763,6 +3665,35 @@ int pci_reset_slot(struct pci_slot *slot)
}
EXPORT_SYMBOL_GPL(pci_reset_slot);
/**
* pci_try_reset_slot - Try to reset a PCI slot
* @slot: PCI slot to reset
*
* Same as above except return -EAGAIN if the slot cannot be locked
*/
int pci_try_reset_slot(struct pci_slot *slot)
{
int rc;
rc = pci_slot_reset(slot, 1);
if (rc)
return rc;
pci_slot_save_and_disable(slot);
if (pci_slot_trylock(slot)) {
might_sleep();
rc = pci_reset_hotplug_slot(slot->hotplug, 0);
pci_slot_unlock(slot);
} else
rc = -EAGAIN;
pci_slot_restore(slot);
return rc;
}
EXPORT_SYMBOL_GPL(pci_try_reset_slot);
static int pci_bus_reset(struct pci_bus *bus, int probe)
{
if (!bus->self)
@ -3821,6 +3752,35 @@ int pci_reset_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_reset_bus);
/**
* pci_try_reset_bus - Try to reset a PCI bus
* @bus: top level PCI bus to reset
*
* Same as above except return -EAGAIN if the bus cannot be locked
*/
int pci_try_reset_bus(struct pci_bus *bus)
{
int rc;
rc = pci_bus_reset(bus, 1);
if (rc)
return rc;
pci_bus_save_and_disable(bus);
if (pci_bus_trylock(bus)) {
might_sleep();
pci_reset_bridge_secondary_bus(bus->self);
pci_bus_unlock(bus);
} else
rc = -EAGAIN;
pci_bus_restore(bus);
return rc;
}
EXPORT_SYMBOL_GPL(pci_try_reset_bus);
/**
* pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
* @dev: PCI device to query
@ -4450,7 +4410,6 @@ EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_pme_capable);
EXPORT_SYMBOL(pci_pme_active);
EXPORT_SYMBOL(pci_wake_from_d3);
EXPORT_SYMBOL(pci_target_state);
EXPORT_SYMBOL(pci_prepare_to_sleep);
EXPORT_SYMBOL(pci_back_from_sleep);
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);