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

@ -70,18 +70,15 @@ Date: September, 2011
Contact: Neil Horman <nhorman@tuxdriver.com> Contact: Neil Horman <nhorman@tuxdriver.com>
Description: Description:
The /sys/devices/.../msi_irqs directory contains a variable set The /sys/devices/.../msi_irqs directory contains a variable set
of sub-directories, with each sub-directory being named after a of files, with each file being named after a corresponding msi
corresponding msi irq vector allocated to that device. Each irq vector allocated to that device.
numbered sub-directory N contains attributes of that irq.
Note that this directory is not created for device drivers which
do not support msi irqs
What: /sys/bus/pci/devices/.../msi_irqs/<N>/mode What: /sys/bus/pci/devices/.../msi_irqs/<N>
Date: September 2011 Date: September 2011
Contact: Neil Horman <nhorman@tuxdriver.com> Contact: Neil Horman <nhorman@tuxdriver.com>
Description: Description:
This attribute indicates the mode that the irq vector named by This attribute indicates the mode that the irq vector named by
the parent directory is in (msi vs. msix) the file is in (msi vs. msix)
What: /sys/bus/pci/devices/.../remove What: /sys/bus/pci/devices/.../remove
Date: January 2009 Date: January 2009

View file

@ -2,12 +2,12 @@
- this file - this file
MSI-HOWTO.txt MSI-HOWTO.txt
- the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ. - the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ.
PCI-DMA-mapping.txt
- info for PCI drivers using DMA portably across all platforms
PCIEBUS-HOWTO.txt PCIEBUS-HOWTO.txt
- a guide describing the PCI Express Port Bus driver - a guide describing the PCI Express Port Bus driver
pci-error-recovery.txt pci-error-recovery.txt
- info on PCI error recovery - info on PCI error recovery
pci-iov-howto.txt
- the PCI Express I/O Virtualization HOWTO
pci.txt pci.txt
- info on the PCI subsystem for device driver authors - info on the PCI subsystem for device driver authors
pcieaer-howto.txt pcieaer-howto.txt

View file

@ -82,93 +82,111 @@ Most of the hard work is done for the driver in the PCI layer. It simply
has to request that the PCI layer set up the MSI capability for this has to request that the PCI layer set up the MSI capability for this
device. device.
4.2.1 pci_enable_msi 4.2.1 pci_enable_msi_range
int pci_enable_msi(struct pci_dev *dev) int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
A successful call allocates ONE interrupt to the device, regardless This function allows a device driver to request any number of MSI
of how many MSIs the device supports. The device is switched from interrupts within specified range from 'minvec' to 'maxvec'.
pin-based interrupt mode to MSI mode. The dev->irq number is changed
to a new number which represents the message signaled interrupt;
consequently, this function should be called before the driver calls
request_irq(), because an MSI is delivered via a vector that is
different from the vector of a pin-based interrupt.
4.2.2 pci_enable_msi_block If this function returns a positive number it indicates the number of
MSI interrupts that have been successfully allocated. In this case
int pci_enable_msi_block(struct pci_dev *dev, int count) the device is switched from pin-based interrupt mode to MSI mode and
updates dev->irq to be the lowest of the new interrupts assigned to it.
This variation on the above call allows a device driver to request multiple The other interrupts assigned to the device are in the range dev->irq
MSIs. The MSI specification only allows interrupts to be allocated in to dev->irq + returned value - 1. Device driver can use the returned
powers of two, up to a maximum of 2^5 (32). number of successfully allocated MSI interrupts to further allocate
and initialize device resources.
If this function returns 0, it has succeeded in allocating at least as many
interrupts as the driver requested (it may have allocated more in order
to satisfy the power-of-two requirement). In this case, the function
enables MSI on this device and updates dev->irq to be the lowest of
the new interrupts assigned to it. The other interrupts assigned to
the device are in the range dev->irq to dev->irq + count - 1.
If this function returns a negative number, it indicates an error and
the driver should not attempt to request any more MSI interrupts for
this device. If this function returns a positive number, it is
less than 'count' and indicates the number of interrupts that could have
been allocated. In neither case is the irq value updated or the device
switched into MSI mode.
The device driver must decide what action to take if
pci_enable_msi_block() returns a value less than the number requested.
For instance, the driver could still make use of fewer interrupts;
in this case the driver should call pci_enable_msi_block()
again. Note that it is not guaranteed to succeed, even when the
'count' has been reduced to the value returned from a previous call to
pci_enable_msi_block(). This is because there are multiple constraints
on the number of vectors that can be allocated; pci_enable_msi_block()
returns as soon as it finds any constraint that doesn't allow the
call to succeed.
4.2.3 pci_enable_msi_block_auto
int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count)
This variation on pci_enable_msi() call allows a device driver to request
the maximum possible number of MSIs. The MSI specification only allows
interrupts to be allocated in powers of two, up to a maximum of 2^5 (32).
If this function returns a positive number, it indicates that it has
succeeded and the returned value is the number of allocated interrupts. In
this case, the function enables MSI on this device and updates dev->irq to
be the lowest of the new interrupts assigned to it. The other interrupts
assigned to the device are in the range dev->irq to dev->irq + returned
value - 1.
If this function returns a negative number, it indicates an error and If this function returns a negative number, it indicates an error and
the driver should not attempt to request any more MSI interrupts for the driver should not attempt to request any more MSI interrupts for
this device. this device.
If the device driver needs to know the number of interrupts the device This function should be called before the driver calls request_irq(),
supports it can pass the pointer count where that number is stored. The because MSI interrupts are delivered via vectors that are different
device driver must decide what action to take if pci_enable_msi_block_auto() from the vector of a pin-based interrupt.
succeeds, but returns a value less than the number of interrupts supported.
If the device driver does not need to know the number of interrupts
supported, it can set the pointer count to NULL.
4.2.4 pci_disable_msi It is ideal if drivers can cope with a variable number of MSI interrupts;
there are many reasons why the platform may not be able to provide the
exact number that a driver asks for.
There could be devices that can not operate with just any number of MSI
interrupts within a range. See chapter 4.3.1.3 to get the idea how to
handle such devices for MSI-X - the same logic applies to MSI.
4.2.1.1 Maximum possible number of MSI interrupts
The typical usage of MSI interrupts is to allocate as many vectors as
possible, likely up to the limit returned by pci_msi_vec_count() function:
static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
{
return pci_enable_msi_range(pdev, 1, nvec);
}
Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
the value of 0 would be meaningless and could result in error.
Some devices have a minimal limit on number of MSI interrupts.
In this case the function could look like this:
static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
{
return pci_enable_msi_range(pdev, FOO_DRIVER_MINIMUM_NVEC, nvec);
}
4.2.1.2 Exact number of MSI interrupts
If a driver is unable or unwilling to deal with a variable number of MSI
interrupts it could request a particular number of interrupts by passing
that number to pci_enable_msi_range() function as both 'minvec' and 'maxvec'
parameters:
static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
{
return pci_enable_msi_range(pdev, nvec, nvec);
}
4.2.1.3 Single MSI mode
The most notorious example of the request type described above is
enabling the single MSI mode for a device. It could be done by passing
two 1s as 'minvec' and 'maxvec':
static int foo_driver_enable_single_msi(struct pci_dev *pdev)
{
return pci_enable_msi_range(pdev, 1, 1);
}
4.2.2 pci_disable_msi
void pci_disable_msi(struct pci_dev *dev) void pci_disable_msi(struct pci_dev *dev)
This function should be used to undo the effect of pci_enable_msi() or This function should be used to undo the effect of pci_enable_msi_range().
pci_enable_msi_block() or pci_enable_msi_block_auto(). Calling it restores Calling it restores dev->irq to the pin-based interrupt number and frees
dev->irq to the pin-based interrupt number and frees the previously the previously allocated MSIs. The interrupts may subsequently be assigned
allocated message signaled interrupt(s). The interrupt may subsequently be to another device, so drivers should not cache the value of dev->irq.
assigned to another device, so drivers should not cache the value of
dev->irq.
Before calling this function, a device driver must always call free_irq() Before calling this function, a device driver must always call free_irq()
on any interrupt for which it previously called request_irq(). on any interrupt for which it previously called request_irq().
Failure to do so results in a BUG_ON(), leaving the device with Failure to do so results in a BUG_ON(), leaving the device with
MSI enabled and thus leaking its vector. MSI enabled and thus leaking its vector.
4.2.3 pci_msi_vec_count
int pci_msi_vec_count(struct pci_dev *dev)
This function could be used to retrieve the number of MSI vectors the
device requested (via the Multiple Message Capable register). The MSI
specification only allows the returned value to be a power of two,
up to a maximum of 2^5 (32).
If this function returns a negative number, it indicates the device is
not capable of sending MSIs.
If this function returns a positive number, it indicates the maximum
number of MSI interrupt vectors that could be allocated.
4.3 Using MSI-X 4.3 Using MSI-X
The MSI-X capability is much more flexible than the MSI capability. The MSI-X capability is much more flexible than the MSI capability.
@ -188,26 +206,31 @@ in each element of the array to indicate for which entries the kernel
should assign interrupts; it is invalid to fill in two entries with the should assign interrupts; it is invalid to fill in two entries with the
same number. same number.
4.3.1 pci_enable_msix 4.3.1 pci_enable_msix_range
int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec)
Calling this function asks the PCI subsystem to allocate 'nvec' MSIs. Calling this function asks the PCI subsystem to allocate any number of
MSI-X interrupts within specified range from 'minvec' to 'maxvec'.
The 'entries' argument is a pointer to an array of msix_entry structs The 'entries' argument is a pointer to an array of msix_entry structs
which should be at least 'nvec' entries in size. On success, the which should be at least 'maxvec' entries in size.
device is switched into MSI-X mode and the function returns 0.
The 'vector' member in each entry is populated with the interrupt number; On success, the device is switched into MSI-X mode and the function
returns the number of MSI-X interrupts that have been successfully
allocated. In this case the 'vector' member in entries numbered from
0 to the returned value - 1 is populated with the interrupt number;
the driver should then call request_irq() for each 'vector' that it the driver should then call request_irq() for each 'vector' that it
decides to use. The device driver is responsible for keeping track of the decides to use. The device driver is responsible for keeping track of the
interrupts assigned to the MSI-X vectors so it can free them again later. interrupts assigned to the MSI-X vectors so it can free them again later.
Device driver can use the returned number of successfully allocated MSI-X
interrupts to further allocate and initialize device resources.
If this function returns a negative number, it indicates an error and If this function returns a negative number, it indicates an error and
the driver should not attempt to allocate any more MSI-X interrupts for the driver should not attempt to allocate any more MSI-X interrupts for
this device. If it returns a positive number, it indicates the maximum this device.
number of interrupt vectors that could have been allocated. See example
below.
This function, in contrast with pci_enable_msi(), does not adjust This function, in contrast with pci_enable_msi_range(), does not adjust
dev->irq. The device will not generate interrupts for this interrupt dev->irq. The device will not generate interrupts for this interrupt
number once MSI-X is enabled. number once MSI-X is enabled.
@ -218,28 +241,103 @@ It is ideal if drivers can cope with a variable number of MSI-X interrupts;
there are many reasons why the platform may not be able to provide the there are many reasons why the platform may not be able to provide the
exact number that a driver asks for. exact number that a driver asks for.
A request loop to achieve that might look like: There could be devices that can not operate with just any number of MSI-X
interrupts within a range. E.g., an network adapter might need let's say
four vectors per each queue it provides. Therefore, a number of MSI-X
interrupts allocated should be a multiple of four. In this case interface
pci_enable_msix_range() can not be used alone to request MSI-X interrupts
(since it can allocate any number within the range, without any notion of
the multiple of four) and the device driver should master a custom logic
to request the required number of MSI-X interrupts.
4.3.1.1 Maximum possible number of MSI-X interrupts
The typical usage of MSI-X interrupts is to allocate as many vectors as
possible, likely up to the limit returned by pci_msix_vec_count() function:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{ {
while (nvec >= FOO_DRIVER_MINIMUM_NVEC) { return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
rc = pci_enable_msix(adapter->pdev, 1, nvec);
adapter->msix_entries, nvec); }
if (rc > 0)
nvec = rc; Note the value of 'minvec' parameter is 1. As 'minvec' is inclusive,
else the value of 0 would be meaningless and could result in error.
return rc;
Some devices have a minimal limit on number of MSI-X interrupts.
In this case the function could look like this:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
FOO_DRIVER_MINIMUM_NVEC, nvec);
}
4.3.1.2 Exact number of MSI-X interrupts
If a driver is unable or unwilling to deal with a variable number of MSI-X
interrupts it could request a particular number of interrupts by passing
that number to pci_enable_msix_range() function as both 'minvec' and 'maxvec'
parameters:
static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
{
return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
nvec, nvec);
}
4.3.1.3 Specific requirements to the number of MSI-X interrupts
As noted above, there could be devices that can not operate with just any
number of MSI-X interrupts within a range. E.g., let's assume a device that
is only capable sending the number of MSI-X interrupts which is a power of
two. A routine that enables MSI-X mode for such device might look like this:
/*
* Assume 'minvec' and 'maxvec' are non-zero
*/
static int foo_driver_enable_msix(struct foo_adapter *adapter,
int minvec, int maxvec)
{
int rc;
minvec = roundup_pow_of_two(minvec);
maxvec = rounddown_pow_of_two(maxvec);
if (minvec > maxvec)
return -ERANGE;
retry:
rc = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
maxvec, maxvec);
/*
* -ENOSPC is the only error code allowed to be analized
*/
if (rc == -ENOSPC) {
if (maxvec == 1)
return -ENOSPC;
maxvec /= 2;
if (minvec > maxvec)
return -ENOSPC;
goto retry;
} }
return -ENOSPC; return rc;
} }
Note how pci_enable_msix_range() return value is analized for a fallback -
any error code other than -ENOSPC indicates a fatal error and should not
be retried.
4.3.2 pci_disable_msix 4.3.2 pci_disable_msix
void pci_disable_msix(struct pci_dev *dev) void pci_disable_msix(struct pci_dev *dev)
This function should be used to undo the effect of pci_enable_msix(). It frees This function should be used to undo the effect of pci_enable_msix_range().
the previously allocated message signaled interrupts. The interrupts may It frees the previously allocated MSI-X interrupts. The interrupts may
subsequently be assigned to another device, so drivers should not cache subsequently be assigned to another device, so drivers should not cache
the value of the 'vector' elements over a call to pci_disable_msix(). the value of the 'vector' elements over a call to pci_disable_msix().
@ -255,18 +353,32 @@ MSI-X Table. This address is mapped by the PCI subsystem, and should not
be accessed directly by the device driver. If the driver wishes to be accessed directly by the device driver. If the driver wishes to
mask or unmask an interrupt, it should call disable_irq() / enable_irq(). mask or unmask an interrupt, it should call disable_irq() / enable_irq().
4.3.4 pci_msix_vec_count
int pci_msix_vec_count(struct pci_dev *dev)
This function could be used to retrieve number of entries in the device
MSI-X table.
If this function returns a negative number, it indicates the device is
not capable of sending MSI-Xs.
If this function returns a positive number, it indicates the maximum
number of MSI-X interrupt vectors that could be allocated.
4.4 Handling devices implementing both MSI and MSI-X capabilities 4.4 Handling devices implementing both MSI and MSI-X capabilities
If a device implements both MSI and MSI-X capabilities, it can If a device implements both MSI and MSI-X capabilities, it can
run in either MSI mode or MSI-X mode, but not both simultaneously. run in either MSI mode or MSI-X mode, but not both simultaneously.
This is a requirement of the PCI spec, and it is enforced by the This is a requirement of the PCI spec, and it is enforced by the
PCI layer. Calling pci_enable_msi() when MSI-X is already enabled or PCI layer. Calling pci_enable_msi_range() when MSI-X is already
pci_enable_msix() when MSI is already enabled results in an error. enabled or pci_enable_msix_range() when MSI is already enabled
If a device driver wishes to switch between MSI and MSI-X at runtime, results in an error. If a device driver wishes to switch between MSI
it must first quiesce the device, then switch it back to pin-interrupt and MSI-X at runtime, it must first quiesce the device, then switch
mode, before calling pci_enable_msi() or pci_enable_msix() and resuming it back to pin-interrupt mode, before calling pci_enable_msi_range()
operation. This is not expected to be a common operation but may be or pci_enable_msix_range() and resuming operation. This is not expected
useful for debugging or testing during development. to be a common operation but may be useful for debugging or testing
during development.
4.5 Considerations when using MSIs 4.5 Considerations when using MSIs
@ -381,5 +493,5 @@ or disabled (0). If 0 is found in any of the msi_bus files belonging
to bridges between the PCI root and the device, MSIs are disabled. to bridges between the PCI root and the device, MSIs are disabled.
It is also worth checking the device driver to see whether it supports MSIs. It is also worth checking the device driver to see whether it supports MSIs.
For example, it may contain calls to pci_enable_msi(), pci_enable_msix() or For example, it may contain calls to pci_enable_msi_range() or
pci_enable_msi_block(). pci_enable_msix_range().

View file

@ -123,8 +123,10 @@ initialization with a pointer to a structure describing the driver
The ID table is an array of struct pci_device_id entries ending with an The ID table is an array of struct pci_device_id entries ending with an
all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred all-zero entry. Definitions with static const are generally preferred.
method of declaring the table. Each entry consists of: Use of the deprecated macro DEFINE_PCI_DEVICE_TABLE should be avoided.
Each entry consists of:
vendor,device Vendor and device ID to match (or PCI_ANY_ID) vendor,device Vendor and device ID to match (or PCI_ANY_ID)

View file

@ -19,6 +19,8 @@ Required properties:
to define the mapping of the PCIe interface to interrupt to define the mapping of the PCIe interface to interrupt
numbers. numbers.
- num-lanes: number of lanes to use - num-lanes: number of lanes to use
Optional properties:
- reset-gpio: gpio pin number of power good signal - reset-gpio: gpio pin number of power good signal
Optional properties for fsl,imx6q-pcie Optional properties for fsl,imx6q-pcie

View file

@ -83,7 +83,7 @@ static int pci_mmap_resource(struct kobject *kobj,
if (iomem_is_exclusive(res->start)) if (iomem_is_exclusive(res->start))
return -EINVAL; return -EINVAL;
pcibios_resource_to_bus(pdev, &bar, res); pcibios_resource_to_bus(pdev->bus, &bar, res);
vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0)); vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
@ -139,7 +139,7 @@ static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
long dense_offset; long dense_offset;
unsigned long sparse_size; unsigned long sparse_size;
pcibios_resource_to_bus(pdev, &bar, &pdev->resource[num]); pcibios_resource_to_bus(pdev->bus, &bar, &pdev->resource[num]);
/* All core logic chips have 4G sparse address space, except /* All core logic chips have 4G sparse address space, except
CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM

View file

@ -325,7 +325,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
/* Helper for generic DMA-mapping functions. */ /* Helper for generic DMA-mapping functions. */
static struct pci_dev *alpha_gendev_to_pci(struct device *dev) static struct pci_dev *alpha_gendev_to_pci(struct device *dev)
{ {
if (dev && dev->bus == &pci_bus_type) if (dev && dev_is_pci(dev))
return to_pci_dev(dev); return to_pci_dev(dev);
/* Assume that non-PCI devices asking for DMA are either ISA or EISA, /* Assume that non-PCI devices asking for DMA are either ISA or EISA,

View file

@ -257,7 +257,7 @@ static int it8152_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t s
*/ */
static int it8152_pci_platform_notify(struct device *dev) static int it8152_pci_platform_notify(struct device *dev)
{ {
if (dev->bus == &pci_bus_type) { if (dev_is_pci(dev)) {
if (dev->dma_mask) if (dev->dma_mask)
*dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET;
@ -268,7 +268,7 @@ static int it8152_pci_platform_notify(struct device *dev)
static int it8152_pci_platform_notify_remove(struct device *dev) static int it8152_pci_platform_notify_remove(struct device *dev)
{ {
if (dev->bus == &pci_bus_type) if (dev_is_pci(dev))
dmabounce_unregister_dev(dev); dmabounce_unregister_dev(dev);
return 0; return 0;

View file

@ -326,7 +326,7 @@ static int ixp4xx_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t s
*/ */
static int ixp4xx_pci_platform_notify(struct device *dev) static int ixp4xx_pci_platform_notify(struct device *dev)
{ {
if(dev->bus == &pci_bus_type) { if (dev_is_pci(dev)) {
*dev->dma_mask = SZ_64M - 1; *dev->dma_mask = SZ_64M - 1;
dev->coherent_dma_mask = SZ_64M - 1; dev->coherent_dma_mask = SZ_64M - 1;
dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce); dmabounce_register_dev(dev, 2048, 4096, ixp4xx_needs_bounce);
@ -336,9 +336,9 @@ static int ixp4xx_pci_platform_notify(struct device *dev)
static int ixp4xx_pci_platform_notify_remove(struct device *dev) static int ixp4xx_pci_platform_notify_remove(struct device *dev)
{ {
if(dev->bus == &pci_bus_type) { if (dev_is_pci(dev))
dmabounce_unregister_dev(dev); dmabounce_unregister_dev(dev);
}
return 0; return 0;
} }

View file

@ -255,7 +255,7 @@ static u64 prefetch_spill_page;
#endif #endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
# define GET_IOC(dev) (((dev)->bus == &pci_bus_type) \ # define GET_IOC(dev) ((dev_is_pci(dev)) \
? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL) ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL)
#else #else
# define GET_IOC(dev) NULL # define GET_IOC(dev) NULL

View file

@ -34,7 +34,7 @@
*/ */
static int sn_dma_supported(struct device *dev, u64 mask) static int sn_dma_supported(struct device *dev, u64 mask)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
if (mask < 0x7fffffff) if (mask < 0x7fffffff)
return 0; return 0;
@ -50,7 +50,7 @@ static int sn_dma_supported(struct device *dev, u64 mask)
*/ */
int sn_dma_set_mask(struct device *dev, u64 dma_mask) int sn_dma_set_mask(struct device *dev, u64 dma_mask)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
if (!sn_dma_supported(dev, dma_mask)) if (!sn_dma_supported(dev, dma_mask))
return 0; return 0;
@ -85,7 +85,7 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
/* /*
* Allocate the memory. * Allocate the memory.
@ -143,7 +143,7 @@ static void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
provider->dma_unmap(pdev, dma_handle, 0); provider->dma_unmap(pdev, dma_handle, 0);
free_pages((unsigned long)cpu_addr, get_order(size)); free_pages((unsigned long)cpu_addr, get_order(size));
@ -187,7 +187,7 @@ static dma_addr_t sn_dma_map_page(struct device *dev, struct page *page,
dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs); dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
phys_addr = __pa(cpu_addr); phys_addr = __pa(cpu_addr);
if (dmabarr) if (dmabarr)
@ -223,7 +223,7 @@ static void sn_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
provider->dma_unmap(pdev, dma_addr, dir); provider->dma_unmap(pdev, dma_addr, dir);
} }
@ -247,7 +247,7 @@ static void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
struct scatterlist *sg; struct scatterlist *sg;
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
for_each_sg(sgl, sg, nhwentries, i) { for_each_sg(sgl, sg, nhwentries, i) {
provider->dma_unmap(pdev, sg->dma_address, dir); provider->dma_unmap(pdev, sg->dma_address, dir);
@ -284,7 +284,7 @@ static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs); dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
/* /*
* Setup a DMA address for each entry in the scatterlist. * Setup a DMA address for each entry in the scatterlist.
@ -323,26 +323,26 @@ static int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl,
static void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, static void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir) size_t size, enum dma_data_direction dir)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
} }
static void sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, static void sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
size_t size, size_t size,
enum dma_data_direction dir) enum dma_data_direction dir)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
} }
static void sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, static void sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir) int nelems, enum dma_data_direction dir)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
} }
static void sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, static void sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir) int nelems, enum dma_data_direction dir)
{ {
BUG_ON(dev->bus != &pci_bus_type); BUG_ON(!dev_is_pci(dev));
} }
static int sn_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) static int sn_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)

View file

@ -282,18 +282,6 @@ find_pa_parent_type(const struct parisc_device *padev, int type)
return NULL; return NULL;
} }
#ifdef CONFIG_PCI
static inline int is_pci_dev(struct device *dev)
{
return dev->bus == &pci_bus_type;
}
#else
static inline int is_pci_dev(struct device *dev)
{
return 0;
}
#endif
/* /*
* get_node_path fills in @path with the firmware path to the device. * get_node_path fills in @path with the firmware path to the device.
* Note that if @node is a parisc device, we don't fill in the 'mod' field. * Note that if @node is a parisc device, we don't fill in the 'mod' field.
@ -306,7 +294,7 @@ static void get_node_path(struct device *dev, struct hardware_path *path)
int i = 5; int i = 5;
memset(&path->bc, -1, 6); memset(&path->bc, -1, 6);
if (is_pci_dev(dev)) { if (dev_is_pci(dev)) {
unsigned int devfn = to_pci_dev(dev)->devfn; unsigned int devfn = to_pci_dev(dev)->devfn;
path->mod = PCI_FUNC(devfn); path->mod = PCI_FUNC(devfn);
path->bc[i--] = PCI_SLOT(devfn); path->bc[i--] = PCI_SLOT(devfn);
@ -314,7 +302,7 @@ static void get_node_path(struct device *dev, struct hardware_path *path)
} }
while (dev != &root) { while (dev != &root) {
if (is_pci_dev(dev)) { if (dev_is_pci(dev)) {
unsigned int devfn = to_pci_dev(dev)->devfn; unsigned int devfn = to_pci_dev(dev)->devfn;
path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5); path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5);
} else if (dev->bus == &parisc_bus_type) { } else if (dev->bus == &parisc_bus_type) {
@ -695,7 +683,7 @@ static int check_parent(struct device * dev, void * data)
if (dev->bus == &parisc_bus_type) { if (dev->bus == &parisc_bus_type) {
if (match_parisc_device(dev, d->index, d->modpath)) if (match_parisc_device(dev, d->index, d->modpath))
d->dev = dev; d->dev = dev;
} else if (is_pci_dev(dev)) { } else if (dev_is_pci(dev)) {
if (match_pci_device(dev, d->index, d->modpath)) if (match_pci_device(dev, d->index, d->modpath))
d->dev = dev; d->dev = dev;
} else if (dev->bus == NULL) { } else if (dev->bus == NULL) {
@ -753,7 +741,7 @@ struct device *hwpath_to_device(struct hardware_path *modpath)
if (!parent) if (!parent)
return NULL; return NULL;
} }
if (is_pci_dev(parent)) /* pci devices already parse MOD */ if (dev_is_pci(parent)) /* pci devices already parse MOD */
return parent; return parent;
else else
return parse_tree_node(parent, 6, modpath); return parse_tree_node(parent, 6, modpath);
@ -772,7 +760,7 @@ void device_to_hwpath(struct device *dev, struct hardware_path *path)
padev = to_parisc_device(dev); padev = to_parisc_device(dev);
get_node_path(dev->parent, path); get_node_path(dev->parent, path);
path->mod = padev->hw_path; path->mod = padev->hw_path;
} else if (is_pci_dev(dev)) { } else if (dev_is_pci(dev)) {
get_node_path(dev, path); get_node_path(dev, path);
} }
} }

View file

@ -369,7 +369,9 @@ static void *eeh_rmv_device(void *data, void *userdata)
edev->mode |= EEH_DEV_DISCONNECTED; edev->mode |= EEH_DEV_DISCONNECTED;
(*removed)++; (*removed)++;
pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_unlock_rescan_remove();
return NULL; return NULL;
} }
@ -416,10 +418,13 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
* into pcibios_add_pci_devices(). * into pcibios_add_pci_devices().
*/ */
eeh_pe_state_mark(pe, EEH_PE_KEEP); eeh_pe_state_mark(pe, EEH_PE_KEEP);
if (bus) if (bus) {
pci_lock_rescan_remove();
pcibios_remove_pci_devices(bus); pcibios_remove_pci_devices(bus);
else if (frozen_bus) pci_unlock_rescan_remove();
} else if (frozen_bus) {
eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed); eeh_pe_dev_traverse(pe, eeh_rmv_device, &removed);
}
/* Reset the pci controller. (Asserts RST#; resets config space). /* Reset the pci controller. (Asserts RST#; resets config space).
* Reconfigure bridges and devices. Don't try to bring the system * Reconfigure bridges and devices. Don't try to bring the system
@ -429,6 +434,8 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
if (rc) if (rc)
return rc; return rc;
pci_lock_rescan_remove();
/* Restore PE */ /* Restore PE */
eeh_ops->configure_bridge(pe); eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe); eeh_pe_restore_bars(pe);
@ -462,6 +469,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
pe->tstamp = tstamp; pe->tstamp = tstamp;
pe->freeze_count = cnt; pe->freeze_count = cnt;
pci_unlock_rescan_remove();
return 0; return 0;
} }
@ -618,8 +626,11 @@ perm_error:
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
/* Shut down the device drivers for good. */ /* Shut down the device drivers for good. */
if (frozen_bus) if (frozen_bus) {
pci_lock_rescan_remove();
pcibios_remove_pci_devices(frozen_bus); pcibios_remove_pci_devices(frozen_bus);
pci_unlock_rescan_remove();
}
} }
static void eeh_handle_special_event(void) static void eeh_handle_special_event(void)
@ -692,6 +703,7 @@ static void eeh_handle_special_event(void)
if (rc == 2 || rc == 1) if (rc == 2 || rc == 1)
eeh_handle_normal_event(pe); eeh_handle_normal_event(pe);
else { else {
pci_lock_rescan_remove();
list_for_each_entry_safe(hose, tmp, list_for_each_entry_safe(hose, tmp,
&hose_list, list_node) { &hose_list, list_node) {
phb_pe = eeh_phb_pe_get(hose); phb_pe = eeh_phb_pe_get(hose);
@ -703,6 +715,7 @@ static void eeh_handle_special_event(void)
eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
pcibios_remove_pci_devices(bus); pcibios_remove_pci_devices(bus);
} }
pci_unlock_rescan_remove();
} }
} }

View file

@ -835,7 +835,7 @@ static void pcibios_fixup_resources(struct pci_dev *dev)
* at 0 as unset as well, except if PCI_PROBE_ONLY is also set * at 0 as unset as well, except if PCI_PROBE_ONLY is also set
* since in that case, we don't want to re-assign anything * since in that case, we don't want to re-assign anything
*/ */
pcibios_resource_to_bus(dev, &reg, res); pcibios_resource_to_bus(dev->bus, &reg, res);
if (pci_has_flag(PCI_REASSIGN_ALL_RSRC) || if (pci_has_flag(PCI_REASSIGN_ALL_RSRC) ||
(reg.start == 0 && !pci_has_flag(PCI_PROBE_ONLY))) { (reg.start == 0 && !pci_has_flag(PCI_PROBE_ONLY))) {
/* Only print message if not re-assigning */ /* Only print message if not re-assigning */
@ -886,7 +886,7 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
/* Job is a bit different between memory and IO */ /* Job is a bit different between memory and IO */
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
pcibios_resource_to_bus(dev, &region, res); pcibios_resource_to_bus(dev->bus, &region, res);
/* If the BAR is non-0 then it's probably been initialized */ /* If the BAR is non-0 then it's probably been initialized */
if (region.start != 0) if (region.start != 0)

View file

@ -111,7 +111,7 @@ static void of_pci_parse_addrs(struct device_node *node, struct pci_dev *dev)
res->name = pci_name(dev); res->name = pci_name(dev);
region.start = base; region.start = base;
region.end = base + size - 1; region.end = base + size - 1;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
} }
@ -280,7 +280,7 @@ void of_scan_pci_bridge(struct pci_dev *dev)
res->flags = flags; res->flags = flags;
region.start = of_read_number(&ranges[1], 2); region.start = of_read_number(&ranges[1], 2);
region.end = region.start + size - 1; region.end = region.start + size - 1;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
bus->number); bus->number);

View file

@ -407,8 +407,8 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
struct msi_msg msg; struct msi_msg msg;
int rc; int rc;
if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI) if (type == PCI_CAP_ID_MSI && nvec > 1)
return -EINVAL; return 1;
msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX); msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX);
msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI); msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI);

View file

@ -392,7 +392,7 @@ static void apb_fake_ranges(struct pci_dev *dev,
res->flags = IORESOURCE_IO; res->flags = IORESOURCE_IO;
region.start = (first << 21); region.start = (first << 21);
region.end = (last << 21) + ((1 << 21) - 1); region.end = (last << 21) + ((1 << 21) - 1);
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map);
apb_calc_first_last(map, &first, &last); apb_calc_first_last(map, &first, &last);
@ -400,7 +400,7 @@ static void apb_fake_ranges(struct pci_dev *dev,
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
region.start = (first << 29); region.start = (first << 29);
region.end = (last << 29) + ((1 << 29) - 1); region.end = (last << 29) + ((1 << 29) - 1);
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
static void pci_of_scan_bus(struct pci_pbm_info *pbm, static void pci_of_scan_bus(struct pci_pbm_info *pbm,
@ -491,7 +491,7 @@ static void of_scan_pci_bridge(struct pci_pbm_info *pbm,
res->flags = flags; res->flags = flags;
region.start = GET_64BIT(ranges, 1); region.start = GET_64BIT(ranges, 1);
region.end = region.start + size - 1; region.end = region.start + size - 1;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
after_ranges: after_ranges:
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),

View file

@ -104,7 +104,7 @@ extern void pci_iommu_alloc(void);
struct msi_desc; struct msi_desc;
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
void native_teardown_msi_irq(unsigned int irq); void native_teardown_msi_irq(unsigned int irq);
void native_restore_msi_irqs(struct pci_dev *dev, int irq); void native_restore_msi_irqs(struct pci_dev *dev);
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
unsigned int irq_base, unsigned int irq_offset); unsigned int irq_base, unsigned int irq_offset);
#else #else
@ -125,7 +125,6 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
/* generic pci stuff */ /* generic pci stuff */
#include <asm-generic/pci.h> #include <asm-generic/pci.h>
#define PCIBIOS_MAX_MEM_32 0xffffffff
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
/* Returns the node based on pci bus */ /* Returns the node based on pci bus */

View file

@ -181,7 +181,7 @@ struct x86_msi_ops {
u8 hpet_id); u8 hpet_id);
void (*teardown_msi_irq)(unsigned int irq); void (*teardown_msi_irq)(unsigned int irq);
void (*teardown_msi_irqs)(struct pci_dev *dev); void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev, int irq); void (*restore_msi_irqs)(struct pci_dev *dev);
int (*setup_hpet_msi)(unsigned int irq, unsigned int id); int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag); u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag);
u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag); u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag);

View file

@ -1034,9 +1034,7 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
if (!acpi_ioapic) if (!acpi_ioapic)
return 0; return 0;
if (!dev) if (!dev || !dev_is_pci(dev))
return 0;
if (dev->bus != &pci_bus_type)
return 0; return 0;
pdev = to_pci_dev(dev); pdev = to_pci_dev(dev);

View file

@ -136,9 +136,9 @@ void arch_teardown_msi_irq(unsigned int irq)
x86_msi.teardown_msi_irq(irq); x86_msi.teardown_msi_irq(irq);
} }
void arch_restore_msi_irqs(struct pci_dev *dev, int irq) void arch_restore_msi_irqs(struct pci_dev *dev)
{ {
x86_msi.restore_msi_irqs(dev, irq); x86_msi.restore_msi_irqs(dev);
} }
u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{ {

View file

@ -337,7 +337,7 @@ out:
return ret; return ret;
} }
static void xen_initdom_restore_msi_irqs(struct pci_dev *dev, int irq) static void xen_initdom_restore_msi_irqs(struct pci_dev *dev)
{ {
int ret = 0; int ret = 0;

View file

@ -599,7 +599,9 @@ static int acpi_pci_root_add(struct acpi_device *device,
pci_assign_unassigned_root_bus_resources(root->bus); pci_assign_unassigned_root_bus_resources(root->bus);
} }
pci_lock_rescan_remove();
pci_bus_add_devices(root->bus); pci_bus_add_devices(root->bus);
pci_unlock_rescan_remove();
return 1; return 1;
end: end:
@ -611,6 +613,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
{ {
struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_root *root = acpi_driver_data(device);
pci_lock_rescan_remove();
pci_stop_root_bus(root->bus); pci_stop_root_bus(root->bus);
device_set_run_wake(root->bus->bridge, false); device_set_run_wake(root->bus->bridge, false);
@ -618,6 +622,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_remove_root_bus(root->bus); pci_remove_root_bus(root->bus);
pci_unlock_rescan_remove();
kfree(root); kfree(root);
} }

View file

@ -1148,26 +1148,40 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
{} {}
#endif #endif
static int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
struct ahci_host_priv *hpriv)
{ {
int rc; int rc, nvec;
unsigned int maxvec;
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
goto intx;
rc = pci_msi_vec_count(pdev);
if (rc < 0)
goto intx;
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI)) {
rc = pci_enable_msi_block_auto(pdev, &maxvec);
if (rc > 0) {
if ((rc == maxvec) || (rc == 1))
return rc;
/* /*
* Assume that advantage of multipe MSIs is negated, * If number of MSIs is less than number of ports then Sharing Last
* so fallback to single MSI mode to save resources * Message mode could be enforced. In this case assume that advantage
* of multipe MSIs is negated and use single MSI mode instead.
*/ */
pci_disable_msi(pdev); if (rc < n_ports)
if (!pci_enable_msi(pdev)) goto single_msi;
return 1;
}
}
nvec = rc;
rc = pci_enable_msi_block(pdev, nvec);
if (rc)
goto intx;
return nvec;
single_msi:
rc = pci_enable_msi(pdev);
if (rc)
goto intx;
return 1;
intx:
pci_intx(pdev, 1); pci_intx(pdev, 1);
return 0; return 0;
} }
@ -1328,10 +1342,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar]; hpriv->mmio = pcim_iomap_table(pdev)[ahci_pci_bar];
n_msis = ahci_init_interrupts(pdev, hpriv);
if (n_msis > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
/* save initial config */ /* save initial config */
ahci_pci_save_initial_config(pdev, hpriv); ahci_pci_save_initial_config(pdev, hpriv);
@ -1386,6 +1396,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
*/ */
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
n_msis = ahci_init_interrupts(pdev, n_ports, hpriv);
if (n_msis > 1)
hpriv->flags |= AHCI_HFLAG_MULTI_MSI;
host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;

View file

@ -239,6 +239,7 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* Chipset independent registers (from AGP Spec) */ /* Chipset independent registers (from AGP Spec) */
#define AGP_APBASE 0x10 #define AGP_APBASE 0x10
#define AGP_APERTURE_BAR 0
#define AGPSTAT 0x4 #define AGPSTAT 0x4
#define AGPCMD 0x8 #define AGPCMD 0x8

View file

@ -85,8 +85,8 @@ static int ali_configure(void)
pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010)); pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010));
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
#if 0 #if 0
if (agp_bridge->type == ALI_M1541) { if (agp_bridge->type == ALI_M1541) {

View file

@ -11,7 +11,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include "agp.h" #include "agp.h"
#define AMD_MMBASE 0x14 #define AMD_MMBASE_BAR 1
#define AMD_APSIZE 0xac #define AMD_APSIZE 0xac
#define AMD_MODECNTL 0xb0 #define AMD_MODECNTL 0xb0
#define AMD_MODECNTL2 0xb2 #define AMD_MODECNTL2 0xb2
@ -126,7 +126,6 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
unsigned long __iomem *cur_gatt; unsigned long __iomem *cur_gatt;
unsigned long addr; unsigned long addr;
int retval; int retval;
u32 temp;
int i; int i;
value = A_SIZE_LVL2(agp_bridge->current_size); value = A_SIZE_LVL2(agp_bridge->current_size);
@ -149,8 +148,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
* used to program the agp master not the cpu * used to program the agp master not the cpu
*/ */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
agp_bridge->gart_bus_addr = addr; agp_bridge->gart_bus_addr = addr;
/* Calculate the agp offset */ /* Calculate the agp offset */
@ -207,6 +205,7 @@ static int amd_irongate_fetch_size(void)
static int amd_irongate_configure(void) static int amd_irongate_configure(void)
{ {
struct aper_size_info_lvl2 *current_size; struct aper_size_info_lvl2 *current_size;
phys_addr_t reg;
u32 temp; u32 temp;
u16 enable_reg; u16 enable_reg;
@ -214,9 +213,8 @@ static int amd_irongate_configure(void)
if (!amd_irongate_private.registers) { if (!amd_irongate_private.registers) {
/* Get the memory mapped registers */ /* Get the memory mapped registers */
pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp); reg = pci_resource_start(agp_bridge->dev, AMD_MMBASE_BAR);
temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);
amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
if (!amd_irongate_private.registers) if (!amd_irongate_private.registers)
return -ENOMEM; return -ENOMEM;
} }

View file

@ -269,7 +269,6 @@ static int agp_aperture_valid(u64 aper, u32 size)
*/ */
static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap) static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
{ {
u32 aper_low, aper_hi;
u64 aper, nb_aper; u64 aper, nb_aper;
int order = 0; int order = 0;
u32 nb_order, nb_base; u32 nb_order, nb_base;
@ -295,9 +294,7 @@ static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
apsize |= 0xf00; apsize |= 0xf00;
order = 7 - hweight16(apsize); order = 7 - hweight16(apsize);
pci_read_config_dword(agp, 0x10, &aper_low); aper = pci_bus_address(agp, AGP_APERTURE_BAR);
pci_read_config_dword(agp, 0x14, &aper_hi);
aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
/* /*
* On some sick chips APSIZE is 0. This means it wants 4G * On some sick chips APSIZE is 0. This means it wants 4G

View file

@ -12,7 +12,7 @@
#include <asm/agp.h> #include <asm/agp.h>
#include "agp.h" #include "agp.h"
#define ATI_GART_MMBASE_ADDR 0x14 #define ATI_GART_MMBASE_BAR 1
#define ATI_RS100_APSIZE 0xac #define ATI_RS100_APSIZE 0xac
#define ATI_RS100_IG_AGPMODE 0xb0 #define ATI_RS100_IG_AGPMODE 0xb0
#define ATI_RS300_APSIZE 0xf8 #define ATI_RS300_APSIZE 0xf8
@ -196,12 +196,12 @@ static void ati_cleanup(void)
static int ati_configure(void) static int ati_configure(void)
{ {
phys_addr_t reg;
u32 temp; u32 temp;
/* Get the memory mapped registers */ /* Get the memory mapped registers */
pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp); reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR);
temp = (temp & 0xfffff000); ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);
ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
if (!ati_generic_private.registers) if (!ati_generic_private.registers)
return -ENOMEM; return -ENOMEM;
@ -211,18 +211,18 @@ static int ati_configure(void)
else else
pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000); pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
/* address to map too */ /* address to map to */
/* /*
pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp); agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev,
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr); printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
*/ */
writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID); writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/ readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/
/* SIGNALED_SYSTEM_ERROR @ NB_STATUS */ /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
pci_read_config_dword(agp_bridge->dev, 4, &temp); pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp);
pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14)); pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14));
/* Write out the address of the gatt table */ /* Write out the address of the gatt table */
writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE); writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
@ -385,8 +385,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
* This is a bus address even on the alpha, b/c its * This is a bus address even on the alpha, b/c its
* used to program the agp master not the cpu * used to program the agp master not the cpu
*/ */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
agp_bridge->gart_bus_addr = addr; agp_bridge->gart_bus_addr = addr;
/* Calculate the agp offset */ /* Calculate the agp offset */

View file

@ -128,7 +128,6 @@ static void efficeon_cleanup(void)
static int efficeon_configure(void) static int efficeon_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_lvl2 *current_size; struct aper_size_info_lvl2 *current_size;
@ -141,8 +140,8 @@ static int efficeon_configure(void)
current_size->size_value); current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280); pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);

View file

@ -1396,8 +1396,8 @@ int agp3_generic_configure(void)
current_size = A_SIZE_16(agp_bridge->current_size); current_size = A_SIZE_16(agp_bridge->current_size);
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* set aperture size */ /* set aperture size */
pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value); pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value);

View file

@ -118,7 +118,6 @@ static void intel_8xx_cleanup(void)
static int intel_configure(void) static int intel_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_16 *current_size; struct aper_size_info_16 *current_size;
@ -128,8 +127,8 @@ static int intel_configure(void)
pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -148,7 +147,7 @@ static int intel_configure(void)
static int intel_815_configure(void) static int intel_815_configure(void)
{ {
u32 temp, addr; u32 addr;
u8 temp2; u8 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -167,8 +166,8 @@ static int intel_815_configure(void)
current_size->size_value); current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr); pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);
addr &= INTEL_815_ATTBASE_MASK; addr &= INTEL_815_ATTBASE_MASK;
@ -208,7 +207,6 @@ static void intel_820_cleanup(void)
static int intel_820_configure(void) static int intel_820_configure(void)
{ {
u32 temp;
u8 temp2; u8 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -218,8 +216,8 @@ static int intel_820_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -239,7 +237,6 @@ static int intel_820_configure(void)
static int intel_840_configure(void) static int intel_840_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -249,8 +246,8 @@ static int intel_840_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -268,7 +265,6 @@ static int intel_840_configure(void)
static int intel_845_configure(void) static int intel_845_configure(void)
{ {
u32 temp;
u8 temp2; u8 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -282,9 +278,9 @@ static int intel_845_configure(void)
agp_bridge->apbase_config); agp_bridge->apbase_config);
} else { } else {
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
agp_bridge->apbase_config = temp; agp_bridge->apbase_config = agp_bridge->gart_bus_addr;
} }
/* attbase - aperture base */ /* attbase - aperture base */
@ -303,7 +299,6 @@ static int intel_845_configure(void)
static int intel_850_configure(void) static int intel_850_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -313,8 +308,8 @@ static int intel_850_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -332,7 +327,6 @@ static int intel_850_configure(void)
static int intel_860_configure(void) static int intel_860_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -342,8 +336,8 @@ static int intel_860_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -361,7 +355,6 @@ static int intel_860_configure(void)
static int intel_830mp_configure(void) static int intel_830mp_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -371,8 +364,8 @@ static int intel_830mp_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@ -390,7 +383,6 @@ static int intel_830mp_configure(void)
static int intel_7505_configure(void) static int intel_7505_configure(void)
{ {
u32 temp;
u16 temp2; u16 temp2;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
@ -400,8 +392,8 @@ static int intel_7505_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);

View file

@ -55,8 +55,8 @@
#define INTEL_I860_ERRSTS 0xc8 #define INTEL_I860_ERRSTS 0xc8
/* Intel i810 registers */ /* Intel i810 registers */
#define I810_GMADDR 0x10 #define I810_GMADR_BAR 0
#define I810_MMADDR 0x14 #define I810_MMADR_BAR 1
#define I810_PTE_BASE 0x10000 #define I810_PTE_BASE 0x10000
#define I810_PTE_MAIN_UNCACHED 0x00000000 #define I810_PTE_MAIN_UNCACHED 0x00000000
#define I810_PTE_LOCAL 0x00000002 #define I810_PTE_LOCAL 0x00000002
@ -113,9 +113,9 @@
#define INTEL_I850_ERRSTS 0xc8 #define INTEL_I850_ERRSTS 0xc8
/* intel 915G registers */ /* intel 915G registers */
#define I915_GMADDR 0x18 #define I915_GMADR_BAR 2
#define I915_MMADDR 0x10 #define I915_MMADR_BAR 0
#define I915_PTEADDR 0x1C #define I915_PTE_BAR 3
#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4) #define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)

View file

@ -64,7 +64,7 @@ static struct _intel_private {
struct pci_dev *pcidev; /* device one */ struct pci_dev *pcidev; /* device one */
struct pci_dev *bridge_dev; struct pci_dev *bridge_dev;
u8 __iomem *registers; u8 __iomem *registers;
phys_addr_t gtt_bus_addr; phys_addr_t gtt_phys_addr;
u32 PGETBL_save; u32 PGETBL_save;
u32 __iomem *gtt; /* I915G */ u32 __iomem *gtt; /* I915G */
bool clear_fake_agp; /* on first access via agp, fill with scratch */ bool clear_fake_agp; /* on first access via agp, fill with scratch */
@ -172,7 +172,7 @@ static void i8xx_destroy_pages(struct page *page)
#define I810_GTT_ORDER 4 #define I810_GTT_ORDER 4
static int i810_setup(void) static int i810_setup(void)
{ {
u32 reg_addr; phys_addr_t reg_addr;
char *gtt_table; char *gtt_table;
/* i81x does not preallocate the gtt. It's always 64kb in size. */ /* i81x does not preallocate the gtt. It's always 64kb in size. */
@ -181,8 +181,7 @@ static int i810_setup(void)
return -ENOMEM; return -ENOMEM;
intel_private.i81x_gtt_table = gtt_table; intel_private.i81x_gtt_table = gtt_table;
pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr); reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);
reg_addr &= 0xfff80000;
intel_private.registers = ioremap(reg_addr, KB(64)); intel_private.registers = ioremap(reg_addr, KB(64));
if (!intel_private.registers) if (!intel_private.registers)
@ -191,7 +190,7 @@ static int i810_setup(void)
writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED, writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED,
intel_private.registers+I810_PGETBL_CTL); intel_private.registers+I810_PGETBL_CTL);
intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;
if ((readl(intel_private.registers+I810_DRAM_CTL) if ((readl(intel_private.registers+I810_DRAM_CTL)
& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
@ -608,9 +607,8 @@ static bool intel_gtt_can_wc(void)
static int intel_gtt_init(void) static int intel_gtt_init(void)
{ {
u32 gma_addr;
u32 gtt_map_size; u32 gtt_map_size;
int ret; int ret, bar;
ret = intel_private.driver->setup(); ret = intel_private.driver->setup();
if (ret != 0) if (ret != 0)
@ -636,10 +634,10 @@ static int intel_gtt_init(void)
intel_private.gtt = NULL; intel_private.gtt = NULL;
if (intel_gtt_can_wc()) if (intel_gtt_can_wc())
intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr, intel_private.gtt = ioremap_wc(intel_private.gtt_phys_addr,
gtt_map_size); gtt_map_size);
if (intel_private.gtt == NULL) if (intel_private.gtt == NULL)
intel_private.gtt = ioremap(intel_private.gtt_bus_addr, intel_private.gtt = ioremap(intel_private.gtt_phys_addr,
gtt_map_size); gtt_map_size);
if (intel_private.gtt == NULL) { if (intel_private.gtt == NULL) {
intel_private.driver->cleanup(); intel_private.driver->cleanup();
@ -660,14 +658,11 @@ static int intel_gtt_init(void)
} }
if (INTEL_GTT_GEN <= 2) if (INTEL_GTT_GEN <= 2)
pci_read_config_dword(intel_private.pcidev, I810_GMADDR, bar = I810_GMADR_BAR;
&gma_addr);
else else
pci_read_config_dword(intel_private.pcidev, I915_GMADDR, bar = I915_GMADR_BAR;
&gma_addr);
intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
intel_private.gma_bus_addr = pci_bus_address(intel_private.pcidev, bar);
return 0; return 0;
} }
@ -787,16 +782,15 @@ EXPORT_SYMBOL(intel_enable_gtt);
static int i830_setup(void) static int i830_setup(void)
{ {
u32 reg_addr; phys_addr_t reg_addr;
pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr); reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);
reg_addr &= 0xfff80000;
intel_private.registers = ioremap(reg_addr, KB(64)); intel_private.registers = ioremap(reg_addr, KB(64));
if (!intel_private.registers) if (!intel_private.registers)
return -ENOMEM; return -ENOMEM;
intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;
return 0; return 0;
} }
@ -1108,12 +1102,10 @@ static void i965_write_entry(dma_addr_t addr,
static int i9xx_setup(void) static int i9xx_setup(void)
{ {
u32 reg_addr, gtt_addr; phys_addr_t reg_addr;
int size = KB(512); int size = KB(512);
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr); reg_addr = pci_resource_start(intel_private.pcidev, I915_MMADR_BAR);
reg_addr &= 0xfff80000;
intel_private.registers = ioremap(reg_addr, size); intel_private.registers = ioremap(reg_addr, size);
if (!intel_private.registers) if (!intel_private.registers)
@ -1121,15 +1113,14 @@ static int i9xx_setup(void)
switch (INTEL_GTT_GEN) { switch (INTEL_GTT_GEN) {
case 3: case 3:
pci_read_config_dword(intel_private.pcidev, intel_private.gtt_phys_addr =
I915_PTEADDR, &gtt_addr); pci_resource_start(intel_private.pcidev, I915_PTE_BAR);
intel_private.gtt_bus_addr = gtt_addr;
break; break;
case 5: case 5:
intel_private.gtt_bus_addr = reg_addr + MB(2); intel_private.gtt_phys_addr = reg_addr + MB(2);
break; break;
default: default:
intel_private.gtt_bus_addr = reg_addr + KB(512); intel_private.gtt_phys_addr = reg_addr + KB(512);
break; break;
} }

View file

@ -106,6 +106,7 @@ static int nvidia_configure(void)
{ {
int i, rc, num_dirs; int i, rc, num_dirs;
u32 apbase, aplimit; u32 apbase, aplimit;
phys_addr_t apbase_phys;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
u32 temp; u32 temp;
@ -116,8 +117,7 @@ static int nvidia_configure(void)
current_size->size_value); current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &apbase); apbase = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
apbase &= PCI_BASE_ADDRESS_MEM_MASK;
agp_bridge->gart_bus_addr = apbase; agp_bridge->gart_bus_addr = apbase;
aplimit = apbase + (current_size->size * 1024 * 1024) - 1; aplimit = apbase + (current_size->size * 1024 * 1024) - 1;
pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase); pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase);
@ -153,8 +153,9 @@ static int nvidia_configure(void)
pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100); pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100);
/* map aperture */ /* map aperture */
apbase_phys = pci_resource_start(agp_bridge->dev, AGP_APERTURE_BAR);
nvidia_private.aperture = nvidia_private.aperture =
(volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE); (volatile u32 __iomem *) ioremap(apbase_phys, 33 * PAGE_SIZE);
if (!nvidia_private.aperture) if (!nvidia_private.aperture)
return -ENOMEM; return -ENOMEM;

View file

@ -50,13 +50,12 @@ static void sis_tlbflush(struct agp_memory *mem)
static int sis_configure(void) static int sis_configure(void)
{ {
u32 temp;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
current_size = A_SIZE_8(agp_bridge->current_size); current_size = A_SIZE_8(agp_bridge->current_size);
pci_write_config_byte(agp_bridge->dev, SIS_TLBCNTRL, 0x05); pci_write_config_byte(agp_bridge->dev, SIS_TLBCNTRL, 0x05);
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
pci_write_config_dword(agp_bridge->dev, SIS_ATTBASE, pci_write_config_dword(agp_bridge->dev, SIS_ATTBASE,
agp_bridge->gatt_bus_addr); agp_bridge->gatt_bus_addr);
pci_write_config_byte(agp_bridge->dev, SIS_APSIZE, pci_write_config_byte(agp_bridge->dev, SIS_APSIZE,

View file

@ -43,16 +43,15 @@ static int via_fetch_size(void)
static int via_configure(void) static int via_configure(void)
{ {
u32 temp;
struct aper_size_info_8 *current_size; struct aper_size_info_8 *current_size;
current_size = A_SIZE_8(agp_bridge->current_size); current_size = A_SIZE_8(agp_bridge->current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge->dev, VIA_APSIZE, pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,
current_size->size_value); current_size->size_value);
/* address to map too */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* GART control register */ /* GART control register */
pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f); pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f);
@ -132,9 +131,9 @@ static int via_configure_agp3(void)
current_size = A_SIZE_16(agp_bridge->current_size); current_size = A_SIZE_16(agp_bridge->current_size);
/* address to map too */ /* address to map to */
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); AGP_APERTURE_BAR);
/* attbase - aperture GATT base */ /* attbase - aperture GATT base */
pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE, pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE,

View file

@ -232,8 +232,10 @@ static int __init eisa_init_device(struct eisa_root_device *root,
static int __init eisa_register_device(struct eisa_device *edev) static int __init eisa_register_device(struct eisa_device *edev)
{ {
int rc = device_register(&edev->dev); int rc = device_register(&edev->dev);
if (rc) if (rc) {
put_device(&edev->dev);
return rc; return rc;
}
rc = device_create_file(&edev->dev, &dev_attr_signature); rc = device_create_file(&edev->dev, &dev_attr_signature);
if (rc) if (rc)
@ -275,18 +277,19 @@ static int __init eisa_request_resources(struct eisa_root_device *root,
} }
if (slot) { if (slot) {
edev->res[i].name = NULL;
edev->res[i].start = SLOT_ADDRESS(root, slot) edev->res[i].start = SLOT_ADDRESS(root, slot)
+ (i * 0x400); + (i * 0x400);
edev->res[i].end = edev->res[i].start + 0xff; edev->res[i].end = edev->res[i].start + 0xff;
edev->res[i].flags = IORESOURCE_IO; edev->res[i].flags = IORESOURCE_IO;
} else { } else {
edev->res[i].name = NULL;
edev->res[i].start = SLOT_ADDRESS(root, slot) edev->res[i].start = SLOT_ADDRESS(root, slot)
+ EISA_VENDOR_ID_OFFSET; + EISA_VENDOR_ID_OFFSET;
edev->res[i].end = edev->res[i].start + 3; edev->res[i].end = edev->res[i].start + 3;
edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY; edev->res[i].flags = IORESOURCE_IO | IORESOURCE_BUSY;
} }
dev_printk(KERN_DEBUG, &edev->dev, "%pR\n", &edev->res[i]);
if (request_resource(root->res, &edev->res[i])) if (request_resource(root->res, &edev->res[i]))
goto failed; goto failed;
} }
@ -326,13 +329,6 @@ static int __init eisa_probe(struct eisa_root_device *root)
return -ENOMEM; return -ENOMEM;
} }
if (eisa_init_device(root, edev, 0)) {
kfree(edev);
if (!root->force_probe)
return -ENODEV;
goto force_probe;
}
if (eisa_request_resources(root, edev, 0)) { if (eisa_request_resources(root, edev, 0)) {
dev_warn(root->dev, dev_warn(root->dev,
"EISA: Cannot allocate resource for mainboard\n"); "EISA: Cannot allocate resource for mainboard\n");
@ -342,6 +338,14 @@ static int __init eisa_probe(struct eisa_root_device *root)
goto force_probe; goto force_probe;
} }
if (eisa_init_device(root, edev, 0)) {
eisa_release_resources(edev);
kfree(edev);
if (!root->force_probe)
return -ENODEV;
goto force_probe;
}
dev_info(&edev->dev, "EISA: Mainboard %s detected\n", edev->id.sig); dev_info(&edev->dev, "EISA: Mainboard %s detected\n", edev->id.sig);
if (eisa_register_device(edev)) { if (eisa_register_device(edev)) {
@ -361,11 +365,6 @@ static int __init eisa_probe(struct eisa_root_device *root)
continue; continue;
} }
if (eisa_init_device(root, edev, i)) {
kfree(edev);
continue;
}
if (eisa_request_resources(root, edev, i)) { if (eisa_request_resources(root, edev, i)) {
dev_warn(root->dev, dev_warn(root->dev,
"Cannot allocate resource for EISA slot %d\n", "Cannot allocate resource for EISA slot %d\n",
@ -374,6 +373,12 @@ static int __init eisa_probe(struct eisa_root_device *root)
continue; continue;
} }
if (eisa_init_device(root, edev, i)) {
eisa_release_resources(edev);
kfree(edev);
continue;
}
if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED)) if (edev->state == (EISA_CONFIG_ENABLED | EISA_CONFIG_FORCED))
enabled_str = " (forced enabled)"; enabled_str = " (forced enabled)";
else if (edev->state == EISA_CONFIG_FORCED) else if (edev->state == EISA_CONFIG_FORCED)

View file

@ -1265,14 +1265,14 @@ static int ggtt_probe_common(struct drm_device *dev,
size_t gtt_size) size_t gtt_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
phys_addr_t gtt_bus_addr; phys_addr_t gtt_phys_addr;
int ret; int ret;
/* For Modern GENs the PTEs and register space are split in the BAR */ /* For Modern GENs the PTEs and register space are split in the BAR */
gtt_bus_addr = pci_resource_start(dev->pdev, 0) + gtt_phys_addr = pci_resource_start(dev->pdev, 0) +
(pci_resource_len(dev->pdev, 0) / 2); (pci_resource_len(dev->pdev, 0) / 2);
dev_priv->gtt.gsm = ioremap_wc(gtt_bus_addr, gtt_size); dev_priv->gtt.gsm = ioremap_wc(gtt_phys_addr, gtt_size);
if (!dev_priv->gtt.gsm) { if (!dev_priv->gtt.gsm) {
DRM_ERROR("Failed to map the gtt page table\n"); DRM_ERROR("Failed to map the gtt page table\n");
return -ENOMEM; return -ENOMEM;

View file

@ -346,7 +346,7 @@ static int mpt_remove_dead_ioc_func(void *arg)
if ((pdev == NULL)) if ((pdev == NULL))
return -1; return -1;
pci_stop_and_remove_bus_device(pdev); pci_stop_and_remove_bus_device_locked(pdev);
return 0; return 0;
} }

View file

@ -105,9 +105,10 @@ config PCI_PASID
If unsure, say N. If unsure, say N.
config PCI_IOAPIC config PCI_IOAPIC
tristate "PCI IO-APIC hotplug support" if X86 bool "PCI IO-APIC hotplug support" if X86
depends on PCI depends on PCI
depends on ACPI depends on ACPI
depends on X86_IO_APIC
default !X86 default !X86
config PCI_LABEL config PCI_LABEL

View file

@ -4,7 +4,7 @@
obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
irq.o vpd.o setup-bus.o irq.o vpd.o setup-bus.o vc.o
obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o obj-$(CONFIG_SYSFS) += slot.o

View file

@ -380,30 +380,6 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
return 0; return 0;
} }
/**
* pci_vpd_truncate - Set available Vital Product Data size
* @dev: pci device struct
* @size: available memory in bytes
*
* Adjust size of available VPD area.
*/
int pci_vpd_truncate(struct pci_dev *dev, size_t size)
{
if (!dev->vpd)
return -EINVAL;
/* limited by the access method */
if (size > dev->vpd->len)
return -EINVAL;
dev->vpd->len = size;
if (dev->vpd->attr)
dev->vpd->attr->size = size;
return 0;
}
EXPORT_SYMBOL(pci_vpd_truncate);
/** /**
* pci_cfg_access_lock - Lock PCI config reads/writes * pci_cfg_access_lock - Lock PCI config reads/writes
* @dev: pci device struct * @dev: pci device struct

View file

@ -234,27 +234,6 @@ void pci_disable_pri(struct pci_dev *pdev)
} }
EXPORT_SYMBOL_GPL(pci_disable_pri); EXPORT_SYMBOL_GPL(pci_disable_pri);
/**
* pci_pri_enabled - Checks if PRI capability is enabled
* @pdev: PCI device structure
*
* Returns true if PRI is enabled on the device, false otherwise
*/
bool pci_pri_enabled(struct pci_dev *pdev)
{
u16 control;
int pos;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return false;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
return (control & PCI_PRI_CTRL_ENABLE) ? true : false;
}
EXPORT_SYMBOL_GPL(pci_pri_enabled);
/** /**
* pci_reset_pri - Resets device's PRI state * pci_reset_pri - Resets device's PRI state
* @pdev: PCI device structure * @pdev: PCI device structure
@ -282,67 +261,6 @@ int pci_reset_pri(struct pci_dev *pdev)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_reset_pri); EXPORT_SYMBOL_GPL(pci_reset_pri);
/**
* pci_pri_stopped - Checks whether the PRI capability is stopped
* @pdev: PCI device structure
*
* Returns true if the PRI capability on the device is disabled and the
* device has no outstanding PRI requests, false otherwise. The device
* indicates this via the STOPPED bit in the status register of the
* capability.
* The device internal state can be cleared by resetting the PRI state
* with pci_reset_pri(). This can force the capability into the STOPPED
* state.
*/
bool pci_pri_stopped(struct pci_dev *pdev)
{
u16 control, status;
int pos;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return true;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
if (control & PCI_PRI_CTRL_ENABLE)
return false;
return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
}
EXPORT_SYMBOL_GPL(pci_pri_stopped);
/**
* pci_pri_status - Request PRI status of a device
* @pdev: PCI device structure
*
* Returns negative value on failure, status on success. The status can
* be checked against status-bits. Supported bits are currently:
* PCI_PRI_STATUS_RF: Response failure
* PCI_PRI_STATUS_UPRGI: Unexpected Page Request Group Index
* PCI_PRI_STATUS_STOPPED: PRI has stopped
*/
int pci_pri_status(struct pci_dev *pdev)
{
u16 status, control;
int pos;
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
if (!pos)
return -EINVAL;
pci_read_config_word(pdev, pos + PCI_PRI_CTRL, &control);
pci_read_config_word(pdev, pos + PCI_PRI_STATUS, &status);
/* Stopped bit is undefined when enable == 1, so clear it */
if (control & PCI_PRI_CTRL_ENABLE)
status &= ~PCI_PRI_STATUS_STOPPED;
return status;
}
EXPORT_SYMBOL_GPL(pci_pri_status);
#endif /* CONFIG_PCI_PRI */ #endif /* CONFIG_PCI_PRI */
#ifdef CONFIG_PCI_PASID #ifdef CONFIG_PCI_PASID

View file

@ -98,41 +98,54 @@ void pci_bus_remove_resources(struct pci_bus *bus)
} }
} }
/** static struct pci_bus_region pci_32_bit = {0, 0xffffffffULL};
* pci_bus_alloc_resource - allocate a resource from a parent bus #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
* @bus: PCI bus static struct pci_bus_region pci_64_bit = {0,
* @res: resource to allocate (dma_addr_t) 0xffffffffffffffffULL};
* @size: size of resource to allocate static struct pci_bus_region pci_high = {(dma_addr_t) 0x100000000ULL,
* @align: alignment of resource to allocate (dma_addr_t) 0xffffffffffffffffULL};
* @min: minimum /proc/iomem address to allocate #endif
* @type_mask: IORESOURCE_* type flags
* @alignf: resource alignment function /*
* @alignf_data: data argument for resource alignment function * @res contains CPU addresses. Clip it so the corresponding bus addresses
* * on @bus are entirely within @region. This is used to control the bus
* Given the PCI bus a device resides on, the size, minimum address, * addresses of resources we allocate, e.g., we may need a resource that
* alignment and type, try to find an acceptable resource allocation * can be mapped by a 32-bit BAR.
* for a specific device resource.
*/ */
int static void pci_clip_resource_to_region(struct pci_bus *bus,
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, struct resource *res,
struct pci_bus_region *region)
{
struct pci_bus_region r;
pcibios_resource_to_bus(bus, &r, res);
if (r.start < region->start)
r.start = region->start;
if (r.end > region->end)
r.end = region->end;
if (r.end < r.start)
res->end = res->start - 1;
else
pcibios_bus_to_resource(bus, res, &r);
}
static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align, resource_size_t size, resource_size_t align,
resource_size_t min, unsigned int type_mask, resource_size_t min, unsigned int type_mask,
resource_size_t (*alignf)(void *, resource_size_t (*alignf)(void *,
const struct resource *, const struct resource *,
resource_size_t, resource_size_t,
resource_size_t), resource_size_t),
void *alignf_data) void *alignf_data,
struct pci_bus_region *region)
{ {
int i, ret = -ENOMEM; int i, ret;
struct resource *r; struct resource *r, avail;
resource_size_t max = -1; resource_size_t max;
type_mask |= IORESOURCE_IO | IORESOURCE_MEM; type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
/* don't allocate too high if the pref mem doesn't support 64bit*/
if (!(res->flags & IORESOURCE_MEM_64))
max = PCIBIOS_MAX_MEM_32;
pci_bus_for_each_resource(bus, r, i) { pci_bus_for_each_resource(bus, r, i) {
if (!r) if (!r)
continue; continue;
@ -147,15 +160,74 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
!(res->flags & IORESOURCE_PREFETCH)) !(res->flags & IORESOURCE_PREFETCH))
continue; continue;
avail = *r;
pci_clip_resource_to_region(bus, &avail, region);
if (!resource_size(&avail))
continue;
/*
* "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
* protect badly documented motherboard resources, but if
* this is an already-configured bridge window, its start
* overrides "min".
*/
if (avail.start)
min = avail.start;
max = avail.end;
/* Ok, try it out.. */ /* Ok, try it out.. */
ret = allocate_resource(r, res, size, ret = allocate_resource(r, res, size, min, max,
r->start ? : min, align, alignf, alignf_data);
max, align,
alignf, alignf_data);
if (ret == 0) if (ret == 0)
break; return 0;
} }
return ret; return -ENOMEM;
}
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
* @bus: PCI bus
* @res: resource to allocate
* @size: size of resource to allocate
* @align: alignment of resource to allocate
* @min: minimum /proc/iomem address to allocate
* @type_mask: IORESOURCE_* type flags
* @alignf: resource alignment function
* @alignf_data: data argument for resource alignment function
*
* Given the PCI bus a device resides on, the size, minimum address,
* alignment and type, try to find an acceptable resource allocation
* for a specific device resource.
*/
int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
resource_size_t size, resource_size_t align,
resource_size_t min, unsigned int type_mask,
resource_size_t (*alignf)(void *,
const struct resource *,
resource_size_t,
resource_size_t),
void *alignf_data)
{
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
int rc;
if (res->flags & IORESOURCE_MEM_64) {
rc = pci_bus_alloc_from_region(bus, res, size, align, min,
type_mask, alignf, alignf_data,
&pci_high);
if (rc == 0)
return 0;
return pci_bus_alloc_from_region(bus, res, size, align, min,
type_mask, alignf, alignf_data,
&pci_64_bit);
}
#endif
return pci_bus_alloc_from_region(bus, res, size, align, min,
type_mask, alignf, alignf_data,
&pci_32_bit);
} }
void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
@ -176,6 +248,7 @@ int pci_bus_add_device(struct pci_dev *dev)
*/ */
pci_fixup_device(pci_fixup_final, dev); pci_fixup_device(pci_fixup_final, dev);
pci_create_sysfs_dev_files(dev); pci_create_sysfs_dev_files(dev);
pci_proc_attach_device(dev);
dev->match_driver = true; dev->match_driver = true;
retval = device_attach(&dev->dev); retval = device_attach(&dev->dev);

View file

@ -9,22 +9,19 @@
#include "pci.h" #include "pci.h"
static struct pci_bus *find_pci_root_bus(struct pci_dev *dev) static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
{ {
struct pci_bus *bus;
bus = dev->bus;
while (bus->parent) while (bus->parent)
bus = bus->parent; bus = bus->parent;
return bus; return bus;
} }
static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev) static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
{ {
struct pci_bus *bus = find_pci_root_bus(dev); struct pci_bus *root_bus = find_pci_root_bus(bus);
return to_pci_host_bridge(bus->bridge); return to_pci_host_bridge(root_bus->bridge);
} }
void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
@ -40,10 +37,10 @@ static bool resource_contains(struct resource *res1, struct resource *res2)
return res1->start <= res2->start && res1->end >= res2->end; return res1->start <= res2->start && res1->end >= res2->end;
} }
void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res) struct resource *res)
{ {
struct pci_host_bridge *bridge = find_pci_host_bridge(dev); struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
struct pci_host_bridge_window *window; struct pci_host_bridge_window *window;
resource_size_t offset = 0; resource_size_t offset = 0;
@ -68,10 +65,10 @@ static bool region_contains(struct pci_bus_region *region1,
return region1->start <= region2->start && region1->end >= region2->end; return region1->start <= region2->start && region1->end >= region2->end;
} }
void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
struct pci_bus_region *region) struct pci_bus_region *region)
{ {
struct pci_host_bridge *bridge = find_pci_host_bridge(dev); struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
struct pci_host_bridge_window *window; struct pci_host_bridge_window *window;
resource_size_t offset = 0; resource_size_t offset = 0;

View file

@ -468,7 +468,7 @@ static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
int ret; int ret;
exynos_pcie_sideband_dbi_r_mode(pp, true); exynos_pcie_sideband_dbi_r_mode(pp, true);
ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where, size, val);
exynos_pcie_sideband_dbi_r_mode(pp, false); exynos_pcie_sideband_dbi_r_mode(pp, false);
return ret; return ret;
} }
@ -479,7 +479,8 @@ static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
int ret; int ret;
exynos_pcie_sideband_dbi_w_mode(pp, true); exynos_pcie_sideband_dbi_w_mode(pp, true);
ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, val); ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3),
where, size, val);
exynos_pcie_sideband_dbi_w_mode(pp, false); exynos_pcie_sideband_dbi_w_mode(pp, false);
return ret; return ret;
} }

View file

@ -44,10 +44,18 @@ struct imx6_pcie {
void __iomem *mem_base; void __iomem *mem_base;
}; };
/* PCIe Root Complex registers (memory-mapped) */
#define PCIE_RC_LCR 0x7c
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
/* PCIe Port Logic registers (memory-mapped) */ /* PCIe Port Logic registers (memory-mapped) */
#define PL_OFFSET 0x700 #define PL_OFFSET 0x700
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28) #define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c) #define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
#define PCIE_PHY_CTRL (PL_OFFSET + 0x114) #define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
#define PCIE_PHY_CTRL_DATA_LOC 0 #define PCIE_PHY_CTRL_DATA_LOC 0
@ -59,6 +67,9 @@ struct imx6_pcie {
#define PCIE_PHY_STAT (PL_OFFSET + 0x110) #define PCIE_PHY_STAT (PL_OFFSET + 0x110)
#define PCIE_PHY_STAT_ACK_LOC 16 #define PCIE_PHY_STAT_ACK_LOC 16
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
/* PHY registers (not memory-mapped) */ /* PHY registers (not memory-mapped) */
#define PCIE_PHY_RX_ASIC_OUT 0x100D #define PCIE_PHY_RX_ASIC_OUT 0x100D
@ -209,15 +220,9 @@ static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18); IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16); IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
gpio_set_value(imx6_pcie->reset_gpio, 0);
msleep(100);
gpio_set_value(imx6_pcie->reset_gpio, 1);
return 0; return 0;
} }
@ -261,6 +266,12 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
/* allow the clocks to stabilize */ /* allow the clocks to stabilize */
usleep_range(200, 500); usleep_range(200, 500);
/* Some boards don't have PCIe reset GPIO. */
if (gpio_is_valid(imx6_pcie->reset_gpio)) {
gpio_set_value(imx6_pcie->reset_gpio, 0);
msleep(100);
gpio_set_value(imx6_pcie->reset_gpio, 1);
}
return 0; return 0;
err_pcie_axi: err_pcie_axi:
@ -299,11 +310,90 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)
IMX6Q_GPR8_TX_SWING_LOW, 127 << 25); IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
} }
static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{
int count = 200;
while (!dw_pcie_link_up(pp)) {
usleep_range(100, 1000);
if (--count)
continue;
dev_err(pp->dev, "phy link never came up\n");
dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
return -EINVAL;
}
return 0;
}
static int imx6_pcie_start_link(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
uint32_t tmp;
int ret, count;
/*
* Force Gen1 operation when starting the link. In case the link is
* started in Gen2 mode, there is a possibility the devices on the
* bus will not be detected at all. This happens with PCIe switches.
*/
tmp = readl(pp->dbi_base + PCIE_RC_LCR);
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
writel(tmp, pp->dbi_base + PCIE_RC_LCR);
/* Start LTSSM. */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
ret = imx6_pcie_wait_for_link(pp);
if (ret)
return ret;
/* Allow Gen2 mode after the link is up. */
tmp = readl(pp->dbi_base + PCIE_RC_LCR);
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
writel(tmp, pp->dbi_base + PCIE_RC_LCR);
/*
* Start Directed Speed Change so the best possible speed both link
* partners support can be negotiated.
*/
tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
tmp |= PORT_LOGIC_SPEED_CHANGE;
writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
count = 200;
while (count--) {
tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL);
/* Test if the speed change finished. */
if (!(tmp & PORT_LOGIC_SPEED_CHANGE))
break;
usleep_range(100, 1000);
}
/* Make sure link training is finished as well! */
if (count)
ret = imx6_pcie_wait_for_link(pp);
else
ret = -EINVAL;
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
} else {
tmp = readl(pp->dbi_base + 0x80);
dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
}
return ret;
}
static void imx6_pcie_host_init(struct pcie_port *pp) static void imx6_pcie_host_init(struct pcie_port *pp)
{ {
int count = 0;
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
imx6_pcie_assert_core_reset(pp); imx6_pcie_assert_core_reset(pp);
imx6_pcie_init_phy(pp); imx6_pcie_init_phy(pp);
@ -312,33 +402,41 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
dw_pcie_setup_rc(pp); dw_pcie_setup_rc(pp);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, imx6_pcie_start_link(pp);
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10); }
while (!dw_pcie_link_up(pp)) { static void imx6_pcie_reset_phy(struct pcie_port *pp)
usleep_range(100, 1000); {
count++; uint32_t temp;
if (count >= 200) {
dev_err(pp->dev, "phy link never came up\n");
dev_dbg(pp->dev,
"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
break;
}
}
return; pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
usleep_range(2000, 3000);
pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &temp);
temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, temp);
} }
static int imx6_pcie_link_up(struct pcie_port *pp) static int imx6_pcie_link_up(struct pcie_port *pp)
{ {
u32 rc, ltssm, rx_valid, temp; u32 rc, ltssm, rx_valid;
/* link is debug bit 36, debug register 1 starts at bit 32 */ /*
rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32)); * Test if the PHY reports that the link is up and also that
if (rc) * the link training finished. It might happen that the PHY
return -EAGAIN; * reports the link is already up, but the link training bit
* is still set, so make sure to check the training is done
* as well here.
*/
rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
if ((rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
return 1;
/* /*
* From L0, initiate MAC entry to gen2 if EP/RC supports gen2. * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
@ -358,21 +456,7 @@ static int imx6_pcie_link_up(struct pcie_port *pp)
dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n"); dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
pcie_phy_read(pp->dbi_base, imx6_pcie_reset_phy(pp);
PHY_RX_OVRD_IN_LO, &temp);
temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
pcie_phy_write(pp->dbi_base,
PHY_RX_OVRD_IN_LO, temp);
usleep_range(2000, 3000);
pcie_phy_read(pp->dbi_base,
PHY_RX_OVRD_IN_LO, &temp);
temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
pcie_phy_write(pp->dbi_base,
PHY_RX_OVRD_IN_LO, temp);
return 0; return 0;
} }
@ -426,30 +510,19 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
"imprecise external abort"); "imprecise external abort");
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!dbi_base) {
dev_err(&pdev->dev, "dbi_base memory resource not found\n");
return -ENODEV;
}
pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base); pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
if (IS_ERR(pp->dbi_base)) { if (IS_ERR(pp->dbi_base))
ret = PTR_ERR(pp->dbi_base); return PTR_ERR(pp->dbi_base);
goto err;
}
/* Fetch GPIOs */ /* Fetch GPIOs */
imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
if (!gpio_is_valid(imx6_pcie->reset_gpio)) { if (gpio_is_valid(imx6_pcie->reset_gpio)) {
dev_err(&pdev->dev, "no reset-gpio defined\n"); ret = devm_gpio_request_one(&pdev->dev, imx6_pcie->reset_gpio,
ret = -ENODEV; GPIOF_OUT_INIT_LOW, "PCIe reset");
}
ret = devm_gpio_request_one(&pdev->dev,
imx6_pcie->reset_gpio,
GPIOF_OUT_INIT_LOW,
"PCIe reset");
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to get reset gpio\n"); dev_err(&pdev->dev, "unable to get reset gpio\n");
goto err; return ret;
}
} }
imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0); imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
@ -460,7 +533,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
"PCIe power enable"); "PCIe power enable");
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to get power-on gpio\n"); dev_err(&pdev->dev, "unable to get power-on gpio\n");
goto err; return ret;
} }
} }
@ -472,7 +545,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
"PCIe wake up"); "PCIe wake up");
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to get wake-up gpio\n"); dev_err(&pdev->dev, "unable to get wake-up gpio\n");
goto err; return ret;
} }
} }
@ -484,7 +557,7 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
"PCIe disable endpoint"); "PCIe disable endpoint");
if (ret) { if (ret) {
dev_err(&pdev->dev, "unable to get disable-ep gpio\n"); dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
goto err; return ret;
} }
} }
@ -493,32 +566,28 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
if (IS_ERR(imx6_pcie->lvds_gate)) { if (IS_ERR(imx6_pcie->lvds_gate)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"lvds_gate clock select missing or invalid\n"); "lvds_gate clock select missing or invalid\n");
ret = PTR_ERR(imx6_pcie->lvds_gate); return PTR_ERR(imx6_pcie->lvds_gate);
goto err;
} }
imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m"); imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m");
if (IS_ERR(imx6_pcie->sata_ref_100m)) { if (IS_ERR(imx6_pcie->sata_ref_100m)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"sata_ref_100m clock source missing or invalid\n"); "sata_ref_100m clock source missing or invalid\n");
ret = PTR_ERR(imx6_pcie->sata_ref_100m); return PTR_ERR(imx6_pcie->sata_ref_100m);
goto err;
} }
imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m"); imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m");
if (IS_ERR(imx6_pcie->pcie_ref_125m)) { if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"pcie_ref_125m clock source missing or invalid\n"); "pcie_ref_125m clock source missing or invalid\n");
ret = PTR_ERR(imx6_pcie->pcie_ref_125m); return PTR_ERR(imx6_pcie->pcie_ref_125m);
goto err;
} }
imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi"); imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi");
if (IS_ERR(imx6_pcie->pcie_axi)) { if (IS_ERR(imx6_pcie->pcie_axi)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"pcie_axi clock source missing or invalid\n"); "pcie_axi clock source missing or invalid\n");
ret = PTR_ERR(imx6_pcie->pcie_axi); return PTR_ERR(imx6_pcie->pcie_axi);
goto err;
} }
/* Grab GPR config register range */ /* Grab GPR config register range */
@ -526,19 +595,15 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
if (IS_ERR(imx6_pcie->iomuxc_gpr)) { if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
dev_err(&pdev->dev, "unable to find iomuxc registers\n"); dev_err(&pdev->dev, "unable to find iomuxc registers\n");
ret = PTR_ERR(imx6_pcie->iomuxc_gpr); return PTR_ERR(imx6_pcie->iomuxc_gpr);
goto err;
} }
ret = imx6_add_pcie_port(pp, pdev); ret = imx6_add_pcie_port(pp, pdev);
if (ret < 0) if (ret < 0)
goto err; return ret;
platform_set_drvdata(pdev, imx6_pcie); platform_set_drvdata(pdev, imx6_pcie);
return 0; return 0;
err:
return ret;
} }
static const struct of_device_id imx6_pcie_of_match[] = { static const struct of_device_id imx6_pcie_of_match[] = {

View file

@ -150,6 +150,11 @@ static inline u32 mvebu_readl(struct mvebu_pcie_port *port, u32 reg)
return readl(port->base + reg); return readl(port->base + reg);
} }
static inline bool mvebu_has_ioport(struct mvebu_pcie_port *port)
{
return port->io_target != -1 && port->io_attr != -1;
}
static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port) static bool mvebu_pcie_link_up(struct mvebu_pcie_port *port)
{ {
return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN); return !(mvebu_readl(port, PCIE_STAT_OFF) & PCIE_STAT_LINK_DOWN);
@ -300,7 +305,8 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
/* Are the new iobase/iolimit values invalid? */ /* Are the new iobase/iolimit values invalid? */
if (port->bridge.iolimit < port->bridge.iobase || if (port->bridge.iolimit < port->bridge.iobase ||
port->bridge.iolimitupper < port->bridge.iobaseupper) { port->bridge.iolimitupper < port->bridge.iobaseupper ||
!(port->bridge.command & PCI_COMMAND_IO)) {
/* If a window was configured, remove it */ /* If a window was configured, remove it */
if (port->iowin_base) { if (port->iowin_base) {
@ -313,6 +319,12 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
return; return;
} }
if (!mvebu_has_ioport(port)) {
dev_WARN(&port->pcie->pdev->dev,
"Attempt to set IO when IO is disabled\n");
return;
}
/* /*
* We read the PCI-to-PCI bridge emulated registers, and * We read the PCI-to-PCI bridge emulated registers, and
* calculate the base address and size of the address decoding * calculate the base address and size of the address decoding
@ -330,14 +342,13 @@ static void mvebu_pcie_handle_iobase_change(struct mvebu_pcie_port *port)
mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr, mvebu_mbus_add_window_remap_by_id(port->io_target, port->io_attr,
port->iowin_base, port->iowin_size, port->iowin_base, port->iowin_size,
iobase); iobase);
pci_ioremap_io(iobase, port->iowin_base);
} }
static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port) static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
{ {
/* Are the new membase/memlimit values invalid? */ /* Are the new membase/memlimit values invalid? */
if (port->bridge.memlimit < port->bridge.membase) { if (port->bridge.memlimit < port->bridge.membase ||
!(port->bridge.command & PCI_COMMAND_MEMORY)) {
/* If a window was configured, remove it */ /* If a window was configured, remove it */
if (port->memwin_base) { if (port->memwin_base) {
@ -426,6 +437,9 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
break; break;
case PCI_IO_BASE: case PCI_IO_BASE:
if (!mvebu_has_ioport(port))
*value = bridge->secondary_status << 16;
else
*value = (bridge->secondary_status << 16 | *value = (bridge->secondary_status << 16 |
bridge->iolimit << 8 | bridge->iolimit << 8 |
bridge->iobase); bridge->iobase);
@ -490,8 +504,19 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
switch (where & ~3) { switch (where & ~3) {
case PCI_COMMAND: case PCI_COMMAND:
{
u32 old = bridge->command;
if (!mvebu_has_ioport(port))
value &= ~PCI_COMMAND_IO;
bridge->command = value & 0xffff; bridge->command = value & 0xffff;
if ((old ^ bridge->command) & PCI_COMMAND_IO)
mvebu_pcie_handle_iobase_change(port);
if ((old ^ bridge->command) & PCI_COMMAND_MEMORY)
mvebu_pcie_handle_membase_change(port);
break; break;
}
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1: case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value; bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
@ -505,7 +530,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
*/ */
bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32; bridge->iobase = (value & 0xff) | PCI_IO_RANGE_TYPE_32;
bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32; bridge->iolimit = ((value >> 8) & 0xff) | PCI_IO_RANGE_TYPE_32;
bridge->secondary_status = value >> 16;
mvebu_pcie_handle_iobase_change(port); mvebu_pcie_handle_iobase_change(port);
break; break;
@ -656,7 +680,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
struct mvebu_pcie *pcie = sys_to_pcie(sys); struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i; int i;
pci_add_resource_offset(&sys->resources, &pcie->realio, sys->io_offset); if (resource_size(&pcie->realio) != 0)
pci_add_resource_offset(&sys->resources, &pcie->realio,
sys->io_offset);
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn); pci_add_resource(&sys->resources, &pcie->busn);
@ -707,9 +733,9 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
* aligned on their size * aligned on their size
*/ */
if (res->flags & IORESOURCE_IO) if (res->flags & IORESOURCE_IO)
return round_up(start, max((resource_size_t)SZ_64K, size)); return round_up(start, max_t(resource_size_t, SZ_64K, size));
else if (res->flags & IORESOURCE_MEM) else if (res->flags & IORESOURCE_MEM)
return round_up(start, max((resource_size_t)SZ_1M, size)); return round_up(start, max_t(resource_size_t, SZ_1M, size));
else else
return start; return start;
} }
@ -757,12 +783,17 @@ static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
#define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF) #define DT_CPUADDR_TO_ATTR(cpuaddr) (((cpuaddr) >> 48) & 0xFF)
static int mvebu_get_tgt_attr(struct device_node *np, int devfn, static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
unsigned long type, int *tgt, int *attr) unsigned long type,
unsigned int *tgt,
unsigned int *attr)
{ {
const int na = 3, ns = 2; const int na = 3, ns = 2;
const __be32 *range; const __be32 *range;
int rlen, nranges, rangesz, pna, i; int rlen, nranges, rangesz, pna, i;
*tgt = -1;
*attr = -1;
range = of_get_property(np, "ranges", &rlen); range = of_get_property(np, "ranges", &rlen);
if (!range) if (!range)
return -EINVAL; return -EINVAL;
@ -832,16 +863,15 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
} }
mvebu_mbus_get_pcie_io_aperture(&pcie->io); mvebu_mbus_get_pcie_io_aperture(&pcie->io);
if (resource_size(&pcie->io) == 0) {
dev_err(&pdev->dev, "invalid I/O aperture size\n");
return -EINVAL;
}
if (resource_size(&pcie->io) != 0) {
pcie->realio.flags = pcie->io.flags; pcie->realio.flags = pcie->io.flags;
pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.start = PCIBIOS_MIN_IO;
pcie->realio.end = min_t(resource_size_t, pcie->realio.end = min_t(resource_size_t,
IO_SPACE_LIMIT, IO_SPACE_LIMIT,
resource_size(&pcie->io)); resource_size(&pcie->io));
} else
pcie->realio = pcie->io;
/* Get the bus range */ /* Get the bus range */
ret = of_pci_parse_bus_range(np, &pcie->busn); ret = of_pci_parse_bus_range(np, &pcie->busn);
@ -900,12 +930,12 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
continue; continue;
} }
ret = mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO, if (resource_size(&pcie->io) != 0)
mvebu_get_tgt_attr(np, port->devfn, IORESOURCE_IO,
&port->io_target, &port->io_attr); &port->io_target, &port->io_attr);
if (ret < 0) { else {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get tgt/attr for io window\n", port->io_target = -1;
port->port, port->lane); port->io_attr = -1;
continue;
} }
port->reset_gpio = of_get_named_gpio_flags(child, port->reset_gpio = of_get_named_gpio_flags(child,
@ -954,14 +984,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
mvebu_pcie_set_local_dev_nr(port, 1); mvebu_pcie_set_local_dev_nr(port, 1);
port->clk = of_clk_get_by_name(child, NULL);
if (IS_ERR(port->clk)) {
dev_err(&pdev->dev, "PCIe%d.%d: cannot get clock\n",
port->port, port->lane);
iounmap(port->base);
continue;
}
port->dn = child; port->dn = child;
spin_lock_init(&port->conf_lock); spin_lock_init(&port->conf_lock);
mvebu_sw_pci_bridge_init(port); mvebu_sw_pci_bridge_init(port);
@ -969,6 +991,10 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
} }
pcie->nports = i; pcie->nports = i;
for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K)
pci_ioremap_io(i, pcie->io.start + i);
mvebu_pcie_msi_enable(pcie); mvebu_pcie_msi_enable(pcie);
mvebu_pcie_enable(pcie); mvebu_pcie_enable(pcie);
@ -988,8 +1014,7 @@ static struct platform_driver mvebu_pcie_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "mvebu-pcie", .name = "mvebu-pcie",
.of_match_table = .of_match_table = mvebu_pcie_of_match_table,
of_match_ptr(mvebu_pcie_of_match_table),
/* driver unloading/unbinding currently not supported */ /* driver unloading/unbinding currently not supported */
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
}, },

View file

@ -17,6 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
/* AHB-PCI Bridge PCI communication registers */ /* AHB-PCI Bridge PCI communication registers */
@ -77,6 +78,7 @@
#define RCAR_PCI_NR_CONTROLLERS 3 #define RCAR_PCI_NR_CONTROLLERS 3
struct rcar_pci_priv { struct rcar_pci_priv {
struct device *dev;
void __iomem *reg; void __iomem *reg;
struct resource io_res; struct resource io_res;
struct resource mem_res; struct resource mem_res;
@ -169,8 +171,11 @@ static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
void __iomem *reg = priv->reg; void __iomem *reg = priv->reg;
u32 val; u32 val;
pm_runtime_enable(priv->dev);
pm_runtime_get_sync(priv->dev);
val = ioread32(reg + RCAR_PCI_UNIT_REV_REG); val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
pr_info("PCI: bus%u revision %x\n", sys->busnr, val); dev_info(priv->dev, "PCI: bus%u revision %x\n", sys->busnr, val);
/* Disable Direct Power Down State and assert reset */ /* Disable Direct Power Down State and assert reset */
val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD; val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
@ -276,8 +281,8 @@ static int __init rcar_pci_probe(struct platform_device *pdev)
cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(&pdev->dev, cfg_res); reg = devm_ioremap_resource(&pdev->dev, cfg_res);
if (!reg) if (IS_ERR(reg))
return -ENODEV; return PTR_ERR(reg);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!mem_res || !mem_res->start) if (!mem_res || !mem_res->start)
@ -301,6 +306,7 @@ static int __init rcar_pci_probe(struct platform_device *pdev)
priv->irq = platform_get_irq(pdev, 0); priv->irq = platform_get_irq(pdev, 0);
priv->reg = reg; priv->reg = reg;
priv->dev = &pdev->dev;
return rcar_pci_add_controller(priv); return rcar_pci_add_controller(priv);
} }

View file

@ -805,7 +805,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
afi_writel(pcie, value, AFI_PCIE_CONFIG); afi_writel(pcie, value, AFI_PCIE_CONFIG);
value = afi_readl(pcie, AFI_FUSE); value = afi_readl(pcie, AFI_FUSE);
value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS; value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE); afi_writel(pcie, value, AFI_FUSE);
/* initialize internal PHY, enable up to 16 PCIE lanes */ /* initialize internal PHY, enable up to 16 PCIE lanes */

View file

@ -74,7 +74,7 @@ static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
return sys->private_data; return sys->private_data;
} }
int cfg_read(void __iomem *addr, int where, int size, u32 *val) int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val)
{ {
*val = readl(addr); *val = readl(addr);
@ -88,7 +88,7 @@ int cfg_read(void __iomem *addr, int where, int size, u32 *val)
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
} }
int cfg_write(void __iomem *addr, int where, int size, u32 val) int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val)
{ {
if (size == 4) if (size == 4)
writel(val, addr); writel(val, addr);
@ -126,7 +126,8 @@ static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
if (pp->ops->rd_own_conf) if (pp->ops->rd_own_conf)
ret = pp->ops->rd_own_conf(pp, where, size, val); ret = pp->ops->rd_own_conf(pp, where, size, val);
else else
ret = cfg_read(pp->dbi_base + (where & ~0x3), where, size, val); ret = dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
size, val);
return ret; return ret;
} }
@ -139,8 +140,8 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
if (pp->ops->wr_own_conf) if (pp->ops->wr_own_conf)
ret = pp->ops->wr_own_conf(pp, where, size, val); ret = pp->ops->wr_own_conf(pp, where, size, val);
else else
ret = cfg_write(pp->dbi_base + (where & ~0x3), where, size, ret = dw_pcie_cfg_write(pp->dbi_base + (where & ~0x3), where,
val); size, val);
return ret; return ret;
} }
@ -167,11 +168,13 @@ void dw_handle_msi_irq(struct pcie_port *pp)
while ((pos = find_next_bit(&val, 32, pos)) != 32) { while ((pos = find_next_bit(&val, 32, pos)) != 32) {
irq = irq_find_mapping(pp->irq_domain, irq = irq_find_mapping(pp->irq_domain,
i * 32 + pos); i * 32 + pos);
dw_pcie_wr_own_conf(pp,
PCIE_MSI_INTR0_STATUS + i * 12,
4, 1 << pos);
generic_handle_irq(irq); generic_handle_irq(irq);
pos++; pos++;
} }
} }
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
} }
} }
@ -209,6 +212,23 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
return 0; return 0;
} }
static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
unsigned int nvec, unsigned int pos)
{
unsigned int i, res, bit, val;
for (i = 0; i < nvec; i++) {
irq_set_msi_desc_off(irq_base, i, NULL);
clear_bit(pos + i, pp->msi_irq_in_use);
/* Disable corresponding interrupt on MSI controller */
res = ((pos + i) / 32) * 12;
bit = (pos + i) % 32;
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
val &= ~(1 << bit);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
}
}
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
{ {
int res, bit, irq, pos0, pos1, i; int res, bit, irq, pos0, pos1, i;
@ -242,18 +262,25 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
if (!irq) if (!irq)
goto no_valid_irq; goto no_valid_irq;
i = 0; /*
while (i < no_irqs) { * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
* descs so there is no need to allocate descs here. We can therefore
* assume that if irq_find_mapping above returns non-zero, then the
* descs are also successfully allocated.
*/
for (i = 0; i < no_irqs; i++) {
if (irq_set_msi_desc_off(irq, i, desc) != 0) {
clear_irq_range(pp, irq, i, pos0);
goto no_valid_irq;
}
set_bit(pos0 + i, pp->msi_irq_in_use); set_bit(pos0 + i, pp->msi_irq_in_use);
irq_alloc_descs((irq + i), (irq + i), 1, 0);
irq_set_msi_desc(irq + i, desc);
/*Enable corresponding interrupt in MSI interrupt controller */ /*Enable corresponding interrupt in MSI interrupt controller */
res = ((pos0 + i) / 32) * 12; res = ((pos0 + i) / 32) * 12;
bit = (pos0 + i) % 32; bit = (pos0 + i) % 32;
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val); dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
val |= 1 << bit; val |= 1 << bit;
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val); dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
i++;
} }
*pos = pos0; *pos = pos0;
@ -266,7 +293,7 @@ no_valid_irq:
static void clear_irq(unsigned int irq) static void clear_irq(unsigned int irq)
{ {
int res, bit, val, pos; unsigned int pos, nvec;
struct irq_desc *desc; struct irq_desc *desc;
struct msi_desc *msi; struct msi_desc *msi;
struct pcie_port *pp; struct pcie_port *pp;
@ -281,18 +308,15 @@ static void clear_irq(unsigned int irq)
return; return;
} }
/* undo what was done in assign_irq */
pos = data->hwirq; pos = data->hwirq;
nvec = 1 << msi->msi_attrib.multiple;
irq_free_desc(irq); clear_irq_range(pp, irq, nvec, pos);
clear_bit(pos, pp->msi_irq_in_use); /* all irqs cleared; reset attributes */
msi->irq = 0;
/* Disable corresponding interrupt on MSI interrupt controller */ msi->msi_attrib.multiple = 0;
res = (pos / 32) * 12;
bit = pos % 32;
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
val &= ~(1 << bit);
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
} }
static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
@ -320,10 +344,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
if (irq < 0) if (irq < 0)
return irq; return irq;
msg_ctr &= ~PCI_MSI_FLAGS_QSIZE; /*
msg_ctr |= msgvec << 4; * write_msi_msg() will update PCI_MSI_FLAGS so there is
pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, * no need to explicitly call pci_write_config_word().
msg_ctr); */
desc->msi_attrib.multiple = msgvec; desc->msi_attrib.multiple = msgvec;
msg.address_lo = virt_to_phys((void *)pp->msi_data); msg.address_lo = virt_to_phys((void *)pp->msi_data);
@ -394,6 +418,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
+ global_io_offset); + global_io_offset);
pp->config.io_size = resource_size(&pp->io); pp->config.io_size = resource_size(&pp->io);
pp->config.io_bus_addr = range.pci_addr; pp->config.io_bus_addr = range.pci_addr;
pp->io_base = range.cpu_addr;
} }
if (restype == IORESOURCE_MEM) { if (restype == IORESOURCE_MEM) {
of_pci_range_to_resource(&range, np, &pp->mem); of_pci_range_to_resource(&range, np, &pp->mem);
@ -419,7 +444,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
pp->cfg0_base = pp->cfg.start; pp->cfg0_base = pp->cfg.start;
pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size; pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
pp->io_base = pp->io.start;
pp->mem_base = pp->mem.start; pp->mem_base = pp->mem.start;
pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base, pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
@ -551,11 +575,13 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
if (bus->parent->number == pp->root_bus_nr) { if (bus->parent->number == pp->root_bus_nr) {
dw_pcie_prog_viewport_cfg0(pp, busdev); dw_pcie_prog_viewport_cfg0(pp, busdev);
ret = cfg_read(pp->va_cfg0_base + address, where, size, val); ret = dw_pcie_cfg_read(pp->va_cfg0_base + address, where, size,
val);
dw_pcie_prog_viewport_mem_outbound(pp); dw_pcie_prog_viewport_mem_outbound(pp);
} else { } else {
dw_pcie_prog_viewport_cfg1(pp, busdev); dw_pcie_prog_viewport_cfg1(pp, busdev);
ret = cfg_read(pp->va_cfg1_base + address, where, size, val); ret = dw_pcie_cfg_read(pp->va_cfg1_base + address, where, size,
val);
dw_pcie_prog_viewport_io_outbound(pp); dw_pcie_prog_viewport_io_outbound(pp);
} }
@ -574,18 +600,19 @@ static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
if (bus->parent->number == pp->root_bus_nr) { if (bus->parent->number == pp->root_bus_nr) {
dw_pcie_prog_viewport_cfg0(pp, busdev); dw_pcie_prog_viewport_cfg0(pp, busdev);
ret = cfg_write(pp->va_cfg0_base + address, where, size, val); ret = dw_pcie_cfg_write(pp->va_cfg0_base + address, where, size,
val);
dw_pcie_prog_viewport_mem_outbound(pp); dw_pcie_prog_viewport_mem_outbound(pp);
} else { } else {
dw_pcie_prog_viewport_cfg1(pp, busdev); dw_pcie_prog_viewport_cfg1(pp, busdev);
ret = cfg_write(pp->va_cfg1_base + address, where, size, val); ret = dw_pcie_cfg_write(pp->va_cfg1_base + address, where, size,
val);
dw_pcie_prog_viewport_io_outbound(pp); dw_pcie_prog_viewport_io_outbound(pp);
} }
return ret; return ret;
} }
static int dw_pcie_valid_config(struct pcie_port *pp, static int dw_pcie_valid_config(struct pcie_port *pp,
struct pci_bus *bus, int dev) struct pci_bus *bus, int dev)
{ {
@ -679,7 +706,7 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
if (global_io_offset < SZ_1M && pp->config.io_size > 0) { if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
sys->io_offset = global_io_offset - pp->config.io_bus_addr; sys->io_offset = global_io_offset - pp->config.io_bus_addr;
pci_ioremap_io(sys->io_offset, pp->io.start); pci_ioremap_io(global_io_offset, pp->io_base);
global_io_offset += SZ_64K; global_io_offset += SZ_64K;
pci_add_resource_offset(&sys->resources, &pp->io, pci_add_resource_offset(&sys->resources, &pp->io,
sys->io_offset); sys->io_offset);

View file

@ -66,8 +66,8 @@ struct pcie_host_ops {
void (*host_init)(struct pcie_port *pp); void (*host_init)(struct pcie_port *pp);
}; };
int cfg_read(void __iomem *addr, int where, int size, u32 *val); int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
int cfg_write(void __iomem *addr, int where, int size, u32 val); int dw_pcie_cfg_write(void __iomem *addr, int where, int size, u32 val);
void dw_handle_msi_irq(struct pcie_port *pp); void dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp); void dw_pcie_msi_init(struct pcie_port *pp);
int dw_pcie_link_up(struct pcie_port *pp); int dw_pcie_link_up(struct pcie_port *pp);

View file

@ -77,6 +77,8 @@ struct acpiphp_bridge {
/* PCI-to-PCI bridge device */ /* PCI-to-PCI bridge device */
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
bool is_going_away;
}; };
@ -150,6 +152,7 @@ struct acpiphp_attention_info
/* slot flags */ /* slot flags */
#define SLOT_ENABLED (0x00000001) #define SLOT_ENABLED (0x00000001)
#define SLOT_IS_GOING_AWAY (0x00000002)
/* function flags */ /* function flags */
@ -169,7 +172,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot);
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
int acpiphp_enable_slot(struct acpiphp_slot *slot); int acpiphp_enable_slot(struct acpiphp_slot *slot);
int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot); int acpiphp_disable_slot(struct acpiphp_slot *slot);
u8 acpiphp_get_power_status(struct acpiphp_slot *slot); u8 acpiphp_get_power_status(struct acpiphp_slot *slot);
u8 acpiphp_get_attention_status(struct acpiphp_slot *slot); u8 acpiphp_get_attention_status(struct acpiphp_slot *slot);
u8 acpiphp_get_latch_status(struct acpiphp_slot *slot); u8 acpiphp_get_latch_status(struct acpiphp_slot *slot);

View file

@ -156,7 +156,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot)); pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
/* disable the specified slot */ /* disable the specified slot */
return acpiphp_disable_and_eject_slot(slot->acpi_slot); return acpiphp_disable_slot(slot->acpi_slot);
} }

View file

@ -432,6 +432,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
pr_err("failed to remove notify handler\n"); pr_err("failed to remove notify handler\n");
} }
} }
slot->flags |= SLOT_IS_GOING_AWAY;
if (slot->slot) if (slot->slot)
acpiphp_unregister_hotplug_slot(slot); acpiphp_unregister_hotplug_slot(slot);
} }
@ -439,6 +440,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
mutex_lock(&bridge_mutex); mutex_lock(&bridge_mutex);
list_del(&bridge->list); list_del(&bridge->list);
mutex_unlock(&bridge_mutex); mutex_unlock(&bridge_mutex);
bridge->is_going_away = true;
} }
/** /**
@ -757,6 +760,10 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
{ {
struct acpiphp_slot *slot; struct acpiphp_slot *slot;
/* Bail out if the bridge is going away. */
if (bridge->is_going_away)
return;
list_for_each_entry(slot, &bridge->slots, node) { list_for_each_entry(slot, &bridge->slots, node) {
struct pci_bus *bus = slot->bus; struct pci_bus *bus = slot->bus;
struct pci_dev *dev, *tmp; struct pci_dev *dev, *tmp;
@ -827,6 +834,8 @@ void acpiphp_check_host_bridge(acpi_handle handle)
} }
} }
static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot);
static void hotplug_event(acpi_handle handle, u32 type, void *data) static void hotplug_event(acpi_handle handle, u32 type, void *data)
{ {
struct acpiphp_context *context = data; struct acpiphp_context *context = data;
@ -856,6 +865,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
} else { } else {
struct acpiphp_slot *slot = func->slot; struct acpiphp_slot *slot = func->slot;
if (slot->flags & SLOT_IS_GOING_AWAY)
break;
mutex_lock(&slot->crit_sect); mutex_lock(&slot->crit_sect);
enable_slot(slot); enable_slot(slot);
mutex_unlock(&slot->crit_sect); mutex_unlock(&slot->crit_sect);
@ -871,6 +883,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
struct acpiphp_slot *slot = func->slot; struct acpiphp_slot *slot = func->slot;
int ret; int ret;
if (slot->flags & SLOT_IS_GOING_AWAY)
break;
/* /*
* Check if anything has changed in the slot and rescan * Check if anything has changed in the slot and rescan
* from the parent if that's the case. * from the parent if that's the case.
@ -900,9 +915,11 @@ static void hotplug_event_work(void *data, u32 type)
acpi_handle handle = context->handle; acpi_handle handle = context->handle;
acpi_scan_lock_acquire(); acpi_scan_lock_acquire();
pci_lock_rescan_remove();
hotplug_event(handle, type, context); hotplug_event(handle, type, context);
pci_unlock_rescan_remove();
acpi_scan_lock_release(); acpi_scan_lock_release();
acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL); acpi_evaluate_hotplug_ost(handle, type, ACPI_OST_SC_SUCCESS, NULL);
put_bridge(context->func.parent); put_bridge(context->func.parent);
@ -1070,12 +1087,19 @@ void acpiphp_remove_slots(struct pci_bus *bus)
*/ */
int acpiphp_enable_slot(struct acpiphp_slot *slot) int acpiphp_enable_slot(struct acpiphp_slot *slot)
{ {
pci_lock_rescan_remove();
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
mutex_lock(&slot->crit_sect); mutex_lock(&slot->crit_sect);
/* configure all functions */ /* configure all functions */
if (!(slot->flags & SLOT_ENABLED)) if (!(slot->flags & SLOT_ENABLED))
enable_slot(slot); enable_slot(slot);
mutex_unlock(&slot->crit_sect); mutex_unlock(&slot->crit_sect);
pci_unlock_rescan_remove();
return 0; return 0;
} }
@ -1083,10 +1107,12 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
* acpiphp_disable_and_eject_slot - power off and eject slot * acpiphp_disable_and_eject_slot - power off and eject slot
* @slot: ACPI PHP slot * @slot: ACPI PHP slot
*/ */
int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot) static int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
{ {
struct acpiphp_func *func; struct acpiphp_func *func;
int retval = 0;
if (slot->flags & SLOT_IS_GOING_AWAY)
return -ENODEV;
mutex_lock(&slot->crit_sect); mutex_lock(&slot->crit_sect);
@ -1104,9 +1130,18 @@ int acpiphp_disable_and_eject_slot(struct acpiphp_slot *slot)
} }
mutex_unlock(&slot->crit_sect); mutex_unlock(&slot->crit_sect);
return retval; return 0;
} }
int acpiphp_disable_slot(struct acpiphp_slot *slot)
{
int ret;
pci_lock_rescan_remove();
ret = acpiphp_disable_and_eject_slot(slot);
pci_unlock_rescan_remove();
return ret;
}
/* /*
* slot enabled: 1 * slot enabled: 1
@ -1117,7 +1152,6 @@ u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
return (slot->flags & SLOT_ENABLED); return (slot->flags & SLOT_ENABLED);
} }
/* /*
* latch open: 1 * latch open: 1
* latch closed: 0 * latch closed: 0
@ -1127,7 +1161,6 @@ u8 acpiphp_get_latch_status(struct acpiphp_slot *slot)
return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI); return !(get_slot_status(slot) & ACPI_STA_DEVICE_UI);
} }
/* /*
* adapter presence : 1 * adapter presence : 1
* absence : 0 * absence : 0

View file

@ -254,9 +254,12 @@ int __ref cpci_configure_slot(struct slot *slot)
{ {
struct pci_dev *dev; struct pci_dev *dev;
struct pci_bus *parent; struct pci_bus *parent;
int ret = 0;
dbg("%s - enter", __func__); dbg("%s - enter", __func__);
pci_lock_rescan_remove();
if (slot->dev == NULL) { if (slot->dev == NULL) {
dbg("pci_dev null, finding %02x:%02x:%x", dbg("pci_dev null, finding %02x:%02x:%x",
slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
@ -277,7 +280,8 @@ int __ref cpci_configure_slot(struct slot *slot)
slot->dev = pci_get_slot(slot->bus, slot->devfn); slot->dev = pci_get_slot(slot->bus, slot->devfn);
if (slot->dev == NULL) { if (slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number); err("Could not find PCI device for slot %02x", slot->number);
return -ENODEV; ret = -ENODEV;
goto out;
} }
} }
parent = slot->dev->bus; parent = slot->dev->bus;
@ -294,8 +298,10 @@ int __ref cpci_configure_slot(struct slot *slot)
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
out:
pci_unlock_rescan_remove();
dbg("%s - exit", __func__); dbg("%s - exit", __func__);
return 0; return ret;
} }
int cpci_unconfigure_slot(struct slot* slot) int cpci_unconfigure_slot(struct slot* slot)
@ -308,6 +314,8 @@ int cpci_unconfigure_slot(struct slot* slot)
return -ENODEV; return -ENODEV;
} }
pci_lock_rescan_remove();
list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) { list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn))
continue; continue;
@ -318,6 +326,8 @@ int cpci_unconfigure_slot(struct slot* slot)
pci_dev_put(slot->dev); pci_dev_put(slot->dev);
slot->dev = NULL; slot->dev = NULL;
pci_unlock_rescan_remove();
dbg("%s - exit", __func__); dbg("%s - exit", __func__);
return 0; return 0;
} }

View file

@ -86,6 +86,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
struct pci_bus *child; struct pci_bus *child;
int num; int num;
pci_lock_rescan_remove();
if (func->pci_dev == NULL) if (func->pci_dev == NULL)
func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function));
@ -100,7 +102,7 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
if (func->pci_dev == NULL) { if (func->pci_dev == NULL) {
dbg("ERROR: pci_dev still null\n"); dbg("ERROR: pci_dev still null\n");
return 0; goto out;
} }
} }
@ -113,6 +115,8 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
pci_dev_put(func->pci_dev); pci_dev_put(func->pci_dev);
out:
pci_unlock_rescan_remove();
return 0; return 0;
} }
@ -123,6 +127,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function);
pci_lock_rescan_remove();
for (j=0; j<8 ; j++) { for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
if (temp) { if (temp) {
@ -130,6 +135,7 @@ int cpqhp_unconfigure_device(struct pci_func* func)
pci_stop_and_remove_bus_device(temp); pci_stop_and_remove_bus_device(temp);
} }
} }
pci_unlock_rescan_remove();
return 0; return 0;
} }

View file

@ -718,6 +718,8 @@ static void ibm_unconfigure_device(struct pci_func *func)
func->device, func->function); func->device, func->function);
debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); debug("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0);
pci_lock_rescan_remove();
for (j = 0; j < 0x08; j++) { for (j = 0; j < 0x08; j++) {
temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j); temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
if (temp) { if (temp) {
@ -725,7 +727,10 @@ static void ibm_unconfigure_device(struct pci_func *func)
pci_dev_put(temp); pci_dev_put(temp);
} }
} }
pci_dev_put(func->dev); pci_dev_put(func->dev);
pci_unlock_rescan_remove();
} }
/* /*
@ -780,6 +785,8 @@ static int ibm_configure_device(struct pci_func *func)
int flag = 0; /* this is to make sure we don't double scan the bus, int flag = 0; /* this is to make sure we don't double scan the bus,
for bridged devices primarily */ for bridged devices primarily */
pci_lock_rescan_remove();
if (!(bus_structure_fixup(func->busno))) if (!(bus_structure_fixup(func->busno)))
flag = 1; flag = 1;
if (func->dev == NULL) if (func->dev == NULL)
@ -789,7 +796,7 @@ static int ibm_configure_device(struct pci_func *func)
if (func->dev == NULL) { if (func->dev == NULL) {
struct pci_bus *bus = pci_find_bus(0, func->busno); struct pci_bus *bus = pci_find_bus(0, func->busno);
if (!bus) if (!bus)
return 0; goto out;
num = pci_scan_slot(bus, num = pci_scan_slot(bus,
PCI_DEVFN(func->device, func->function)); PCI_DEVFN(func->device, func->function));
@ -800,7 +807,7 @@ static int ibm_configure_device(struct pci_func *func)
PCI_DEVFN(func->device, func->function)); PCI_DEVFN(func->device, func->function));
if (func->dev == NULL) { if (func->dev == NULL) {
err("ERROR... : pci_dev still NULL\n"); err("ERROR... : pci_dev still NULL\n");
return 0; goto out;
} }
} }
if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
@ -810,6 +817,8 @@ static int ibm_configure_device(struct pci_func *func)
pci_bus_add_devices(child); pci_bus_add_devices(child);
} }
out:
pci_unlock_rescan_remove();
return 0; return 0;
} }

View file

@ -43,7 +43,6 @@
extern bool pciehp_poll_mode; extern bool pciehp_poll_mode;
extern int pciehp_poll_time; extern int pciehp_poll_time;
extern bool pciehp_debug; extern bool pciehp_debug;
extern bool pciehp_force;
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
@ -140,15 +139,15 @@ struct controller *pcie_init(struct pcie_device *dev);
int pcie_init_notification(struct controller *ctrl); int pcie_init_notification(struct controller *ctrl);
int pciehp_enable_slot(struct slot *p_slot); int pciehp_enable_slot(struct slot *p_slot);
int pciehp_disable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot);
int pcie_enable_notification(struct controller *ctrl); void pcie_enable_notification(struct controller *ctrl);
int pciehp_power_on_slot(struct slot *slot); int pciehp_power_on_slot(struct slot *slot);
int pciehp_power_off_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot);
int pciehp_get_power_status(struct slot *slot, u8 *status); void pciehp_get_power_status(struct slot *slot, u8 *status);
int pciehp_get_attention_status(struct slot *slot, u8 *status); void pciehp_get_attention_status(struct slot *slot, u8 *status);
int pciehp_set_attention_status(struct slot *slot, u8 status); void pciehp_set_attention_status(struct slot *slot, u8 status);
int pciehp_get_latch_status(struct slot *slot, u8 *status); void pciehp_get_latch_status(struct slot *slot, u8 *status);
int pciehp_get_adapter_status(struct slot *slot, u8 *status); void pciehp_get_adapter_status(struct slot *slot, u8 *status);
int pciehp_query_power_fault(struct slot *slot); int pciehp_query_power_fault(struct slot *slot);
void pciehp_green_led_on(struct slot *slot); void pciehp_green_led_on(struct slot *slot);
void pciehp_green_led_off(struct slot *slot); void pciehp_green_led_off(struct slot *slot);

View file

@ -41,7 +41,7 @@
bool pciehp_debug; bool pciehp_debug;
bool pciehp_poll_mode; bool pciehp_poll_mode;
int pciehp_poll_time; int pciehp_poll_time;
bool pciehp_force; static bool pciehp_force;
#define DRIVER_VERSION "0.4" #define DRIVER_VERSION "0.4"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@ -160,7 +160,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
return pciehp_set_attention_status(slot, status); pciehp_set_attention_status(slot, status);
return 0;
} }
@ -192,7 +193,8 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
return pciehp_get_power_status(slot, value); pciehp_get_power_status(slot, value);
return 0;
} }
static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
@ -202,7 +204,8 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
return pciehp_get_attention_status(slot, value); pciehp_get_attention_status(slot, value);
return 0;
} }
static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
@ -212,7 +215,8 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
return pciehp_get_latch_status(slot, value); pciehp_get_latch_status(slot, value);
return 0;
} }
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
@ -222,7 +226,8 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
return pciehp_get_adapter_status(slot, value); pciehp_get_adapter_status(slot, value);
return 0;
} }
static int reset_slot(struct hotplug_slot *hotplug_slot, int probe) static int reset_slot(struct hotplug_slot *hotplug_slot, int probe)

View file

@ -158,11 +158,8 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{ {
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/ /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl)) { if (POWER_CTRL(ctrl)) {
if (pciehp_power_off_slot(pslot)) { pciehp_power_off_slot(pslot);
ctrl_err(ctrl,
"Issue of Slot Power Off command failed\n");
return;
}
/* /*
* After turning power off, we must wait for at least 1 second * After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been * before taking any action that relies on power having been
@ -171,16 +168,8 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
msleep(1000); msleep(1000);
} }
if (PWR_LED(ctrl))
pciehp_green_led_off(pslot); pciehp_green_led_off(pslot);
pciehp_set_attention_status(pslot, 1);
if (ATTN_LED(ctrl)) {
if (pciehp_set_attention_status(pslot, 1)) {
ctrl_err(ctrl,
"Issue of Set Attention Led command failed\n");
return;
}
}
} }
/** /**
@ -203,7 +192,6 @@ static int board_added(struct slot *p_slot)
return retval; return retval;
} }
if (PWR_LED(ctrl))
pciehp_green_led_blink(p_slot); pciehp_green_led_blink(p_slot);
/* Check link training status */ /* Check link training status */
@ -227,9 +215,7 @@ static int board_added(struct slot *p_slot)
goto err_exit; goto err_exit;
} }
if (PWR_LED(ctrl))
pciehp_green_led_on(p_slot); pciehp_green_led_on(p_slot);
return 0; return 0;
err_exit: err_exit:
@ -243,7 +229,7 @@ err_exit:
*/ */
static int remove_board(struct slot *p_slot) static int remove_board(struct slot *p_slot)
{ {
int retval = 0; int retval;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
retval = pciehp_unconfigure_device(p_slot); retval = pciehp_unconfigure_device(p_slot);
@ -251,13 +237,8 @@ static int remove_board(struct slot *p_slot)
return retval; return retval;
if (POWER_CTRL(ctrl)) { if (POWER_CTRL(ctrl)) {
/* power off slot */ pciehp_power_off_slot(p_slot);
retval = pciehp_power_off_slot(p_slot);
if (retval) {
ctrl_err(ctrl,
"Issue of Slot Disable command failed\n");
return retval;
}
/* /*
* After turning power off, we must wait for at least 1 second * After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been * before taking any action that relies on power having been
@ -267,9 +248,7 @@ static int remove_board(struct slot *p_slot)
} }
/* turn off Green LED */ /* turn off Green LED */
if (PWR_LED(ctrl))
pciehp_green_led_off(p_slot); pciehp_green_led_off(p_slot);
return 0; return 0;
} }
@ -305,7 +284,7 @@ static void pciehp_power_thread(struct work_struct *work)
break; break;
case POWERON_STATE: case POWERON_STATE:
mutex_unlock(&p_slot->lock); mutex_unlock(&p_slot->lock);
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl)) if (pciehp_enable_slot(p_slot))
pciehp_green_led_off(p_slot); pciehp_green_led_off(p_slot);
mutex_lock(&p_slot->lock); mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE; p_slot->state = STATIC_STATE;
@ -372,11 +351,8 @@ static void handle_button_press_event(struct slot *p_slot)
"press.\n", slot_name(p_slot)); "press.\n", slot_name(p_slot));
} }
/* blink green LED and turn off amber */ /* blink green LED and turn off amber */
if (PWR_LED(ctrl))
pciehp_green_led_blink(p_slot); pciehp_green_led_blink(p_slot);
if (ATTN_LED(ctrl))
pciehp_set_attention_status(p_slot, 0); pciehp_set_attention_status(p_slot, 0);
queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ); queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
break; break;
case BLINKINGOFF_STATE: case BLINKINGOFF_STATE:
@ -389,13 +365,10 @@ static void handle_button_press_event(struct slot *p_slot)
ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
cancel_delayed_work(&p_slot->work); cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE) { if (p_slot->state == BLINKINGOFF_STATE) {
if (PWR_LED(ctrl))
pciehp_green_led_on(p_slot); pciehp_green_led_on(p_slot);
} else { } else {
if (PWR_LED(ctrl))
pciehp_green_led_off(p_slot); pciehp_green_led_off(p_slot);
} }
if (ATTN_LED(ctrl))
pciehp_set_attention_status(p_slot, 0); pciehp_set_attention_status(p_slot, 0);
ctrl_info(ctrl, "PCI slot #%s - action canceled " ctrl_info(ctrl, "PCI slot #%s - action canceled "
"due to button press\n", slot_name(p_slot)); "due to button press\n", slot_name(p_slot));
@ -456,9 +429,7 @@ static void interrupt_event_handler(struct work_struct *work)
case INT_POWER_FAULT: case INT_POWER_FAULT:
if (!POWER_CTRL(ctrl)) if (!POWER_CTRL(ctrl))
break; break;
if (ATTN_LED(ctrl))
pciehp_set_attention_status(p_slot, 1); pciehp_set_attention_status(p_slot, 1);
if (PWR_LED(ctrl))
pciehp_green_led_off(p_slot); pciehp_green_led_off(p_slot);
break; break;
case INT_PRESENCE_ON: case INT_PRESENCE_ON:
@ -482,14 +453,14 @@ int pciehp_enable_slot(struct slot *p_slot)
int rc; int rc;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
rc = pciehp_get_adapter_status(p_slot, &getstatus); pciehp_get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) { if (!getstatus) {
ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot)); ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
return -ENODEV; return -ENODEV;
} }
if (MRL_SENS(p_slot->ctrl)) { if (MRL_SENS(p_slot->ctrl)) {
rc = pciehp_get_latch_status(p_slot, &getstatus); pciehp_get_latch_status(p_slot, &getstatus);
if (rc || getstatus) { if (getstatus) {
ctrl_info(ctrl, "Latch open on slot(%s)\n", ctrl_info(ctrl, "Latch open on slot(%s)\n",
slot_name(p_slot)); slot_name(p_slot));
return -ENODEV; return -ENODEV;
@ -497,8 +468,8 @@ int pciehp_enable_slot(struct slot *p_slot)
} }
if (POWER_CTRL(p_slot->ctrl)) { if (POWER_CTRL(p_slot->ctrl)) {
rc = pciehp_get_power_status(p_slot, &getstatus); pciehp_get_power_status(p_slot, &getstatus);
if (rc || getstatus) { if (getstatus) {
ctrl_info(ctrl, "Already enabled on slot(%s)\n", ctrl_info(ctrl, "Already enabled on slot(%s)\n",
slot_name(p_slot)); slot_name(p_slot));
return -EINVAL; return -EINVAL;
@ -518,15 +489,14 @@ int pciehp_enable_slot(struct slot *p_slot)
int pciehp_disable_slot(struct slot *p_slot) int pciehp_disable_slot(struct slot *p_slot)
{ {
u8 getstatus = 0; u8 getstatus = 0;
int ret = 0;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
if (!p_slot->ctrl) if (!p_slot->ctrl)
return 1; return 1;
if (!HP_SUPR_RM(p_slot->ctrl)) { if (!HP_SUPR_RM(p_slot->ctrl)) {
ret = pciehp_get_adapter_status(p_slot, &getstatus); pciehp_get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) { if (!getstatus) {
ctrl_info(ctrl, "No adapter on slot(%s)\n", ctrl_info(ctrl, "No adapter on slot(%s)\n",
slot_name(p_slot)); slot_name(p_slot));
return -ENODEV; return -ENODEV;
@ -534,8 +504,8 @@ int pciehp_disable_slot(struct slot *p_slot)
} }
if (MRL_SENS(p_slot->ctrl)) { if (MRL_SENS(p_slot->ctrl)) {
ret = pciehp_get_latch_status(p_slot, &getstatus); pciehp_get_latch_status(p_slot, &getstatus);
if (ret || getstatus) { if (getstatus) {
ctrl_info(ctrl, "Latch open on slot(%s)\n", ctrl_info(ctrl, "Latch open on slot(%s)\n",
slot_name(p_slot)); slot_name(p_slot));
return -ENODEV; return -ENODEV;
@ -543,8 +513,8 @@ int pciehp_disable_slot(struct slot *p_slot)
} }
if (POWER_CTRL(p_slot->ctrl)) { if (POWER_CTRL(p_slot->ctrl)) {
ret = pciehp_get_power_status(p_slot, &getstatus); pciehp_get_power_status(p_slot, &getstatus);
if (ret || !getstatus) { if (!getstatus) {
ctrl_info(ctrl, "Already disabled on slot(%s)\n", ctrl_info(ctrl, "Already disabled on slot(%s)\n",
slot_name(p_slot)); slot_name(p_slot));
return -EINVAL; return -EINVAL;

View file

@ -41,34 +41,11 @@
#include "../pci.h" #include "../pci.h"
#include "pciehp.h" #include "pciehp.h"
static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) static inline struct pci_dev *ctrl_dev(struct controller *ctrl)
{ {
struct pci_dev *dev = ctrl->pcie->port; return ctrl->pcie->port;
return pcie_capability_read_word(dev, reg, value);
} }
static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
{
struct pci_dev *dev = ctrl->pcie->port;
return pcie_capability_read_dword(dev, reg, value);
}
static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
{
struct pci_dev *dev = ctrl->pcie->port;
return pcie_capability_write_word(dev, reg, value);
}
static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
{
struct pci_dev *dev = ctrl->pcie->port;
return pcie_capability_write_dword(dev, reg, value);
}
/* Power Control Command */
#define POWER_ON 0
#define POWER_OFF PCI_EXP_SLTCTL_PCC
static irqreturn_t pcie_isr(int irq, void *dev_id); static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec); static void start_int_poll_timer(struct controller *ctrl, int sec);
@ -129,20 +106,23 @@ static inline void pciehp_free_irq(struct controller *ctrl)
static int pcie_poll_cmd(struct controller *ctrl) static int pcie_poll_cmd(struct controller *ctrl)
{ {
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status; u16 slot_status;
int err, timeout = 1000; int timeout = 1000;
err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { if (slot_status & PCI_EXP_SLTSTA_CC) {
pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_CC);
return 1; return 1;
} }
while (timeout > 0) { while (timeout > 0) {
msleep(10); msleep(10);
timeout -= 10; timeout -= 10;
err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) { if (slot_status & PCI_EXP_SLTSTA_CC) {
pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC); pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_CC);
return 1; return 1;
} }
} }
@ -169,21 +149,15 @@ static void pcie_wait_cmd(struct controller *ctrl, int poll)
* @cmd: command value written to slot control register * @cmd: command value written to slot control register
* @mask: bitmask of slot control register to be modified * @mask: bitmask of slot control register to be modified
*/ */
static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
{ {
int retval = 0; struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_status; u16 slot_status;
u16 slot_ctrl; u16 slot_ctrl;
mutex_lock(&ctrl->ctrl_lock); mutex_lock(&ctrl->ctrl_lock);
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
goto out;
}
if (slot_status & PCI_EXP_SLTSTA_CC) { if (slot_status & PCI_EXP_SLTSTA_CC) {
if (!ctrl->no_cmd_complete) { if (!ctrl->no_cmd_complete) {
/* /*
@ -207,24 +181,17 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
} }
} }
retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
goto out;
}
slot_ctrl &= ~mask; slot_ctrl &= ~mask;
slot_ctrl |= (cmd & mask); slot_ctrl |= (cmd & mask);
ctrl->cmd_busy = 1; ctrl->cmd_busy = 1;
smp_mb(); smp_mb();
retval = pciehp_writew(ctrl, PCI_EXP_SLTCTL, slot_ctrl); pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl);
if (retval)
ctrl_err(ctrl, "Cannot write to SLOTCTRL register\n");
/* /*
* Wait for command completion. * Wait for command completion.
*/ */
if (!retval && !ctrl->no_cmd_complete) { if (!ctrl->no_cmd_complete) {
int poll = 0; int poll = 0;
/* /*
* if hotplug interrupt is not enabled or command * if hotplug interrupt is not enabled or command
@ -236,19 +203,16 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
poll = 1; poll = 1;
pcie_wait_cmd(ctrl, poll); pcie_wait_cmd(ctrl, poll);
} }
out:
mutex_unlock(&ctrl->ctrl_lock); mutex_unlock(&ctrl->ctrl_lock);
return retval;
} }
static bool check_link_active(struct controller *ctrl) static bool check_link_active(struct controller *ctrl)
{ {
bool ret = false; struct pci_dev *pdev = ctrl_dev(ctrl);
u16 lnk_status; u16 lnk_status;
bool ret;
if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status)) pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
return ret;
ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA); ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
if (ret) if (ret)
@ -311,9 +275,9 @@ static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
int pciehp_check_link_status(struct controller *ctrl) int pciehp_check_link_status(struct controller *ctrl)
{ {
struct pci_dev *pdev = ctrl_dev(ctrl);
bool found;
u16 lnk_status; u16 lnk_status;
int retval = 0;
bool found = false;
/* /*
* Data Link Layer Link Active Reporting must be capable for * Data Link Layer Link Active Reporting must be capable for
@ -330,52 +294,37 @@ int pciehp_check_link_status(struct controller *ctrl)
found = pci_bus_check_dev(ctrl->pcie->port->subordinate, found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
PCI_DEVFN(0, 0)); PCI_DEVFN(0, 0));
retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
ctrl_err(ctrl, "Cannot read LNKSTATUS register\n");
return retval;
}
ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status); ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
if ((lnk_status & PCI_EXP_LNKSTA_LT) || if ((lnk_status & PCI_EXP_LNKSTA_LT) ||
!(lnk_status & PCI_EXP_LNKSTA_NLW)) { !(lnk_status & PCI_EXP_LNKSTA_NLW)) {
ctrl_err(ctrl, "Link Training Error occurs \n"); ctrl_err(ctrl, "Link Training Error occurs \n");
retval = -1; return -1;
return retval;
} }
pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
if (!found && !retval) if (!found)
retval = -1; return -1;
return retval; return 0;
} }
static int __pciehp_link_set(struct controller *ctrl, bool enable) static int __pciehp_link_set(struct controller *ctrl, bool enable)
{ {
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 lnk_ctrl; u16 lnk_ctrl;
int retval = 0;
retval = pciehp_readw(ctrl, PCI_EXP_LNKCTL, &lnk_ctrl); pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &lnk_ctrl);
if (retval) {
ctrl_err(ctrl, "Cannot read LNKCTRL register\n");
return retval;
}
if (enable) if (enable)
lnk_ctrl &= ~PCI_EXP_LNKCTL_LD; lnk_ctrl &= ~PCI_EXP_LNKCTL_LD;
else else
lnk_ctrl |= PCI_EXP_LNKCTL_LD; lnk_ctrl |= PCI_EXP_LNKCTL_LD;
retval = pciehp_writew(ctrl, PCI_EXP_LNKCTL, lnk_ctrl); pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, lnk_ctrl);
if (retval) {
ctrl_err(ctrl, "Cannot write LNKCTRL register\n");
return retval;
}
ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl); ctrl_dbg(ctrl, "%s: lnk_ctrl = %x\n", __func__, lnk_ctrl);
return 0;
return retval;
} }
static int pciehp_link_enable(struct controller *ctrl) static int pciehp_link_enable(struct controller *ctrl)
@ -388,223 +337,165 @@ static int pciehp_link_disable(struct controller *ctrl)
return __pciehp_link_set(ctrl, false); return __pciehp_link_set(ctrl, false);
} }
int pciehp_get_attention_status(struct slot *slot, u8 *status) void pciehp_get_attention_status(struct slot *slot, u8 *status)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_ctrl; u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; switch (slot_ctrl & PCI_EXP_SLTCTL_AIC) {
case PCI_EXP_SLTCTL_ATTN_IND_ON:
switch (atten_led_state) {
case 0:
*status = 0xFF; /* Reserved */
break;
case 1:
*status = 1; /* On */ *status = 1; /* On */
break; break;
case 2: case PCI_EXP_SLTCTL_ATTN_IND_BLINK:
*status = 2; /* Blink */ *status = 2; /* Blink */
break; break;
case 3: case PCI_EXP_SLTCTL_ATTN_IND_OFF:
*status = 0; /* Off */ *status = 0; /* Off */
break; break;
default: default:
*status = 0xFF; *status = 0xFF;
break; break;
} }
return 0;
} }
int pciehp_get_power_status(struct slot *slot, u8 *status) void pciehp_get_power_status(struct slot *slot, u8 *status)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
u16 slot_ctrl; u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; switch (slot_ctrl & PCI_EXP_SLTCTL_PCC) {
case PCI_EXP_SLTCTL_PWR_ON:
switch (pwr_state) { *status = 1; /* On */
case 0:
*status = 1;
break; break;
case 1: case PCI_EXP_SLTCTL_PWR_OFF:
*status = 0; *status = 0; /* Off */
break; break;
default: default:
*status = 0xFF; *status = 0xFF;
break; break;
} }
return retval;
} }
int pciehp_get_latch_status(struct slot *slot, u8 *status) void pciehp_get_latch_status(struct slot *slot, u8 *status)
{ {
struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(slot->ctrl);
u16 slot_status; u16 slot_status;
int retval;
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
return retval;
}
*status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS); *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
return 0;
} }
int pciehp_get_adapter_status(struct slot *slot, u8 *status) void pciehp_get_adapter_status(struct slot *slot, u8 *status)
{ {
struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(slot->ctrl);
u16 slot_status; u16 slot_status;
int retval;
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
return retval;
}
*status = !!(slot_status & PCI_EXP_SLTSTA_PDS); *status = !!(slot_status & PCI_EXP_SLTSTA_PDS);
return 0;
} }
int pciehp_query_power_fault(struct slot *slot) int pciehp_query_power_fault(struct slot *slot)
{ {
struct controller *ctrl = slot->ctrl; struct pci_dev *pdev = ctrl_dev(slot->ctrl);
u16 slot_status; u16 slot_status;
int retval;
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "Cannot check for power fault\n");
return retval;
}
return !!(slot_status & PCI_EXP_SLTSTA_PFD); return !!(slot_status & PCI_EXP_SLTSTA_PFD);
} }
int pciehp_set_attention_status(struct slot *slot, u8 value) void pciehp_set_attention_status(struct slot *slot, u8 value)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd; u16 slot_cmd;
u16 cmd_mask;
cmd_mask = PCI_EXP_SLTCTL_AIC; if (!ATTN_LED(ctrl))
return;
switch (value) { switch (value) {
case 0 : /* turn off */ case 0 : /* turn off */
slot_cmd = 0x00C0; slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF;
break; break;
case 1: /* turn on */ case 1: /* turn on */
slot_cmd = 0x0040; slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON;
break; break;
case 2: /* turn blink */ case 2: /* turn blink */
slot_cmd = 0x0080; slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK;
break; break;
default: default:
return -EINVAL; return;
} }
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
return pcie_write_cmd(ctrl, slot_cmd, cmd_mask); pcie_write_cmd(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
} }
void pciehp_green_led_on(struct slot *slot) void pciehp_green_led_on(struct slot *slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
slot_cmd = 0x0100; if (!PWR_LED(ctrl))
cmd_mask = PCI_EXP_SLTCTL_PIC; return;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON, PCI_EXP_SLTCTL_PIC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_PWR_IND_ON);
} }
void pciehp_green_led_off(struct slot *slot) void pciehp_green_led_off(struct slot *slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
slot_cmd = 0x0300; if (!PWR_LED(ctrl))
cmd_mask = PCI_EXP_SLTCTL_PIC; return;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF, PCI_EXP_SLTCTL_PIC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_PWR_IND_OFF);
} }
void pciehp_green_led_blink(struct slot *slot) void pciehp_green_led_blink(struct slot *slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
slot_cmd = 0x0200; if (!PWR_LED(ctrl))
cmd_mask = PCI_EXP_SLTCTL_PIC; return;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK, PCI_EXP_SLTCTL_PIC);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_PWR_IND_BLINK);
} }
int pciehp_power_on_slot(struct slot * slot) int pciehp_power_on_slot(struct slot * slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd; struct pci_dev *pdev = ctrl_dev(ctrl);
u16 cmd_mask;
u16 slot_status; u16 slot_status;
int retval = 0; int retval;
/* Clear sticky power-fault bit from previous power failures */ /* Clear sticky power-fault bit from previous power failures */
retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
if (retval) { if (slot_status & PCI_EXP_SLTSTA_PFD)
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n", pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
__func__); PCI_EXP_SLTSTA_PFD);
return retval;
}
slot_status &= PCI_EXP_SLTSTA_PFD;
if (slot_status) {
retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status);
if (retval) {
ctrl_err(ctrl,
"%s: Cannot write to SLOTSTATUS register\n",
__func__);
return retval;
}
}
ctrl->power_fault_detected = 0; ctrl->power_fault_detected = 0;
slot_cmd = POWER_ON; pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC);
cmd_mask = PCI_EXP_SLTCTL_PCC;
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
return retval;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
PCI_EXP_SLTCTL_PWR_ON);
retval = pciehp_link_enable(ctrl); retval = pciehp_link_enable(ctrl);
if (retval) if (retval)
@ -613,12 +504,9 @@ int pciehp_power_on_slot(struct slot * slot)
return retval; return retval;
} }
int pciehp_power_off_slot(struct slot * slot) void pciehp_power_off_slot(struct slot * slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
int retval;
/* Disable the link at first */ /* Disable the link at first */
pciehp_link_disable(ctrl); pciehp_link_disable(ctrl);
@ -628,21 +516,16 @@ int pciehp_power_off_slot(struct slot * slot)
else else
msleep(1000); msleep(1000);
slot_cmd = POWER_OFF; pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
cmd_mask = PCI_EXP_SLTCTL_PCC;
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
ctrl_err(ctrl, "Write command failed!\n");
return retval;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
return 0; PCI_EXP_SLTCTL_PWR_OFF);
} }
static irqreturn_t pcie_isr(int irq, void *dev_id) static irqreturn_t pcie_isr(int irq, void *dev_id)
{ {
struct controller *ctrl = (struct controller *)dev_id; struct controller *ctrl = (struct controller *)dev_id;
struct pci_dev *pdev = ctrl_dev(ctrl);
struct slot *slot = ctrl->slot; struct slot *slot = ctrl->slot;
u16 detected, intr_loc; u16 detected, intr_loc;
@ -653,11 +536,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
*/ */
intr_loc = 0; intr_loc = 0;
do { do {
if (pciehp_readw(ctrl, PCI_EXP_SLTSTA, &detected)) { pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &detected);
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n",
__func__);
return IRQ_NONE;
}
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
@ -666,11 +545,9 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
intr_loc |= detected; intr_loc |= detected;
if (!intr_loc) if (!intr_loc)
return IRQ_NONE; return IRQ_NONE;
if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) { if (detected)
ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n", pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
__func__); intr_loc);
return IRQ_NONE;
}
} while (detected); } while (detected);
ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc); ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc);
@ -705,7 +582,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
int pcie_enable_notification(struct controller *ctrl) void pcie_enable_notification(struct controller *ctrl)
{ {
u16 cmd, mask; u16 cmd, mask;
@ -731,22 +608,18 @@ int pcie_enable_notification(struct controller *ctrl)
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
if (pcie_write_cmd(ctrl, cmd, mask)) { pcie_write_cmd(ctrl, cmd, mask);
ctrl_err(ctrl, "Cannot enable software notification\n");
return -1;
}
return 0;
} }
static void pcie_disable_notification(struct controller *ctrl) static void pcie_disable_notification(struct controller *ctrl)
{ {
u16 mask; u16 mask;
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE | PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
PCI_EXP_SLTCTL_DLLSCE); PCI_EXP_SLTCTL_DLLSCE);
if (pcie_write_cmd(ctrl, 0, mask)) pcie_write_cmd(ctrl, 0, mask);
ctrl_warn(ctrl, "Cannot disable software notification\n");
} }
/* /*
@ -758,6 +631,7 @@ static void pcie_disable_notification(struct controller *ctrl)
int pciehp_reset_slot(struct slot *slot, int probe) int pciehp_reset_slot(struct slot *slot, int probe)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
struct pci_dev *pdev = ctrl_dev(ctrl);
if (probe) if (probe)
return 0; return 0;
@ -771,7 +645,8 @@ int pciehp_reset_slot(struct slot *slot, int probe)
pci_reset_bridge_secondary_bus(ctrl->pcie->port); pci_reset_bridge_secondary_bus(ctrl->pcie->port);
if (HP_SUPR_RM(ctrl)) { if (HP_SUPR_RM(ctrl)) {
pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDC); pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDC);
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE); pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
if (pciehp_poll_mode) if (pciehp_poll_mode)
int_poll_timeout(ctrl->poll_timer.data); int_poll_timeout(ctrl->poll_timer.data);
@ -784,10 +659,7 @@ int pcie_init_notification(struct controller *ctrl)
{ {
if (pciehp_request_irq(ctrl)) if (pciehp_request_irq(ctrl))
return -1; return -1;
if (pcie_enable_notification(ctrl)) { pcie_enable_notification(ctrl);
pciehp_free_irq(ctrl);
return -1;
}
ctrl->notification_enabled = 1; ctrl->notification_enabled = 1;
return 0; return 0;
} }
@ -875,12 +747,14 @@ static inline void dbg_ctrl(struct controller *ctrl)
EMI(ctrl) ? "yes" : "no"); EMI(ctrl) ? "yes" : "no");
ctrl_info(ctrl, " Command Completed : %3s\n", ctrl_info(ctrl, " Command Completed : %3s\n",
NO_CMD_CMPL(ctrl) ? "no" : "yes"); NO_CMD_CMPL(ctrl) ? "no" : "yes");
pciehp_readw(ctrl, PCI_EXP_SLTSTA, &reg16); pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &reg16);
ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16); ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16);
pciehp_readw(ctrl, PCI_EXP_SLTCTL, &reg16); pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &reg16);
ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16); ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16);
} }
#define FLAG(x,y) (((x) & (y)) ? '+' : '-')
struct controller *pcie_init(struct pcie_device *dev) struct controller *pcie_init(struct pcie_device *dev)
{ {
struct controller *ctrl; struct controller *ctrl;
@ -893,11 +767,7 @@ struct controller *pcie_init(struct pcie_device *dev)
goto abort; goto abort;
} }
ctrl->pcie = dev; ctrl->pcie = dev;
if (pciehp_readl(ctrl, PCI_EXP_SLTCAP, &slot_cap)) { pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
ctrl_err(ctrl, "Cannot read SLOTCAP register\n");
goto abort_ctrl;
}
ctrl->slot_cap = slot_cap; ctrl->slot_cap = slot_cap;
mutex_init(&ctrl->ctrl_lock); mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue); init_waitqueue_head(&ctrl->queue);
@ -913,25 +783,31 @@ struct controller *pcie_init(struct pcie_device *dev)
ctrl->no_cmd_complete = 1; ctrl->no_cmd_complete = 1;
/* Check if Data Link Layer Link Active Reporting is implemented */ /* Check if Data Link Layer Link Active Reporting is implemented */
if (pciehp_readl(ctrl, PCI_EXP_LNKCAP, &link_cap)) { pcie_capability_read_dword(pdev, PCI_EXP_LNKCAP, &link_cap);
ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
goto abort_ctrl;
}
if (link_cap & PCI_EXP_LNKCAP_DLLLARC) { if (link_cap & PCI_EXP_LNKCAP_DLLLARC) {
ctrl_dbg(ctrl, "Link Active Reporting supported\n"); ctrl_dbg(ctrl, "Link Active Reporting supported\n");
ctrl->link_active_reporting = 1; ctrl->link_active_reporting = 1;
} }
/* Clear all remaining event bits in Slot Status register */ /* Clear all remaining event bits in Slot Status register */
if (pciehp_writew(ctrl, PCI_EXP_SLTSTA, 0x1f)) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
goto abort_ctrl; PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_CC);
/* Disable software notification */ /* Disable software notification */
pcie_disable_notification(ctrl); pcie_disable_notification(ctrl);
ctrl_info(ctrl, "HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", ctrl_info(ctrl, "Slot #%d AttnBtn%c AttnInd%c PwrInd%c PwrCtrl%c MRL%c Interlock%c NoCompl%c LLActRep%c\n",
pdev->vendor, pdev->device, pdev->subsystem_vendor, (slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
pdev->subsystem_device); FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
FLAG(slot_cap, PCI_EXP_SLTCAP_AIP),
FLAG(slot_cap, PCI_EXP_SLTCAP_PIP),
FLAG(slot_cap, PCI_EXP_SLTCAP_PCP),
FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP),
FLAG(slot_cap, PCI_EXP_SLTCAP_EIP),
FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS),
FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC));
if (pcie_init_slot(ctrl)) if (pcie_init_slot(ctrl))
goto abort_ctrl; goto abort_ctrl;

View file

@ -39,22 +39,26 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_dev *dev; struct pci_dev *dev;
struct pci_dev *bridge = p_slot->ctrl->pcie->port; struct pci_dev *bridge = p_slot->ctrl->pcie->port;
struct pci_bus *parent = bridge->subordinate; struct pci_bus *parent = bridge->subordinate;
int num; int num, ret = 0;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
pci_lock_rescan_remove();
dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
if (dev) { if (dev) {
ctrl_err(ctrl, "Device %s already exists " ctrl_err(ctrl, "Device %s already exists "
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev), "at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
pci_domain_nr(parent), parent->number); pci_domain_nr(parent), parent->number);
pci_dev_put(dev); pci_dev_put(dev);
return -EINVAL; ret = -EINVAL;
goto out;
} }
num = pci_scan_slot(parent, PCI_DEVFN(0, 0)); num = pci_scan_slot(parent, PCI_DEVFN(0, 0));
if (num == 0) { if (num == 0) {
ctrl_err(ctrl, "No new device found\n"); ctrl_err(ctrl, "No new device found\n");
return -ENODEV; ret = -ENODEV;
goto out;
} }
list_for_each_entry(dev, &parent->devices, bus_list) list_for_each_entry(dev, &parent->devices, bus_list)
@ -73,12 +77,14 @@ int pciehp_configure_device(struct slot *p_slot)
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
return 0; out:
pci_unlock_rescan_remove();
return ret;
} }
int pciehp_unconfigure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot)
{ {
int ret, rc = 0; int rc = 0;
u8 bctl = 0; u8 bctl = 0;
u8 presence = 0; u8 presence = 0;
struct pci_dev *dev, *temp; struct pci_dev *dev, *temp;
@ -88,9 +94,9 @@ int pciehp_unconfigure_device(struct slot *p_slot)
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n", ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:00\n",
__func__, pci_domain_nr(parent), parent->number); __func__, pci_domain_nr(parent), parent->number);
ret = pciehp_get_adapter_status(p_slot, &presence); pciehp_get_adapter_status(p_slot, &presence);
if (ret)
presence = 0; pci_lock_rescan_remove();
/* /*
* Stopping an SR-IOV PF device removes all the associated VFs, * Stopping an SR-IOV PF device removes all the associated VFs,
@ -126,5 +132,6 @@ int pciehp_unconfigure_device(struct slot *p_slot)
pci_dev_put(dev); pci_dev_put(dev);
} }
pci_unlock_rescan_remove();
return rc; return rc;
} }

View file

@ -354,10 +354,15 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
{ {
struct pci_bus *bus; struct pci_bus *bus;
struct slot *slot; struct slot *slot;
int ret = 0;
pci_lock_rescan_remove();
bus = pcibios_find_pci_bus(dn); bus = pcibios_find_pci_bus(dn);
if (!bus) if (!bus) {
return -EINVAL; ret = -EINVAL;
goto out;
}
pr_debug("PCI: Removing PCI slot below EADS bridge %s\n", pr_debug("PCI: Removing PCI slot below EADS bridge %s\n",
bus->self ? pci_name(bus->self) : "<!PHB!>"); bus->self ? pci_name(bus->self) : "<!PHB!>");
@ -371,7 +376,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
printk(KERN_ERR printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n", "%s: unable to remove hotplug slot %s\n",
__func__, drc_name); __func__, drc_name);
return -EIO; ret = -EIO;
goto out;
} }
} }
@ -382,7 +388,8 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
if (pcibios_unmap_io_space(bus)) { if (pcibios_unmap_io_space(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n", printk(KERN_ERR "%s: failed to unmap bus range\n",
__func__); __func__);
return -ERANGE; ret = -ERANGE;
goto out;
} }
/* Remove the EADS bridge device itself */ /* Remove the EADS bridge device itself */
@ -390,7 +397,9 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self)); pr_debug("PCI: Now removing bridge device %s\n", pci_name(bus->self));
pci_stop_and_remove_bus_device(bus->self); pci_stop_and_remove_bus_device(bus->self);
return 0; out:
pci_unlock_rescan_remove();
return ret;
} }
/** /**

View file

@ -398,7 +398,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return retval; return retval;
if (state == PRESENT) { if (state == PRESENT) {
pci_lock_rescan_remove();
pcibios_add_pci_devices(slot->bus); pcibios_add_pci_devices(slot->bus);
pci_unlock_rescan_remove();
slot->state = CONFIGURED; slot->state = CONFIGURED;
} else if (state == EMPTY) { } else if (state == EMPTY) {
slot->state = EMPTY; slot->state = EMPTY;
@ -418,7 +420,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
if (slot->state == NOT_CONFIGURED) if (slot->state == NOT_CONFIGURED)
return -EINVAL; return -EINVAL;
pci_lock_rescan_remove();
pcibios_remove_pci_devices(slot->bus); pcibios_remove_pci_devices(slot->bus);
pci_unlock_rescan_remove();
vm_unmap_aliases(); vm_unmap_aliases();
slot->state = NOT_CONFIGURED; slot->state = NOT_CONFIGURED;

View file

@ -80,7 +80,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
goto out_deconfigure; goto out_deconfigure;
pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN); pci_scan_slot(slot->zdev->bus, ZPCI_DEVFN);
pci_lock_rescan_remove();
pci_bus_add_devices(slot->zdev->bus); pci_bus_add_devices(slot->zdev->bus);
pci_unlock_rescan_remove();
return rc; return rc;
@ -98,7 +100,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
return -EIO; return -EIO;
if (slot->zdev->pdev) if (slot->zdev->pdev)
pci_stop_and_remove_bus_device(slot->zdev->pdev); pci_stop_and_remove_bus_device_locked(slot->zdev->pdev);
rc = zpci_disable_device(slot->zdev); rc = zpci_disable_device(slot->zdev);
if (rc) if (rc)

View file

@ -459,12 +459,15 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
acpi_scan_lock_release(); acpi_scan_lock_release();
} }
pci_lock_rescan_remove();
/* Call the driver for the new device */ /* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus); pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */ /* Call the drivers for the new devices subordinate to PPB */
if (new_ppb) if (new_ppb)
pci_bus_add_devices(new_bus); pci_bus_add_devices(new_bus);
pci_unlock_rescan_remove();
mutex_unlock(&sn_hotplug_mutex); mutex_unlock(&sn_hotplug_mutex);
if (rc == 0) if (rc == 0)
@ -540,6 +543,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
acpi_scan_lock_release(); acpi_scan_lock_release();
} }
pci_lock_rescan_remove();
/* Free the SN resources assigned to the Linux device.*/ /* Free the SN resources assigned to the Linux device.*/
list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) { list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != slot->device_num + 1) if (PCI_SLOT(dev->devfn) != slot->device_num + 1)
@ -550,6 +554,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev); pci_dev_put(dev);
} }
pci_unlock_rescan_remove();
/* Remove the SSDT for the slot from the ACPI namespace */ /* Remove the SSDT for the slot from the ACPI namespace */
if (SN_ACPI_BASE_SUPPORT() && ssdt_id) { if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {

View file

@ -40,7 +40,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
struct pci_dev *bridge = ctrl->pci_dev; struct pci_dev *bridge = ctrl->pci_dev;
struct pci_bus *parent = bridge->subordinate; struct pci_bus *parent = bridge->subordinate;
int num; int num, ret = 0;
pci_lock_rescan_remove();
dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) { if (dev) {
@ -48,13 +50,15 @@ int __ref shpchp_configure_device(struct slot *p_slot)
"at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev), "at %04x:%02x:%02x, cannot hot-add\n", pci_name(dev),
pci_domain_nr(parent), p_slot->bus, p_slot->device); pci_domain_nr(parent), p_slot->bus, p_slot->device);
pci_dev_put(dev); pci_dev_put(dev);
return -EINVAL; ret = -EINVAL;
goto out;
} }
num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0)); num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (num == 0) { if (num == 0) {
ctrl_err(ctrl, "No new device found\n"); ctrl_err(ctrl, "No new device found\n");
return -ENODEV; ret = -ENODEV;
goto out;
} }
list_for_each_entry(dev, &parent->devices, bus_list) { list_for_each_entry(dev, &parent->devices, bus_list) {
@ -75,7 +79,9 @@ int __ref shpchp_configure_device(struct slot *p_slot)
pci_bus_add_devices(parent); pci_bus_add_devices(parent);
return 0; out:
pci_unlock_rescan_remove();
return ret;
} }
int shpchp_unconfigure_device(struct slot *p_slot) int shpchp_unconfigure_device(struct slot *p_slot)
@ -89,6 +95,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n",
__func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device);
pci_lock_rescan_remove();
list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
if (PCI_SLOT(dev->devfn) != p_slot->device) if (PCI_SLOT(dev->devfn) != p_slot->device)
continue; continue;
@ -108,6 +116,8 @@ int shpchp_unconfigure_device(struct slot *p_slot)
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_dev_put(dev); pci_dev_put(dev);
} }
pci_unlock_rescan_remove();
return rc; return rc;
} }

View file

@ -113,6 +113,10 @@ static struct pci_driver ioapic_driver = {
.remove = ioapic_remove, .remove = ioapic_remove,
}; };
module_pci_driver(ioapic_driver); static int __init ioapic_init(void)
{
return pci_register_driver(&ioapic_driver);
}
module_init(ioapic_init);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View file

@ -84,6 +84,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
virtfn->dev.parent = dev->dev.parent; virtfn->dev.parent = dev->dev.parent;
virtfn->physfn = pci_dev_get(dev); virtfn->physfn = pci_dev_get(dev);
virtfn->is_virtfn = 1; virtfn->is_virtfn = 1;
virtfn->multifunction = 0;
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
res = dev->resource + PCI_IOV_RESOURCES + i; res = dev->resource + PCI_IOV_RESOURCES + i;
@ -441,6 +442,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
found: found:
pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl);
pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, 0);
pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset);
pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride);
if (!offset || (total > 1 && !stride)) if (!offset || (total > 1 && !stride))

View file

@ -116,7 +116,7 @@ void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
return default_teardown_msi_irqs(dev); return default_teardown_msi_irqs(dev);
} }
void default_restore_msi_irqs(struct pci_dev *dev, int irq) static void default_restore_msi_irq(struct pci_dev *dev, int irq)
{ {
struct msi_desc *entry; struct msi_desc *entry;
@ -134,9 +134,9 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq)
write_msi_msg(irq, &entry->msg); write_msi_msg(irq, &entry->msg);
} }
void __weak arch_restore_msi_irqs(struct pci_dev *dev, int irq) void __weak arch_restore_msi_irqs(struct pci_dev *dev)
{ {
return default_restore_msi_irqs(dev, irq); return default_restore_msi_irqs(dev);
} }
static void msi_set_enable(struct pci_dev *dev, int enable) static void msi_set_enable(struct pci_dev *dev, int enable)
@ -262,6 +262,15 @@ void unmask_msi_irq(struct irq_data *data)
msi_set_mask_bit(data, 0); msi_set_mask_bit(data, 0);
} }
void default_restore_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *entry;
list_for_each_entry(entry, &dev->msi_list, list) {
default_restore_msi_irq(dev, entry->irq);
}
}
void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{ {
BUG_ON(entry->dev->current_state != PCI_D0); BUG_ON(entry->dev->current_state != PCI_D0);
@ -363,6 +372,9 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
static void free_msi_irqs(struct pci_dev *dev) static void free_msi_irqs(struct pci_dev *dev)
{ {
struct msi_desc *entry, *tmp; struct msi_desc *entry, *tmp;
struct attribute **msi_attrs;
struct device_attribute *dev_attr;
int count = 0;
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
int i, nvec; int i, nvec;
@ -398,6 +410,22 @@ static void free_msi_irqs(struct pci_dev *dev)
list_del(&entry->list); list_del(&entry->list);
kfree(entry); kfree(entry);
} }
if (dev->msi_irq_groups) {
sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups);
msi_attrs = dev->msi_irq_groups[0]->attrs;
list_for_each_entry(entry, &dev->msi_list, list) {
dev_attr = container_of(msi_attrs[count],
struct device_attribute, attr);
kfree(dev_attr->attr.name);
kfree(dev_attr);
++count;
}
kfree(msi_attrs);
kfree(dev->msi_irq_groups[0]);
kfree(dev->msi_irq_groups);
dev->msi_irq_groups = NULL;
}
} }
static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) static struct msi_desc *alloc_msi_entry(struct pci_dev *dev)
@ -430,7 +458,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pci_intx_for_msi(dev, 0); pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0); msi_set_enable(dev, 0);
arch_restore_msi_irqs(dev, dev->irq); arch_restore_msi_irqs(dev);
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
msi_mask_irq(entry, msi_capable_mask(control), entry->masked); msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
@ -455,8 +483,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL; control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control); pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control);
arch_restore_msi_irqs(dev);
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
arch_restore_msi_irqs(dev, entry->irq);
msix_mask_irq(entry, entry->masked); msix_mask_irq(entry, entry->masked);
} }
@ -471,94 +499,95 @@ void pci_restore_msi_state(struct pci_dev *dev)
} }
EXPORT_SYMBOL_GPL(pci_restore_msi_state); EXPORT_SYMBOL_GPL(pci_restore_msi_state);
static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr,
#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr)
#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj)
struct msi_attribute {
struct attribute attr;
ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr,
char *buf);
ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr,
const char *buf, size_t count);
};
static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr,
char *buf) char *buf)
{ {
return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi"); struct pci_dev *pdev = to_pci_dev(dev);
struct msi_desc *entry;
unsigned long irq;
int retval;
retval = kstrtoul(attr->attr.name, 10, &irq);
if (retval)
return retval;
list_for_each_entry(entry, &pdev->msi_list, list) {
if (entry->irq == irq) {
return sprintf(buf, "%s\n",
entry->msi_attrib.is_msix ? "msix" : "msi");
}
}
return -ENODEV;
} }
static ssize_t msi_irq_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct msi_attribute *attribute = to_msi_attr(attr);
struct msi_desc *entry = to_msi_desc(kobj);
if (!attribute->show)
return -EIO;
return attribute->show(entry, attribute, buf);
}
static const struct sysfs_ops msi_irq_sysfs_ops = {
.show = msi_irq_attr_show,
};
static struct msi_attribute mode_attribute =
__ATTR(mode, S_IRUGO, show_msi_mode, NULL);
static struct attribute *msi_irq_default_attrs[] = {
&mode_attribute.attr,
NULL
};
static void msi_kobj_release(struct kobject *kobj)
{
struct msi_desc *entry = to_msi_desc(kobj);
pci_dev_put(entry->dev);
}
static struct kobj_type msi_irq_ktype = {
.release = msi_kobj_release,
.sysfs_ops = &msi_irq_sysfs_ops,
.default_attrs = msi_irq_default_attrs,
};
static int populate_msi_sysfs(struct pci_dev *pdev) static int populate_msi_sysfs(struct pci_dev *pdev)
{ {
struct attribute **msi_attrs;
struct attribute *msi_attr;
struct device_attribute *msi_dev_attr;
struct attribute_group *msi_irq_group;
const struct attribute_group **msi_irq_groups;
struct msi_desc *entry; struct msi_desc *entry;
struct kobject *kobj; int ret = -ENOMEM;
int ret; int num_msi = 0;
int count = 0; int count = 0;
pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); /* Determine how many msi entries we have */
if (!pdev->msi_kset)
return -ENOMEM;
list_for_each_entry(entry, &pdev->msi_list, list) { list_for_each_entry(entry, &pdev->msi_list, list) {
kobj = &entry->kobj; ++num_msi;
kobj->kset = pdev->msi_kset;
pci_dev_get(pdev);
ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL,
"%u", entry->irq);
if (ret)
goto out_unroll;
count++;
} }
if (!num_msi)
return 0;
/* Dynamically create the MSI attributes for the PCI device */
msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL);
if (!msi_attrs)
return -ENOMEM;
list_for_each_entry(entry, &pdev->msi_list, list) {
char *name = kmalloc(20, GFP_KERNEL);
msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
if (!msi_dev_attr)
goto error_attrs;
sprintf(name, "%d", entry->irq);
sysfs_attr_init(&msi_dev_attr->attr);
msi_dev_attr->attr.name = name;
msi_dev_attr->attr.mode = S_IRUGO;
msi_dev_attr->show = msi_mode_show;
msi_attrs[count] = &msi_dev_attr->attr;
++count;
}
msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL);
if (!msi_irq_group)
goto error_attrs;
msi_irq_group->name = "msi_irqs";
msi_irq_group->attrs = msi_attrs;
msi_irq_groups = kzalloc(sizeof(void *) * 2, GFP_KERNEL);
if (!msi_irq_groups)
goto error_irq_group;
msi_irq_groups[0] = msi_irq_group;
ret = sysfs_create_groups(&pdev->dev.kobj, msi_irq_groups);
if (ret)
goto error_irq_groups;
pdev->msi_irq_groups = msi_irq_groups;
return 0; return 0;
out_unroll: error_irq_groups:
list_for_each_entry(entry, &pdev->msi_list, list) { kfree(msi_irq_groups);
if (!count) error_irq_group:
break; kfree(msi_irq_group);
kobject_del(&entry->kobj); error_attrs:
kobject_put(&entry->kobj); count = 0;
count--; msi_attr = msi_attrs[count];
while (msi_attr) {
msi_dev_attr = container_of(msi_attr, struct device_attribute, attr);
kfree(msi_attr->name);
kfree(msi_dev_attr);
++count;
msi_attr = msi_attrs[count];
} }
return ret; return ret;
} }
@ -729,7 +758,7 @@ static int msix_capability_init(struct pci_dev *dev,
ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
if (ret) if (ret)
goto error; goto out_avail;
/* /*
* Some devices require MSI-X to be enabled before we can touch the * Some devices require MSI-X to be enabled before we can touch the
@ -742,10 +771,8 @@ static int msix_capability_init(struct pci_dev *dev,
msix_program_entries(dev, entries); msix_program_entries(dev, entries);
ret = populate_msi_sysfs(dev); ret = populate_msi_sysfs(dev);
if (ret) { if (ret)
ret = 0; goto out_free;
goto error;
}
/* Set MSI-X enabled bits and unmask the function */ /* Set MSI-X enabled bits and unmask the function */
pci_intx_for_msi(dev, 0); pci_intx_for_msi(dev, 0);
@ -756,7 +783,7 @@ static int msix_capability_init(struct pci_dev *dev,
return 0; return 0;
error: out_avail:
if (ret < 0) { if (ret < 0) {
/* /*
* If we had some success, report the number of irqs * If we had some success, report the number of irqs
@ -773,6 +800,7 @@ error:
ret = avail; ret = avail;
} }
out_free:
free_msi_irqs(dev); free_msi_irqs(dev);
return ret; return ret;
@ -823,6 +851,31 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
return 0; return 0;
} }
/**
* pci_msi_vec_count - Return the number of MSI vectors a device can send
* @dev: device to report about
*
* This function returns the number of MSI vectors a device requested via
* Multiple Message Capable register. It returns a negative errno if the
* device is not capable sending MSI interrupts. Otherwise, the call succeeds
* and returns a power of two, up to a maximum of 2^5 (32), according to the
* MSI specification.
**/
int pci_msi_vec_count(struct pci_dev *dev)
{
int ret;
u16 msgctl;
if (!dev->msi_cap)
return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
return ret;
}
EXPORT_SYMBOL(pci_msi_vec_count);
/** /**
* pci_enable_msi_block - configure device's MSI capability structure * pci_enable_msi_block - configure device's MSI capability structure
* @dev: device to configure * @dev: device to configure
@ -836,16 +889,16 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type)
* updates the @dev's irq member to the lowest new interrupt number; the * updates the @dev's irq member to the lowest new interrupt number; the
* other interrupt numbers allocated to this device are consecutive. * other interrupt numbers allocated to this device are consecutive.
*/ */
int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) int pci_enable_msi_block(struct pci_dev *dev, int nvec)
{ {
int status, maxvec; int status, maxvec;
u16 msgctl;
if (!dev->msi_cap || dev->current_state != PCI_D0) if (dev->current_state != PCI_D0)
return -EINVAL; return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl); maxvec = pci_msi_vec_count(dev);
maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); if (maxvec < 0)
return maxvec;
if (nvec > maxvec) if (nvec > maxvec)
return maxvec; return maxvec;
@ -867,31 +920,6 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
} }
EXPORT_SYMBOL(pci_enable_msi_block); EXPORT_SYMBOL(pci_enable_msi_block);
int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
{
int ret, nvec;
u16 msgctl;
if (!dev->msi_cap || dev->current_state != PCI_D0)
return -EINVAL;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
if (maxvec)
*maxvec = ret;
do {
nvec = ret;
ret = pci_enable_msi_block(dev, nvec);
} while (ret > 0);
if (ret < 0)
return ret;
return nvec;
}
EXPORT_SYMBOL(pci_enable_msi_block_auto);
void pci_msi_shutdown(struct pci_dev *dev) void pci_msi_shutdown(struct pci_dev *dev)
{ {
struct msi_desc *desc; struct msi_desc *desc;
@ -925,25 +953,29 @@ void pci_disable_msi(struct pci_dev *dev)
pci_msi_shutdown(dev); pci_msi_shutdown(dev);
free_msi_irqs(dev); free_msi_irqs(dev);
kset_unregister(dev->msi_kset);
dev->msi_kset = NULL;
} }
EXPORT_SYMBOL(pci_disable_msi); EXPORT_SYMBOL(pci_disable_msi);
/** /**
* pci_msix_table_size - return the number of device's MSI-X table entries * pci_msix_vec_count - return the number of device's MSI-X table entries
* @dev: pointer to the pci_dev data structure of MSI-X device function * @dev: pointer to the pci_dev data structure of MSI-X device function
*/
int pci_msix_table_size(struct pci_dev *dev) * This function returns the number of device's MSI-X table entries and
* therefore the number of MSI-X vectors device is capable of sending.
* It returns a negative errno if the device is not capable of sending MSI-X
* interrupts.
**/
int pci_msix_vec_count(struct pci_dev *dev)
{ {
u16 control; u16 control;
if (!dev->msix_cap) if (!dev->msix_cap)
return 0; return -EINVAL;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control); pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &control);
return msix_table_size(control); return msix_table_size(control);
} }
EXPORT_SYMBOL(pci_msix_vec_count);
/** /**
* pci_enable_msix - configure device's MSI-X capability structure * pci_enable_msix - configure device's MSI-X capability structure
@ -972,7 +1004,9 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
if (status) if (status)
return status; return status;
nr_entries = pci_msix_table_size(dev); nr_entries = pci_msix_vec_count(dev);
if (nr_entries < 0)
return nr_entries;
if (nvec > nr_entries) if (nvec > nr_entries)
return nr_entries; return nr_entries;
@ -1023,8 +1057,6 @@ void pci_disable_msix(struct pci_dev *dev)
pci_msix_shutdown(dev); pci_msix_shutdown(dev);
free_msi_irqs(dev); free_msi_irqs(dev);
kset_unregister(dev->msi_kset);
dev->msi_kset = NULL;
} }
EXPORT_SYMBOL(pci_disable_msix); EXPORT_SYMBOL(pci_disable_msix);
@ -1079,3 +1111,77 @@ void pci_msi_init_pci_dev(struct pci_dev *dev)
if (dev->msix_cap) if (dev->msix_cap)
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
} }
/**
* pci_enable_msi_range - configure device's MSI capability structure
* @dev: device to configure
* @minvec: minimal number of interrupts to configure
* @maxvec: maximum number of interrupts to configure
*
* This function tries to allocate a maximum possible number of interrupts in a
* range between @minvec and @maxvec. It returns a negative errno if an error
* occurs. If it succeeds, it returns the actual number of interrupts allocated
* and updates the @dev's irq member to the lowest new interrupt number;
* the other interrupt numbers allocated to this device are consecutive.
**/
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
{
int nvec = maxvec;
int rc;
if (maxvec < minvec)
return -ERANGE;
do {
rc = pci_enable_msi_block(dev, nvec);
if (rc < 0) {
return rc;
} else if (rc > 0) {
if (rc < minvec)
return -ENOSPC;
nvec = rc;
}
} while (rc);
return nvec;
}
EXPORT_SYMBOL(pci_enable_msi_range);
/**
* pci_enable_msix_range - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
* @minvec: minimum number of MSI-X irqs requested
* @maxvec: maximum number of MSI-X irqs requested
*
* Setup the MSI-X capability structure of device function with a maximum
* possible number of interrupts in the range between @minvec and @maxvec
* upon its software driver call to request for MSI-X mode enabled on its
* hardware device function. It returns a negative errno if an error occurs.
* If it succeeds, it returns the actual number of interrupts allocated and
* indicates the successful configuration of MSI-X capability structure
* with new allocated MSI-X interrupts.
**/
int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
int minvec, int maxvec)
{
int nvec = maxvec;
int rc;
if (maxvec < minvec)
return -ERANGE;
do {
rc = pci_enable_msix(dev, entries, nvec);
if (rc < 0) {
return rc;
} else if (rc > 0) {
if (rc < minvec)
return -ENOSPC;
nvec = rc;
}
} while (rc);
return nvec;
}
EXPORT_SYMBOL(pci_enable_msix_range);

View file

@ -361,7 +361,7 @@ static void pci_acpi_cleanup(struct device *dev)
static bool pci_acpi_bus_match(struct device *dev) static bool pci_acpi_bus_match(struct device *dev)
{ {
return dev->bus == &pci_bus_type; return dev_is_pci(dev);
} }
static struct acpi_bus_type acpi_pci_bus = { static struct acpi_bus_type acpi_pci_bus = {

View file

@ -34,21 +34,7 @@
#define DEVICE_LABEL_DSM 0x07 #define DEVICE_LABEL_DSM 0x07
#ifndef CONFIG_DMI #ifdef CONFIG_DMI
static inline int
pci_create_smbiosname_file(struct pci_dev *pdev)
{
return -1;
}
static inline void
pci_remove_smbiosname_file(struct pci_dev *pdev)
{
}
#else
enum smbios_attr_enum { enum smbios_attr_enum {
SMBIOS_ATTR_NONE = 0, SMBIOS_ATTR_NONE = 0,
SMBIOS_ATTR_LABEL_SHOW, SMBIOS_ATTR_LABEL_SHOW,
@ -156,31 +142,20 @@ pci_remove_smbiosname_file(struct pci_dev *pdev)
{ {
sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group); sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
} }
#else
static inline int
pci_create_smbiosname_file(struct pci_dev *pdev)
{
return -1;
}
static inline void
pci_remove_smbiosname_file(struct pci_dev *pdev)
{
}
#endif #endif
#ifndef CONFIG_ACPI #ifdef CONFIG_ACPI
static inline int
pci_create_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline int
pci_remove_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline bool
device_has_dsm(struct device *dev)
{
return false;
}
#else
static const char device_label_dsm_uuid[] = { static const char device_label_dsm_uuid[] = {
0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D, 0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D 0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
@ -364,6 +339,24 @@ pci_remove_acpi_index_label_files(struct pci_dev *pdev)
sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group); sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group);
return 0; return 0;
} }
#else
static inline int
pci_create_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline int
pci_remove_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline bool
device_has_dsm(struct device *dev)
{
return false;
}
#endif #endif
void pci_create_firmware_label_files(struct pci_dev *pdev) void pci_create_firmware_label_files(struct pci_dev *pdev)

View file

@ -297,7 +297,6 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RW(msi_bus); static DEVICE_ATTR_RW(msi_bus);
static DEFINE_MUTEX(pci_remove_rescan_mutex);
static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
size_t count) size_t count)
{ {
@ -308,10 +307,10 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
return -EINVAL; return -EINVAL;
if (val) { if (val) {
mutex_lock(&pci_remove_rescan_mutex); pci_lock_rescan_remove();
while ((b = pci_find_next_bus(b)) != NULL) while ((b = pci_find_next_bus(b)) != NULL)
pci_rescan_bus(b); pci_rescan_bus(b);
mutex_unlock(&pci_remove_rescan_mutex); pci_unlock_rescan_remove();
} }
return count; return count;
} }
@ -342,9 +341,9 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
if (val) { if (val) {
mutex_lock(&pci_remove_rescan_mutex); pci_lock_rescan_remove();
pci_rescan_bus(pdev->bus); pci_rescan_bus(pdev->bus);
mutex_unlock(&pci_remove_rescan_mutex); pci_unlock_rescan_remove();
} }
return count; return count;
} }
@ -354,11 +353,7 @@ static struct device_attribute dev_rescan_attr = __ATTR(rescan,
static void remove_callback(struct device *dev) static void remove_callback(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
mutex_lock(&pci_remove_rescan_mutex);
pci_stop_and_remove_bus_device(pdev);
mutex_unlock(&pci_remove_rescan_mutex);
} }
static ssize_t static ssize_t
@ -395,12 +390,12 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
if (val) { if (val) {
mutex_lock(&pci_remove_rescan_mutex); pci_lock_rescan_remove();
if (!pci_is_root_bus(bus) && list_empty(&bus->devices)) if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
pci_rescan_bus_bridge_resize(bus->self); pci_rescan_bus_bridge_resize(bus->self);
else else
pci_rescan_bus(bus); pci_rescan_bus(bus);
mutex_unlock(&pci_remove_rescan_mutex); pci_unlock_rescan_remove();
} }
return count; return count;
} }

View file

@ -430,6 +430,32 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
return best; 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) * pci_restore_bars - restore a devices BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored * @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; 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 * __pci_start_power_transition - Start power transition of a PCI device
* @dev: PCI device to handle. * @dev: PCI device to handle.
@ -835,18 +883,28 @@ EXPORT_SYMBOL(pci_choose_state);
#define PCI_EXP_SAVE_REGS 7 #define PCI_EXP_SAVE_REGS 7
static struct pci_cap_saved_state *pci_find_saved_cap( static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev,
struct pci_dev *pci_dev, char cap) u16 cap, bool extended)
{ {
struct pci_cap_saved_state *tmp; struct pci_cap_saved_state *tmp;
hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) { 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 tmp;
} }
return NULL; 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) static int pci_save_pcie_state(struct pci_dev *dev)
{ {
int i = 0; int i = 0;
@ -948,6 +1006,8 @@ pci_save_state(struct pci_dev *dev)
return i; return i;
if ((i = pci_save_pcix_state(dev)) != 0) if ((i = pci_save_pcix_state(dev)) != 0)
return i; return i;
if ((i = pci_save_vc_state(dev)) != 0)
return i;
return 0; return 0;
} }
@ -1010,6 +1070,7 @@ void pci_restore_state(struct pci_dev *dev)
/* PCI Express register must be restored first */ /* PCI Express register must be restored first */
pci_restore_pcie_state(dev); pci_restore_pcie_state(dev);
pci_restore_ats_state(dev); pci_restore_ats_state(dev);
pci_restore_vc_state(dev);
pci_restore_config_space(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 * @dev: PCI device that we're dealing with
* @state: Saved state returned from pci_store_saved_state() * @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; 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) { while (cap->size) {
struct pci_cap_saved_state *tmp; 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) if (!tmp || tmp->cap.size != cap->size)
return -EINVAL; return -EINVAL;
@ -1099,7 +1161,6 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
dev->state_saved = true; dev->state_saved = true;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_load_saved_state);
/** /**
* pci_load_and_free_saved_state - Reload the save state pointed to by 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_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# * 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 * If the platform can't manage @dev, return the deepest state from which it
* can generate wake events, based on any available PME info. * 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; 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 * @dev: the PCI device
* @cap: the capability to allocate the buffer for * @cap: the capability to allocate the buffer for
* @extended: Standard or Extended capability ID
* @size: requested size of the buffer * @size: requested size of the buffer
*/ */
static int pci_add_cap_save_buffer( static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap,
struct pci_dev *dev, char cap, unsigned int size) bool extended, unsigned int size)
{ {
int pos; int pos;
struct pci_cap_saved_state *save_state; struct pci_cap_saved_state *save_state;
if (extended)
pos = pci_find_ext_capability(dev, cap);
else
pos = pci_find_capability(dev, cap); pos = pci_find_capability(dev, cap);
if (pos <= 0) if (pos <= 0)
return 0; return 0;
@ -2041,12 +2087,23 @@ static int pci_add_cap_save_buffer(
return -ENOMEM; return -ENOMEM;
save_state->cap.cap_nr = cap; save_state->cap.cap_nr = cap;
save_state->cap.cap_extended = extended;
save_state->cap.size = size; save_state->cap.size = size;
pci_add_saved_cap(dev, save_state); pci_add_saved_cap(dev, save_state);
return 0; 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 * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
* @dev: the PCI device * @dev: the PCI device
@ -2065,6 +2122,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error) if (error)
dev_err(&dev->dev, dev_err(&dev->dev,
"unable to preallocate PCI-X save buffer\n"); "unable to preallocate PCI-X save buffer\n");
pci_allocate_vc_save_buffers(dev);
} }
void pci_free_cap_save_buffers(struct pci_dev *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; 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); 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 * @dev: the PCI device to operate on
* *
* Check if the device dev has its INTx line asserted, unmask it if not * 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 pci_wait_for_pending_transaction(struct pci_dev *dev)
{ {
int i; if (!pci_is_pcie(dev))
u16 status;
/* 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 1;
}
return 0; return pci_wait_for_pending(dev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_TRPND);
} }
EXPORT_SYMBOL(pci_wait_for_pending_transaction); 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) static int pci_af_flr(struct pci_dev *dev, int probe)
{ {
int i;
int pos; int pos;
u8 cap; u8 cap;
u8 status;
pos = pci_find_capability(dev, PCI_CAP_ID_AF); pos = pci_find_capability(dev, PCI_CAP_ID_AF);
if (!pos) if (!pos)
@ -3261,14 +3072,8 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
return 0; return 0;
/* Wait for Transaction Pending bit clean */ /* Wait for Transaction Pending bit clean */
for (i = 0; i < 4; i++) { if (pci_wait_for_pending(dev, PCI_AF_STATUS, PCI_AF_STATUS_TP))
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; goto clear;
}
dev_err(&dev->dev, "transaction is not cleared; " dev_err(&dev->dev, "transaction is not cleared; "
"proceeding with reset anyway\n"); "proceeding with reset anyway\n");
@ -3445,6 +3250,18 @@ static void pci_dev_lock(struct pci_dev *dev)
device_lock(&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) static void pci_dev_unlock(struct pci_dev *dev)
{ {
device_unlock(&dev->dev); device_unlock(&dev->dev);
@ -3588,6 +3405,34 @@ int pci_reset_function(struct pci_dev *dev)
} }
EXPORT_SYMBOL_GPL(pci_reset_function); 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 */ /* Lock devices from the top of the tree down */
static void pci_bus_lock(struct pci_bus *bus) 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 */ /* Lock devices from the top of the tree down */
static void pci_slot_lock(struct pci_slot *slot) 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 */ /* Save and disable devices from the top of the tree down */
static void pci_bus_save_and_disable(struct pci_bus *bus) 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); 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) static int pci_bus_reset(struct pci_bus *bus, int probe)
{ {
if (!bus->self) if (!bus->self)
@ -3821,6 +3752,35 @@ int pci_reset_bus(struct pci_bus *bus)
} }
EXPORT_SYMBOL_GPL(pci_reset_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 * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
* @dev: PCI device to query * @dev: PCI device to query
@ -4450,7 +4410,6 @@ EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_pme_capable); EXPORT_SYMBOL(pci_pme_capable);
EXPORT_SYMBOL(pci_pme_active); EXPORT_SYMBOL(pci_pme_active);
EXPORT_SYMBOL(pci_wake_from_d3); EXPORT_SYMBOL(pci_wake_from_d3);
EXPORT_SYMBOL(pci_target_state);
EXPORT_SYMBOL(pci_prepare_to_sleep); EXPORT_SYMBOL(pci_prepare_to_sleep);
EXPORT_SYMBOL(pci_back_from_sleep); EXPORT_SYMBOL(pci_back_from_sleep);
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state); EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);

View file

@ -6,7 +6,6 @@
#define PCI_CFG_SPACE_SIZE 256 #define PCI_CFG_SPACE_SIZE 256
#define PCI_CFG_SPACE_EXP_SIZE 4096 #define PCI_CFG_SPACE_EXP_SIZE 4096
extern const unsigned char pcix_bus_speed[];
extern const unsigned char pcie_link_speed[]; extern const unsigned char pcie_link_speed[];
/* Functions internal to the PCI core code */ /* Functions internal to the PCI core code */
@ -68,7 +67,6 @@ void pci_power_up(struct pci_dev *dev);
void pci_disable_enabled_device(struct pci_dev *dev); void pci_disable_enabled_device(struct pci_dev *dev);
int pci_finish_runtime_suspend(struct pci_dev *dev); int pci_finish_runtime_suspend(struct pci_dev *dev);
int __pci_pme_wakeup(struct pci_dev *dev, void *ign); int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
void pci_wakeup_bus(struct pci_bus *bus);
void pci_config_pm_runtime_get(struct pci_dev *dev); void pci_config_pm_runtime_get(struct pci_dev *dev);
void pci_config_pm_runtime_put(struct pci_dev *dev); void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev); void pci_pm_init(struct pci_dev *dev);

View file

@ -23,10 +23,10 @@
static inline int hest_match_pci(struct acpi_hest_aer_common *p, static inline int hest_match_pci(struct acpi_hest_aer_common *p,
struct pci_dev *pci) struct pci_dev *pci)
{ {
return (0 == pci_domain_nr(pci->bus) && return ACPI_HEST_SEGMENT(p->bus) == pci_domain_nr(pci->bus) &&
p->bus == pci->bus->number && ACPI_HEST_BUS(p->bus) == pci->bus->number &&
p->device == PCI_SLOT(pci->devfn) && p->device == PCI_SLOT(pci->devfn) &&
p->function == PCI_FUNC(pci->devfn)); p->function == PCI_FUNC(pci->devfn);
} }
static inline bool hest_match_type(struct acpi_hest_header *hest_hdr, static inline bool hest_match_type(struct acpi_hest_header *hest_hdr,
@ -50,14 +50,37 @@ struct aer_hest_parse_info {
int firmware_first; int firmware_first;
}; };
static int hest_source_is_pcie_aer(struct acpi_hest_header *hest_hdr)
{
if (hest_hdr->type == ACPI_HEST_TYPE_AER_ROOT_PORT ||
hest_hdr->type == ACPI_HEST_TYPE_AER_ENDPOINT ||
hest_hdr->type == ACPI_HEST_TYPE_AER_BRIDGE)
return 1;
return 0;
}
static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data) static int aer_hest_parse(struct acpi_hest_header *hest_hdr, void *data)
{ {
struct aer_hest_parse_info *info = data; struct aer_hest_parse_info *info = data;
struct acpi_hest_aer_common *p; struct acpi_hest_aer_common *p;
int ff; int ff;
if (!hest_source_is_pcie_aer(hest_hdr))
return 0;
p = (struct acpi_hest_aer_common *)(hest_hdr + 1); p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); ff = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
/*
* If no specific device is supplied, determine whether
* FIRMWARE_FIRST is set for *any* PCIe device.
*/
if (!info->pci_dev) {
info->firmware_first |= ff;
return 0;
}
/* Otherwise, check the specific device */
if (p->flags & ACPI_HEST_GLOBAL) { if (p->flags & ACPI_HEST_GLOBAL) {
if (hest_match_type(hest_hdr, info->pci_dev)) if (hest_match_type(hest_hdr, info->pci_dev))
info->firmware_first = ff; info->firmware_first = ff;
@ -97,33 +120,20 @@ int pcie_aer_get_firmware_first(struct pci_dev *dev)
static bool aer_firmware_first; static bool aer_firmware_first;
static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data)
{
struct acpi_hest_aer_common *p;
if (aer_firmware_first)
return 0;
switch (hest_hdr->type) {
case ACPI_HEST_TYPE_AER_ROOT_PORT:
case ACPI_HEST_TYPE_AER_ENDPOINT:
case ACPI_HEST_TYPE_AER_BRIDGE:
p = (struct acpi_hest_aer_common *)(hest_hdr + 1);
aer_firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
default:
return 0;
}
}
/** /**
* aer_acpi_firmware_first - Check if APEI should control AER. * aer_acpi_firmware_first - Check if APEI should control AER.
*/ */
bool aer_acpi_firmware_first(void) bool aer_acpi_firmware_first(void)
{ {
static bool parsed = false; static bool parsed = false;
struct aer_hest_parse_info info = {
.pci_dev = NULL, /* Check all PCIe devices */
.firmware_first = 0,
};
if (!parsed) { if (!parsed) {
apei_hest_parse(aer_hest_parse_aff, NULL); apei_hest_parse(aer_hest_parse, &info);
aer_firmware_first = info.firmware_first;
parsed = true; parsed = true;
} }
return aer_firmware_first; return aer_firmware_first;

View file

@ -124,6 +124,21 @@ static const char *aer_agent_string[] = {
"Transmitter ID" "Transmitter ID"
}; };
static void __print_tlp_header(struct pci_dev *dev,
struct aer_header_log_regs *t)
{
unsigned char *tlp = (unsigned char *)&t;
dev_err(&dev->dev, " TLP Header:"
" %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
*(tlp + 11), *(tlp + 10), *(tlp + 9),
*(tlp + 8), *(tlp + 15), *(tlp + 14),
*(tlp + 13), *(tlp + 12));
}
static void __aer_print_error(struct pci_dev *dev, static void __aer_print_error(struct pci_dev *dev,
struct aer_err_info *info) struct aer_err_info *info)
{ {
@ -153,15 +168,16 @@ static void __aer_print_error(struct pci_dev *dev,
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
{ {
int layer, agent;
int id = ((dev->bus->number << 8) | dev->devfn); int id = ((dev->bus->number << 8) | dev->devfn);
if (info->status == 0) { if (!info->status) {
dev_err(&dev->dev, dev_err(&dev->dev,
"PCIe Bus Error: severity=%s, type=Unaccessible, " "PCIe Bus Error: severity=%s, type=Unaccessible, "
"id=%04x(Unregistered Agent ID)\n", "id=%04x(Unregistered Agent ID)\n",
aer_error_severity_string[info->severity], id); aer_error_severity_string[info->severity], id);
} else { goto out;
int layer, agent; }
layer = AER_GET_LAYER_ERROR(info->severity, info->status); layer = AER_GET_LAYER_ERROR(info->severity, info->status);
agent = AER_GET_AGENT(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status);
@ -178,23 +194,13 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
__aer_print_error(dev, info); __aer_print_error(dev, info);
if (info->tlp_header_valid) { if (info->tlp_header_valid)
unsigned char *tlp = (unsigned char *) &info->tlp; __print_tlp_header(dev, &info->tlp);
dev_err(&dev->dev, " TLP Header:"
" %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
*(tlp + 11), *(tlp + 10), *(tlp + 9),
*(tlp + 8), *(tlp + 15), *(tlp + 14),
*(tlp + 13), *(tlp + 12));
}
}
out:
if (info->id && info->error_dev_num > 1 && info->id == id) if (info->id && info->error_dev_num > 1 && info->id == id)
dev_err(&dev->dev, dev_err(&dev->dev, " Error of this Agent(%04x) is reported first\n", id);
" Error of this Agent(%04x) is reported first\n",
id);
trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask), trace_aer_event(dev_name(&dev->dev), (info->status & ~info->mask),
info->severity); info->severity);
} }
@ -228,6 +234,7 @@ void cper_print_aer(struct pci_dev *dev, int cper_severity,
const char **status_strs; const char **status_strs;
aer_severity = cper_severity_to_aer(cper_severity); aer_severity = cper_severity_to_aer(cper_severity);
if (aer_severity == AER_CORRECTABLE) { if (aer_severity == AER_CORRECTABLE) {
status = aer->cor_status; status = aer->cor_status;
mask = aer->cor_mask; mask = aer->cor_mask;
@ -240,28 +247,22 @@ void cper_print_aer(struct pci_dev *dev, int cper_severity,
status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string); status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string);
tlp_header_valid = status & AER_LOG_TLP_MASKS; tlp_header_valid = status & AER_LOG_TLP_MASKS;
} }
layer = AER_GET_LAYER_ERROR(aer_severity, status); layer = AER_GET_LAYER_ERROR(aer_severity, status);
agent = AER_GET_AGENT(aer_severity, status); agent = AER_GET_AGENT(aer_severity, status);
dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
status, mask); dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n", status, mask);
cper_print_bits("", status, status_strs, status_strs_size); cper_print_bits("", status, status_strs, status_strs_size);
dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n", dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
aer_error_layer[layer], aer_agent_string[agent]); aer_error_layer[layer], aer_agent_string[agent]);
if (aer_severity != AER_CORRECTABLE) if (aer_severity != AER_CORRECTABLE)
dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n", dev_err(&dev->dev, "aer_uncor_severity: 0x%08x\n",
aer->uncor_severity); aer->uncor_severity);
if (tlp_header_valid) {
const unsigned char *tlp; if (tlp_header_valid)
tlp = (const unsigned char *)&aer->header_log; __print_tlp_header(dev, &aer->header_log);
dev_err(&dev->dev, "aer_tlp_header:"
" %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
*(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
*(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
*(tlp + 11), *(tlp + 10), *(tlp + 9),
*(tlp + 8), *(tlp + 15), *(tlp + 14),
*(tlp + 13), *(tlp + 12));
}
trace_aer_event(dev_name(&dev->dev), (status & ~mask), trace_aer_event(dev_name(&dev->dev), (status & ~mask),
aer_severity); aer_severity);
} }

View file

@ -984,18 +984,6 @@ void pcie_no_aspm(void)
} }
} }
/**
* pcie_aspm_enabled - is PCIe ASPM enabled?
*
* Returns true if ASPM has not been disabled by the command-line option
* pcie_aspm=off.
**/
int pcie_aspm_enabled(void)
{
return !aspm_disabled;
}
EXPORT_SYMBOL(pcie_aspm_enabled);
bool pcie_aspm_support_enabled(void) bool pcie_aspm_support_enabled(void)
{ {
return aspm_support_enabled; return aspm_support_enabled;

View file

@ -79,9 +79,10 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
nr_entries = pci_msix_table_size(dev); nr_entries = pci_msix_vec_count(dev);
if (!nr_entries) if (nr_entries < 0)
return -EINVAL; return nr_entries;
BUG_ON(!nr_entries);
if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES) if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES)
nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES; nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES;
@ -344,11 +345,12 @@ static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
device_enable_async_suspend(device); device_enable_async_suspend(device);
retval = device_register(device); retval = device_register(device);
if (retval) if (retval) {
kfree(pcie); put_device(device);
else
get_device(device);
return retval; return retval;
}
return 0;
} }
/** /**
@ -454,10 +456,8 @@ int pcie_port_device_resume(struct device *dev)
static int remove_iter(struct device *dev, void *data) static int remove_iter(struct device *dev, void *data)
{ {
if (dev->bus == &pcie_port_bus_type) { if (dev->bus == &pcie_port_bus_type)
put_device(dev);
device_unregister(dev); device_unregister(dev);
}
return 0; return 0;
} }
@ -498,12 +498,12 @@ static int pcie_port_probe_service(struct device *dev)
pciedev = to_pcie_device(dev); pciedev = to_pcie_device(dev);
status = driver->probe(pciedev); status = driver->probe(pciedev);
if (!status) { if (status)
dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n",
driver->name);
get_device(dev);
}
return status; return status;
dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", driver->name);
get_device(dev);
return 0;
} }
/** /**
@ -554,7 +554,7 @@ int pcie_port_service_register(struct pcie_port_service_driver *new)
if (pcie_ports_disabled) if (pcie_ports_disabled)
return -ENODEV; return -ENODEV;
new->driver.name = (char *)new->name; new->driver.name = new->name;
new->driver.bus = &pcie_port_bus_type; new->driver.bus = &pcie_port_bus_type;
new->driver.probe = pcie_port_probe_service; new->driver.probe = pcie_port_probe_service;
new->driver.remove = pcie_port_remove_service; new->driver.remove = pcie_port_remove_service;

View file

@ -16,7 +16,7 @@
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
#define CARDBUS_RESERVE_BUSNR 3 #define CARDBUS_RESERVE_BUSNR 3
struct resource busn_resource = { static struct resource busn_resource = {
.name = "PCI busn", .name = "PCI busn",
.start = 0, .start = 0,
.end = 255, .end = 255,
@ -269,8 +269,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
region.end = l + sz; region.end = l + sz;
} }
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
pcibios_resource_to_bus(dev, &inverted_region, res); pcibios_resource_to_bus(dev->bus, &inverted_region, res);
/* /*
* If "A" is a BAR value (a bus address), "bus_to_resource(A)" is * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is
@ -364,7 +364,7 @@ static void pci_read_bridge_io(struct pci_bus *child)
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
region.start = base; region.start = base;
region.end = limit + io_granularity - 1; region.end = limit + io_granularity - 1;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
} }
} }
@ -386,7 +386,7 @@ static void pci_read_bridge_mmio(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
region.start = base; region.start = base;
region.end = limit + 0xfffff; region.end = limit + 0xfffff;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
} }
} }
@ -436,7 +436,7 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
res->flags |= IORESOURCE_MEM_64; res->flags |= IORESOURCE_MEM_64;
region.start = base; region.start = base;
region.end = limit + 0xfffff; region.end = limit + 0xfffff;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
} }
} }
@ -518,7 +518,7 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b)
return bridge; return bridge;
} }
const unsigned char pcix_bus_speed[] = { static const unsigned char pcix_bus_speed[] = {
PCI_SPEED_UNKNOWN, /* 0 */ PCI_SPEED_UNKNOWN, /* 0 */
PCI_SPEED_66MHz_PCIX, /* 1 */ PCI_SPEED_66MHz_PCIX, /* 1 */
PCI_SPEED_100MHz_PCIX, /* 2 */ PCI_SPEED_100MHz_PCIX, /* 2 */
@ -999,6 +999,60 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev)
pdev->is_hotplug_bridge = 1; pdev->is_hotplug_bridge = 1;
} }
/**
* pci_cfg_space_size - get the configuration space size of the PCI device.
* @dev: PCI device
*
* Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
* have 4096 bytes. Even if the device is capable, that doesn't mean we can
* access it. Maybe we don't have a way to generate extended config space
* accesses, or the device is behind a reverse Express bridge. So we try
* reading the dword at 0x100 which must either be 0 or a valid extended
* capability header.
*/
static int pci_cfg_space_size_ext(struct pci_dev *dev)
{
u32 status;
int pos = PCI_CFG_SPACE_SIZE;
if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL)
goto fail;
if (status == 0xffffffff)
goto fail;
return PCI_CFG_SPACE_EXP_SIZE;
fail:
return PCI_CFG_SPACE_SIZE;
}
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
u32 status;
u16 class;
class = dev->class >> 8;
if (class == PCI_CLASS_BRIDGE_HOST)
return pci_cfg_space_size_ext(dev);
if (!pci_is_pcie(dev)) {
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (!pos)
goto fail;
pci_read_config_dword(dev, pos + PCI_X_STATUS, &status);
if (!(status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ)))
goto fail;
}
return pci_cfg_space_size_ext(dev);
fail:
return PCI_CFG_SPACE_SIZE;
}
#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
/** /**
@ -1084,24 +1138,24 @@ int pci_setup_device(struct pci_dev *dev)
region.end = 0x1F7; region.end = 0x1F7;
res = &dev->resource[0]; res = &dev->resource[0];
res->flags = LEGACY_IO_RESOURCE; res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
region.start = 0x3F6; region.start = 0x3F6;
region.end = 0x3F6; region.end = 0x3F6;
res = &dev->resource[1]; res = &dev->resource[1];
res->flags = LEGACY_IO_RESOURCE; res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
if ((progif & 4) == 0) { if ((progif & 4) == 0) {
region.start = 0x170; region.start = 0x170;
region.end = 0x177; region.end = 0x177;
res = &dev->resource[2]; res = &dev->resource[2];
res->flags = LEGACY_IO_RESOURCE; res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
region.start = 0x376; region.start = 0x376;
region.end = 0x376; region.end = 0x376;
res = &dev->resource[3]; res = &dev->resource[3];
res->flags = LEGACY_IO_RESOURCE; res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
} }
} }
break; break;
@ -1154,6 +1208,18 @@ static void pci_release_capabilities(struct pci_dev *dev)
pci_free_cap_save_buffers(dev); pci_free_cap_save_buffers(dev);
} }
static void pci_free_resources(struct pci_dev *dev)
{
int i;
pci_cleanup_rom(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
release_resource(res);
}
}
/** /**
* pci_release_dev - free a pci device structure when all users of it are finished. * pci_release_dev - free a pci device structure when all users of it are finished.
* @dev: device that's been disconnected * @dev: device that's been disconnected
@ -1163,9 +1229,14 @@ static void pci_release_capabilities(struct pci_dev *dev)
*/ */
static void pci_release_dev(struct device *dev) static void pci_release_dev(struct device *dev)
{ {
struct pci_dev *pci_dev; struct pci_dev *pci_dev = to_pci_dev(dev);
down_write(&pci_bus_sem);
list_del(&pci_dev->bus_list);
up_write(&pci_bus_sem);
pci_free_resources(pci_dev);
pci_dev = to_pci_dev(dev);
pci_release_capabilities(pci_dev); pci_release_capabilities(pci_dev);
pci_release_of_node(pci_dev); pci_release_of_node(pci_dev);
pcibios_release_device(pci_dev); pcibios_release_device(pci_dev);
@ -1173,59 +1244,6 @@ static void pci_release_dev(struct device *dev)
kfree(pci_dev); kfree(pci_dev);
} }
/**
* pci_cfg_space_size - get the configuration space size of the PCI device.
* @dev: PCI device
*
* Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
* have 4096 bytes. Even if the device is capable, that doesn't mean we can
* access it. Maybe we don't have a way to generate extended config space
* accesses, or the device is behind a reverse Express bridge. So we try
* reading the dword at 0x100 which must either be 0 or a valid extended
* capability header.
*/
int pci_cfg_space_size_ext(struct pci_dev *dev)
{
u32 status;
int pos = PCI_CFG_SPACE_SIZE;
if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL)
goto fail;
if (status == 0xffffffff)
goto fail;
return PCI_CFG_SPACE_EXP_SIZE;
fail:
return PCI_CFG_SPACE_SIZE;
}
int pci_cfg_space_size(struct pci_dev *dev)
{
int pos;
u32 status;
u16 class;
class = dev->class >> 8;
if (class == PCI_CLASS_BRIDGE_HOST)
return pci_cfg_space_size_ext(dev);
if (!pci_is_pcie(dev)) {
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (!pos)
goto fail;
pci_read_config_dword(dev, pos + PCI_X_STATUS, &status);
if (!(status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ)))
goto fail;
}
return pci_cfg_space_size_ext(dev);
fail:
return PCI_CFG_SPACE_SIZE;
}
struct pci_dev *pci_alloc_dev(struct pci_bus *bus) struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
{ {
struct pci_dev *dev; struct pci_dev *dev;
@ -1242,12 +1260,6 @@ struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
} }
EXPORT_SYMBOL(pci_alloc_dev); EXPORT_SYMBOL(pci_alloc_dev);
struct pci_dev *alloc_pci_dev(void)
{
return pci_alloc_dev(NULL);
}
EXPORT_SYMBOL(alloc_pci_dev);
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l, bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *l,
int crs_timeout) int crs_timeout)
{ {
@ -1381,8 +1393,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->match_driver = false; dev->match_driver = false;
ret = device_add(&dev->dev); ret = device_add(&dev->dev);
WARN_ON(ret < 0); WARN_ON(ret < 0);
pci_proc_attach_device(dev);
} }
struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
@ -2014,6 +2024,24 @@ EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL(pci_scan_bridge);
EXPORT_SYMBOL_GPL(pci_scan_child_bus); EXPORT_SYMBOL_GPL(pci_scan_child_bus);
/*
* pci_rescan_bus(), pci_rescan_bus_bridge_resize() and PCI device removal
* routines should always be executed under this mutex.
*/
static DEFINE_MUTEX(pci_rescan_remove_lock);
void pci_lock_rescan_remove(void)
{
mutex_lock(&pci_rescan_remove_lock);
}
EXPORT_SYMBOL_GPL(pci_lock_rescan_remove);
void pci_unlock_rescan_remove(void)
{
mutex_unlock(&pci_rescan_remove_lock);
}
EXPORT_SYMBOL_GPL(pci_unlock_rescan_remove);
static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b) static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b)
{ {
const struct pci_dev *a = to_pci_dev(d_a); const struct pci_dev *a = to_pci_dev(d_a);

View file

@ -339,7 +339,7 @@ static void quirk_io_region(struct pci_dev *dev, int port,
/* Convert from PCI bus to resource space */ /* Convert from PCI bus to resource space */
bus_region.start = region; bus_region.start = region;
bus_region.end = region + size - 1; bus_region.end = region + size - 1;
pcibios_bus_to_resource(dev, res, &bus_region); pcibios_bus_to_resource(dev->bus, res, &bus_region);
if (!pci_claim_resource(dev, nr)) if (!pci_claim_resource(dev, nr))
dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name); dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);

View file

@ -3,20 +3,6 @@
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include "pci.h" #include "pci.h"
static void pci_free_resources(struct pci_dev *dev)
{
int i;
msi_remove_pci_irq_vectors(dev);
pci_cleanup_rom(dev);
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *res = dev->resource + i;
if (res->parent)
release_resource(res);
}
}
static void pci_stop_dev(struct pci_dev *dev) static void pci_stop_dev(struct pci_dev *dev)
{ {
pci_pme_active(dev, false); pci_pme_active(dev, false);
@ -34,13 +20,11 @@ static void pci_stop_dev(struct pci_dev *dev)
static void pci_destroy_dev(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev)
{ {
if (!dev->dev.kobj.parent)
return;
device_del(&dev->dev); device_del(&dev->dev);
down_write(&pci_bus_sem);
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
pci_free_resources(dev);
put_device(&dev->dev); put_device(&dev->dev);
} }
@ -114,6 +98,14 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
} }
EXPORT_SYMBOL(pci_stop_and_remove_bus_device); EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev)
{
pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(dev);
pci_unlock_rescan_remove();
}
EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
void pci_stop_root_bus(struct pci_bus *bus) void pci_stop_root_bus(struct pci_bus *bus)
{ {
struct pci_dev *child, *tmp; struct pci_dev *child, *tmp;
@ -128,7 +120,7 @@ void pci_stop_root_bus(struct pci_bus *bus)
pci_stop_bus_device(child); pci_stop_bus_device(child);
/* stop the host bridge */ /* stop the host bridge */
device_del(&host_bridge->dev); device_release_driver(&host_bridge->dev);
} }
void pci_remove_root_bus(struct pci_bus *bus) void pci_remove_root_bus(struct pci_bus *bus)
@ -147,5 +139,5 @@ void pci_remove_root_bus(struct pci_bus *bus)
host_bridge->bus = NULL; host_bridge->bus = NULL;
/* remove the host bridge */ /* remove the host bridge */
put_device(&host_bridge->dev); device_unregister(&host_bridge->dev);
} }

View file

@ -31,7 +31,7 @@ int pci_enable_rom(struct pci_dev *pdev)
if (!res->flags) if (!res->flags)
return -1; return -1;
pcibios_resource_to_bus(pdev, &region, res); pcibios_resource_to_bus(pdev->bus, &region, res);
pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr);
rom_addr &= ~PCI_ROM_ADDRESS_MASK; rom_addr &= ~PCI_ROM_ADDRESS_MASK;
rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE; rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE;

View file

@ -475,7 +475,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
&bus->busn_res); &bus->busn_res);
res = bus->resource[0]; res = bus->resource[0];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
/* /*
* The IO resource is allocated a range twice as large as it * The IO resource is allocated a range twice as large as it
@ -489,7 +489,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
} }
res = bus->resource[1]; res = bus->resource[1];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
dev_info(&bridge->dev, " bridge window %pR\n", res); dev_info(&bridge->dev, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
@ -499,7 +499,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
} }
res = bus->resource[2]; res = bus->resource[2];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
dev_info(&bridge->dev, " bridge window %pR\n", res); dev_info(&bridge->dev, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
@ -509,7 +509,7 @@ void pci_setup_cardbus(struct pci_bus *bus)
} }
res = bus->resource[3]; res = bus->resource[3];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
dev_info(&bridge->dev, " bridge window %pR\n", res); dev_info(&bridge->dev, " bridge window %pR\n", res);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
@ -538,7 +538,8 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
struct pci_bus_region region; struct pci_bus_region region;
unsigned long io_mask; unsigned long io_mask;
u8 io_base_lo, io_limit_lo; u8 io_base_lo, io_limit_lo;
u32 l, io_upper16; u16 l;
u32 io_upper16;
io_mask = PCI_IO_RANGE_MASK; io_mask = PCI_IO_RANGE_MASK;
if (bridge->io_window_1k) if (bridge->io_window_1k)
@ -546,13 +547,12 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
/* Set up the top and bottom of the PCI I/O segment for this bus. */ /* Set up the top and bottom of the PCI I/O segment for this bus. */
res = bus->resource[0]; res = bus->resource[0];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_IO) { if (res->flags & IORESOURCE_IO) {
pci_read_config_dword(bridge, PCI_IO_BASE, &l); pci_read_config_word(bridge, PCI_IO_BASE, &l);
l &= 0xffff0000;
io_base_lo = (region.start >> 8) & io_mask; io_base_lo = (region.start >> 8) & io_mask;
io_limit_lo = (region.end >> 8) & io_mask; io_limit_lo = (region.end >> 8) & io_mask;
l |= ((u32) io_limit_lo << 8) | io_base_lo; l = ((u16) io_limit_lo << 8) | io_base_lo;
/* Set up upper 16 bits of I/O base/limit. */ /* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
dev_info(&bridge->dev, " bridge window %pR\n", res); dev_info(&bridge->dev, " bridge window %pR\n", res);
@ -564,7 +564,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
/* Temporarily disable the I/O range before updating PCI_IO_BASE. */ /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
/* Update lower 16 bits of I/O base/limit. */ /* Update lower 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE, l); pci_write_config_word(bridge, PCI_IO_BASE, l);
/* Update upper 16 bits of I/O base/limit. */ /* Update upper 16 bits of I/O base/limit. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16); pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
} }
@ -578,7 +578,7 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
/* Set up the top and bottom of the PCI Memory segment for this bus. */ /* Set up the top and bottom of the PCI Memory segment for this bus. */
res = bus->resource[1]; res = bus->resource[1];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000; l |= region.end & 0xfff00000;
@ -604,7 +604,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
/* Set up PREF base/limit. */ /* Set up PREF base/limit. */
bu = lu = 0; bu = lu = 0;
res = bus->resource[2]; res = bus->resource[2];
pcibios_resource_to_bus(bridge, &region, res); pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_PREFETCH) { if (res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000; l |= region.end & 0xfff00000;
@ -665,21 +665,23 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)
pci_read_config_word(bridge, PCI_IO_BASE, &io); pci_read_config_word(bridge, PCI_IO_BASE, &io);
if (!io) { if (!io) {
pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0); pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
pci_read_config_word(bridge, PCI_IO_BASE, &io); pci_read_config_word(bridge, PCI_IO_BASE, &io);
pci_write_config_word(bridge, PCI_IO_BASE, 0x0); pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
} }
if (io) if (io)
b_res[0].flags |= IORESOURCE_IO; b_res[0].flags |= IORESOURCE_IO;
/* DECchip 21050 pass 2 errata: the bridge may miss an address /* DECchip 21050 pass 2 errata: the bridge may miss an address
disconnect boundary by one PCI data phase. disconnect boundary by one PCI data phase.
Workaround: do not use prefetching on this device. */ Workaround: do not use prefetching on this device. */
if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001) if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
return; return;
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
if (!pmem) { if (!pmem) {
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
0xfff0fff0); 0xffe0fff0);
pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem); pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
} }
@ -1422,7 +1424,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)
if (!r->flags) if (!r->flags)
continue; continue;
pcibios_resource_to_bus(dev, &region, r); pcibios_resource_to_bus(dev->bus, &region, r);
if (!region.start) { if (!region.start) {
*unassigned = true; *unassigned = true;
return 1; /* return early from pci_walk_bus() */ return 1; /* return early from pci_walk_bus() */

View file

@ -52,7 +52,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (res->flags & IORESOURCE_PCI_FIXED) if (res->flags & IORESOURCE_PCI_FIXED)
return; return;
pcibios_resource_to_bus(dev, &region, res); pcibios_resource_to_bus(dev->bus, &region, res);
new = region.start | (res->flags & PCI_REGION_FLAG_MASK); new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO) if (res->flags & IORESOURCE_IO)

View file

@ -319,32 +319,6 @@ err:
} }
EXPORT_SYMBOL_GPL(pci_create_slot); EXPORT_SYMBOL_GPL(pci_create_slot);
/**
* pci_renumber_slot - update %struct pci_slot -> number
* @slot: &struct pci_slot to update
* @slot_nr: new number for slot
*
* The primary purpose of this interface is to allow callers who earlier
* created a placeholder slot in pci_create_slot() by passing a -1 as
* slot_nr, to update their %struct pci_slot with the correct @slot_nr.
*/
void pci_renumber_slot(struct pci_slot *slot, int slot_nr)
{
struct pci_slot *tmp;
down_write(&pci_bus_sem);
list_for_each_entry(tmp, &slot->bus->slots, list) {
WARN_ON(tmp->number == slot_nr);
goto out;
}
slot->number = slot_nr;
out:
up_write(&pci_bus_sem);
}
EXPORT_SYMBOL_GPL(pci_renumber_slot);
/** /**
* pci_destroy_slot - decrement refcount for physical PCI slot * pci_destroy_slot - decrement refcount for physical PCI slot
* @slot: struct pci_slot to decrement * @slot: struct pci_slot to decrement

434
drivers/pci/vc.c Normal file
View file

@ -0,0 +1,434 @@
/*
* PCI Virtual Channel support
*
* Copyright (C) 2013 Red Hat, Inc. All rights reserved.
* Author: Alex Williamson <alex.williamson@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/types.h>
/**
* pci_vc_save_restore_dwords - Save or restore a series of dwords
* @dev: device
* @pos: starting config space position
* @buf: buffer to save to or restore from
* @dwords: number of dwords to save/restore
* @save: whether to save or restore
*/
static void pci_vc_save_restore_dwords(struct pci_dev *dev, int pos,
u32 *buf, int dwords, bool save)
{
int i;
for (i = 0; i < dwords; i++, buf++) {
if (save)
pci_read_config_dword(dev, pos + (i * 4), buf);
else
pci_write_config_dword(dev, pos + (i * 4), *buf);
}
}
/**
* pci_vc_load_arb_table - load and wait for VC arbitration table
* @dev: device
* @pos: starting position of VC capability (VC/VC9/MFVC)
*
* Set Load VC Arbitration Table bit requesting hardware to apply the VC
* Arbitration Table (previously loaded). When the VC Arbitration Table
* Status clears, hardware has latched the table into VC arbitration logic.
*/
static void pci_vc_load_arb_table(struct pci_dev *dev, int pos)
{
u16 ctrl;
pci_read_config_word(dev, pos + PCI_VC_PORT_CTRL, &ctrl);
pci_write_config_word(dev, pos + PCI_VC_PORT_CTRL,
ctrl | PCI_VC_PORT_CTRL_LOAD_TABLE);
if (pci_wait_for_pending(dev, pos + PCI_VC_PORT_STATUS,
PCI_VC_PORT_STATUS_TABLE))
return;
dev_err(&dev->dev, "VC arbitration table failed to load\n");
}
/**
* pci_vc_load_port_arb_table - Load and wait for VC port arbitration table
* @dev: device
* @pos: starting position of VC capability (VC/VC9/MFVC)
* @res: VC resource number, ie. VCn (0-7)
*
* Set Load Port Arbitration Table bit requesting hardware to apply the Port
* Arbitration Table (previously loaded). When the Port Arbitration Table
* Status clears, hardware has latched the table into port arbitration logic.
*/
static void pci_vc_load_port_arb_table(struct pci_dev *dev, int pos, int res)
{
int ctrl_pos, status_pos;
u32 ctrl;
ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF);
status_pos = pos + PCI_VC_RES_STATUS + (res * PCI_CAP_VC_PER_VC_SIZEOF);
pci_read_config_dword(dev, ctrl_pos, &ctrl);
pci_write_config_dword(dev, ctrl_pos,
ctrl | PCI_VC_RES_CTRL_LOAD_TABLE);
if (pci_wait_for_pending(dev, status_pos, PCI_VC_RES_STATUS_TABLE))
return;
dev_err(&dev->dev, "VC%d port arbitration table failed to load\n", res);
}
/**
* pci_vc_enable - Enable virtual channel
* @dev: device
* @pos: starting position of VC capability (VC/VC9/MFVC)
* @res: VC res number, ie. VCn (0-7)
*
* A VC is enabled by setting the enable bit in matching resource control
* registers on both sides of a link. We therefore need to find the opposite
* end of the link. To keep this simple we enable from the downstream device.
* RC devices do not have an upstream device, nor does it seem that VC9 do
* (spec is unclear). Once we find the upstream device, match the VC ID to
* get the correct resource, disable and enable on both ends.
*/
static void pci_vc_enable(struct pci_dev *dev, int pos, int res)
{
int ctrl_pos, status_pos, id, pos2, evcc, i, ctrl_pos2, status_pos2;
u32 ctrl, header, cap1, ctrl2;
struct pci_dev *link = NULL;
/* Enable VCs from the downstream device */
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
return;
ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF);
status_pos = pos + PCI_VC_RES_STATUS + (res * PCI_CAP_VC_PER_VC_SIZEOF);
pci_read_config_dword(dev, ctrl_pos, &ctrl);
id = ctrl & PCI_VC_RES_CTRL_ID;
pci_read_config_dword(dev, pos, &header);
/* If there is no opposite end of the link, skip to enable */
if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_VC9 ||
pci_is_root_bus(dev->bus))
goto enable;
pos2 = pci_find_ext_capability(dev->bus->self, PCI_EXT_CAP_ID_VC);
if (!pos2)
goto enable;
pci_read_config_dword(dev->bus->self, pos2 + PCI_VC_PORT_CAP1, &cap1);
evcc = cap1 & PCI_VC_CAP1_EVCC;
/* VC0 is hardwired enabled, so we can start with 1 */
for (i = 1; i < evcc + 1; i++) {
ctrl_pos2 = pos2 + PCI_VC_RES_CTRL +
(i * PCI_CAP_VC_PER_VC_SIZEOF);
status_pos2 = pos2 + PCI_VC_RES_STATUS +
(i * PCI_CAP_VC_PER_VC_SIZEOF);
pci_read_config_dword(dev->bus->self, ctrl_pos2, &ctrl2);
if ((ctrl2 & PCI_VC_RES_CTRL_ID) == id) {
link = dev->bus->self;
break;
}
}
if (!link)
goto enable;
/* Disable if enabled */
if (ctrl2 & PCI_VC_RES_CTRL_ENABLE) {
ctrl2 &= ~PCI_VC_RES_CTRL_ENABLE;
pci_write_config_dword(link, ctrl_pos2, ctrl2);
}
/* Enable on both ends */
ctrl2 |= PCI_VC_RES_CTRL_ENABLE;
pci_write_config_dword(link, ctrl_pos2, ctrl2);
enable:
ctrl |= PCI_VC_RES_CTRL_ENABLE;
pci_write_config_dword(dev, ctrl_pos, ctrl);
if (!pci_wait_for_pending(dev, status_pos, PCI_VC_RES_STATUS_NEGO))
dev_err(&dev->dev, "VC%d negotiation stuck pending\n", id);
if (link && !pci_wait_for_pending(link, status_pos2,
PCI_VC_RES_STATUS_NEGO))
dev_err(&link->dev, "VC%d negotiation stuck pending\n", id);
}
/**
* pci_vc_do_save_buffer - Size, save, or restore VC state
* @dev: device
* @pos: starting position of VC capability (VC/VC9/MFVC)
* @save_state: buffer for save/restore
* @name: for error message
* @save: if provided a buffer, this indicates what to do with it
*
* Walking Virtual Channel config space to size, save, or restore it
* is complicated, so we do it all from one function to reduce code and
* guarantee ordering matches in the buffer. When called with NULL
* @save_state, return the size of the necessary save buffer. When called
* with a non-NULL @save_state, @save determines whether we save to the
* buffer or restore from it.
*/
static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos,
struct pci_cap_saved_state *save_state,
bool save)
{
u32 cap1;
char evcc, lpevcc, parb_size;
int i, len = 0;
u8 *buf = save_state ? (u8 *)save_state->cap.data : NULL;
/* Sanity check buffer size for save/restore */
if (buf && save_state->cap.size !=
pci_vc_do_save_buffer(dev, pos, NULL, save)) {
dev_err(&dev->dev,
"VC save buffer size does not match @0x%x\n", pos);
return -ENOMEM;
}
pci_read_config_dword(dev, pos + PCI_VC_PORT_CAP1, &cap1);
/* Extended VC Count (not counting VC0) */
evcc = cap1 & PCI_VC_CAP1_EVCC;
/* Low Priority Extended VC Count (not counting VC0) */
lpevcc = (cap1 & PCI_VC_CAP1_LPEVCC) >> 4;
/* Port Arbitration Table Entry Size (bits) */
parb_size = 1 << ((cap1 & PCI_VC_CAP1_ARB_SIZE) >> 10);
/*
* Port VC Control Register contains VC Arbitration Select, which
* cannot be modified when more than one LPVC is in operation. We
* therefore save/restore it first, as only VC0 should be enabled
* after device reset.
*/
if (buf) {
if (save)
pci_read_config_word(dev, pos + PCI_VC_PORT_CTRL,
(u16 *)buf);
else
pci_write_config_word(dev, pos + PCI_VC_PORT_CTRL,
*(u16 *)buf);
buf += 2;
}
len += 2;
/*
* If we have any Low Priority VCs and a VC Arbitration Table Offset
* in Port VC Capability Register 2 then save/restore it next.
*/
if (lpevcc) {
u32 cap2;
int vcarb_offset;
pci_read_config_dword(dev, pos + PCI_VC_PORT_CAP2, &cap2);
vcarb_offset = ((cap2 & PCI_VC_CAP2_ARB_OFF) >> 24) * 16;
if (vcarb_offset) {
int size, vcarb_phases = 0;
if (cap2 & PCI_VC_CAP2_128_PHASE)
vcarb_phases = 128;
else if (cap2 & PCI_VC_CAP2_64_PHASE)
vcarb_phases = 64;
else if (cap2 & PCI_VC_CAP2_32_PHASE)
vcarb_phases = 32;
/* Fixed 4 bits per phase per lpevcc (plus VC0) */
size = ((lpevcc + 1) * vcarb_phases * 4) / 8;
if (size && buf) {
pci_vc_save_restore_dwords(dev,
pos + vcarb_offset,
(u32 *)buf,
size / 4, save);
/*
* On restore, we need to signal hardware to
* re-load the VC Arbitration Table.
*/
if (!save)
pci_vc_load_arb_table(dev, pos);
buf += size;
}
len += size;
}
}
/*
* In addition to each VC Resource Control Register, we may have a
* Port Arbitration Table attached to each VC. The Port Arbitration
* Table Offset in each VC Resource Capability Register tells us if
* it exists. The entry size is global from the Port VC Capability
* Register1 above. The number of phases is determined per VC.
*/
for (i = 0; i < evcc + 1; i++) {
u32 cap;
int parb_offset;
pci_read_config_dword(dev, pos + PCI_VC_RES_CAP +
(i * PCI_CAP_VC_PER_VC_SIZEOF), &cap);
parb_offset = ((cap & PCI_VC_RES_CAP_ARB_OFF) >> 24) * 16;
if (parb_offset) {
int size, parb_phases = 0;
if (cap & PCI_VC_RES_CAP_256_PHASE)
parb_phases = 256;
else if (cap & (PCI_VC_RES_CAP_128_PHASE |
PCI_VC_RES_CAP_128_PHASE_TB))
parb_phases = 128;
else if (cap & PCI_VC_RES_CAP_64_PHASE)
parb_phases = 64;
else if (cap & PCI_VC_RES_CAP_32_PHASE)
parb_phases = 32;
size = (parb_size * parb_phases) / 8;
if (size && buf) {
pci_vc_save_restore_dwords(dev,
pos + parb_offset,
(u32 *)buf,
size / 4, save);
buf += size;
}
len += size;
}
/* VC Resource Control Register */
if (buf) {
int ctrl_pos = pos + PCI_VC_RES_CTRL +
(i * PCI_CAP_VC_PER_VC_SIZEOF);
if (save)
pci_read_config_dword(dev, ctrl_pos,
(u32 *)buf);
else {
u32 tmp, ctrl = *(u32 *)buf;
/*
* For an FLR case, the VC config may remain.
* Preserve enable bit, restore the rest.
*/
pci_read_config_dword(dev, ctrl_pos, &tmp);
tmp &= PCI_VC_RES_CTRL_ENABLE;
tmp |= ctrl & ~PCI_VC_RES_CTRL_ENABLE;
pci_write_config_dword(dev, ctrl_pos, tmp);
/* Load port arbitration table if used */
if (ctrl & PCI_VC_RES_CTRL_ARB_SELECT)
pci_vc_load_port_arb_table(dev, pos, i);
/* Re-enable if needed */
if ((ctrl ^ tmp) & PCI_VC_RES_CTRL_ENABLE)
pci_vc_enable(dev, pos, i);
}
buf += 4;
}
len += 4;
}
return buf ? 0 : len;
}
static struct {
u16 id;
const char *name;
} vc_caps[] = { { PCI_EXT_CAP_ID_MFVC, "MFVC" },
{ PCI_EXT_CAP_ID_VC, "VC" },
{ PCI_EXT_CAP_ID_VC9, "VC9" } };
/**
* pci_save_vc_state - Save VC state to pre-allocate save buffer
* @dev: device
*
* For each type of VC capability, VC/VC9/MFVC, find the capability and
* save it to the pre-allocated save buffer.
*/
int pci_save_vc_state(struct pci_dev *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
int pos, ret;
struct pci_cap_saved_state *save_state;
pos = pci_find_ext_capability(dev, vc_caps[i].id);
if (!pos)
continue;
save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
if (!save_state) {
dev_err(&dev->dev, "%s buffer not found in %s\n",
vc_caps[i].name, __func__);
return -ENOMEM;
}
ret = pci_vc_do_save_buffer(dev, pos, save_state, true);
if (ret) {
dev_err(&dev->dev, "%s save unsuccessful %s\n",
vc_caps[i].name, __func__);
return ret;
}
}
return 0;
}
/**
* pci_restore_vc_state - Restore VC state from save buffer
* @dev: device
*
* For each type of VC capability, VC/VC9/MFVC, find the capability and
* restore it from the previously saved buffer.
*/
void pci_restore_vc_state(struct pci_dev *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
int pos;
struct pci_cap_saved_state *save_state;
pos = pci_find_ext_capability(dev, vc_caps[i].id);
save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id);
if (!save_state || !pos)
continue;
pci_vc_do_save_buffer(dev, pos, save_state, false);
}
}
/**
* pci_allocate_vc_save_buffers - Allocate save buffers for VC caps
* @dev: device
*
* For each type of VC capability, VC/VC9/MFVC, find the capability, size
* it, and allocate a buffer for save/restore.
*/
void pci_allocate_vc_save_buffers(struct pci_dev *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(vc_caps); i++) {
int len, pos = pci_find_ext_capability(dev, vc_caps[i].id);
if (!pos)
continue;
len = pci_vc_do_save_buffer(dev, pos, NULL, false);
if (pci_add_ext_cap_save_buffer(dev, vc_caps[i].id, len))
dev_err(&dev->dev,
"unable to preallocate %s save buffer\n",
vc_caps[i].name);
}
}

View file

@ -471,12 +471,15 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
} }
pcifront_init_sd(sd, domain, bus, pdev); pcifront_init_sd(sd, domain, bus, pdev);
pci_lock_rescan_remove();
b = pci_scan_bus_parented(&pdev->xdev->dev, bus, b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
&pcifront_bus_ops, sd); &pcifront_bus_ops, sd);
if (!b) { if (!b) {
dev_err(&pdev->xdev->dev, dev_err(&pdev->xdev->dev,
"Error creating PCI Frontend Bus!\n"); "Error creating PCI Frontend Bus!\n");
err = -ENOMEM; err = -ENOMEM;
pci_unlock_rescan_remove();
goto err_out; goto err_out;
} }
@ -494,6 +497,7 @@ static int pcifront_scan_root(struct pcifront_device *pdev,
/* Create SysFS and notify udev of the devices. Aka: "going live" */ /* Create SysFS and notify udev of the devices. Aka: "going live" */
pci_bus_add_devices(b); pci_bus_add_devices(b);
pci_unlock_rescan_remove();
return err; return err;
err_out: err_out:
@ -556,6 +560,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
pci_lock_rescan_remove();
list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
list_del(&bus_entry->list); list_del(&bus_entry->list);
@ -568,6 +573,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev)
kfree(bus_entry); kfree(bus_entry);
} }
pci_unlock_rescan_remove();
} }
static pci_ers_result_t pcifront_common_process(int cmd, static pci_ers_result_t pcifront_common_process(int cmd,
@ -1043,8 +1049,10 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
domain, bus, slot, func); domain, bus, slot, func);
continue; continue;
} }
pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(pci_dev); pci_stop_and_remove_bus_device(pci_dev);
pci_dev_put(pci_dev); pci_dev_put(pci_dev);
pci_unlock_rescan_remove();
dev_dbg(&pdev->xdev->dev, dev_dbg(&pdev->xdev->dev,
"PCI device %04x:%02x:%02x.%d removed.\n", "PCI device %04x:%02x:%02x.%d removed.\n",

View file

@ -70,6 +70,8 @@ int __ref cb_alloc(struct pcmcia_socket *s)
struct pci_dev *dev; struct pci_dev *dev;
unsigned int max, pass; unsigned int max, pass;
pci_lock_rescan_remove();
s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0));
pci_fixup_cardbus(bus); pci_fixup_cardbus(bus);
@ -93,6 +95,7 @@ int __ref cb_alloc(struct pcmcia_socket *s)
pci_bus_add_devices(bus); pci_bus_add_devices(bus);
pci_unlock_rescan_remove();
return 0; return 0;
} }
@ -115,6 +118,10 @@ void cb_free(struct pcmcia_socket *s)
if (!bus) if (!bus)
return; return;
pci_lock_rescan_remove();
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list)
pci_stop_and_remove_bus_device(dev); pci_stop_and_remove_bus_device(dev);
pci_unlock_rescan_remove();
} }

View file

@ -608,7 +608,7 @@ static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_
enter("i82092aa_set_mem_map"); enter("i82092aa_set_mem_map");
pcibios_resource_to_bus(sock_info->dev, &region, mem->res); pcibios_resource_to_bus(sock_info->dev->bus, &region, mem->res);
map = mem->map; map = mem->map;
if (map > 4) { if (map > 4) {

View file

@ -445,7 +445,7 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *
unsigned int start, stop, card_start; unsigned int start, stop, card_start;
unsigned short word; unsigned short word;
pcibios_resource_to_bus(socket->dev, &region, mem->res); pcibios_resource_to_bus(socket->dev->bus, &region, mem->res);
map = mem->map; map = mem->map;
start = region.start; start = region.start;
@ -709,7 +709,7 @@ static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type
region.start = config_readl(socket, addr_start) & mask; region.start = config_readl(socket, addr_start) & mask;
region.end = config_readl(socket, addr_end) | ~mask; region.end = config_readl(socket, addr_end) | ~mask;
if (region.start && region.end > region.start && !override_bios) { if (region.start && region.end > region.start && !override_bios) {
pcibios_bus_to_resource(dev, res, &region); pcibios_bus_to_resource(dev->bus, res, &region);
if (pci_claim_resource(dev, PCI_BRIDGE_RESOURCES + nr) == 0) if (pci_claim_resource(dev, PCI_BRIDGE_RESOURCES + nr) == 0)
return 0; return 0;
dev_printk(KERN_INFO, &dev->dev, dev_printk(KERN_INFO, &dev->dev,
@ -1033,7 +1033,7 @@ static void yenta_config_init(struct yenta_socket *socket)
struct pci_dev *dev = socket->dev; struct pci_dev *dev = socket->dev;
struct pci_bus_region region; struct pci_bus_region region;
pcibios_resource_to_bus(socket->dev, &region, &dev->resource[0]); pcibios_resource_to_bus(socket->dev->bus, &region, &dev->resource[0]);
config_writel(socket, CB_LEGACY_MODE_BASE, 0); config_writel(socket, CB_LEGACY_MODE_BASE, 0);
config_writel(socket, PCI_BASE_ADDRESS_0, region.start); config_writel(socket, PCI_BASE_ADDRESS_0, region.start);

View file

@ -606,6 +606,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
mutex_unlock(&asus->wmi_lock); mutex_unlock(&asus->wmi_lock);
mutex_lock(&asus->hotplug_lock); mutex_lock(&asus->hotplug_lock);
pci_lock_rescan_remove();
if (asus->wlan.rfkill) if (asus->wlan.rfkill)
rfkill_set_sw_state(asus->wlan.rfkill, blocked); rfkill_set_sw_state(asus->wlan.rfkill, blocked);
@ -656,6 +657,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
} }
out_unlock: out_unlock:
pci_unlock_rescan_remove();
mutex_unlock(&asus->hotplug_lock); mutex_unlock(&asus->hotplug_lock);
} }

View file

@ -592,6 +592,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
mutex_lock(&eeepc->hotplug_lock); mutex_lock(&eeepc->hotplug_lock);
pci_lock_rescan_remove();
if (eeepc->hotplug_slot) { if (eeepc->hotplug_slot) {
port = acpi_get_pci_dev(handle); port = acpi_get_pci_dev(handle);
@ -649,6 +650,7 @@ out_put_dev:
} }
out_unlock: out_unlock:
pci_unlock_rescan_remove();
mutex_unlock(&eeepc->hotplug_lock); mutex_unlock(&eeepc->hotplug_lock);
} }

View file

@ -128,7 +128,7 @@ static int mpt2sas_remove_dead_ioc_func(void *arg)
pdev = ioc->pdev; pdev = ioc->pdev;
if ((pdev == NULL)) if ((pdev == NULL))
return -1; return -1;
pci_stop_and_remove_bus_device(pdev); pci_stop_and_remove_bus_device_locked(pdev);
return 0; return 0;
} }

View file

@ -131,7 +131,7 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
pdev = ioc->pdev; pdev = ioc->pdev;
if ((pdev == NULL)) if ((pdev == NULL))
return -1; return -1;
pci_stop_and_remove_bus_device(pdev); pci_stop_and_remove_bus_device_locked(pdev);
return 0; return 0;
} }

View file

@ -1531,7 +1531,7 @@ static int sym_iomap_device(struct sym_device *device)
struct pci_bus_region bus_addr; struct pci_bus_region bus_addr;
int i = 2; int i = 2;
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); pcibios_resource_to_bus(pdev->bus, &bus_addr, &pdev->resource[1]);
device->mmio_base = bus_addr.start; device->mmio_base = bus_addr.start;
if (device->chip.features & FE_RAM) { if (device->chip.features & FE_RAM) {
@ -1541,7 +1541,8 @@ static int sym_iomap_device(struct sym_device *device)
*/ */
if (!pdev->resource[i].flags) if (!pdev->resource[i].flags)
i++; i++;
pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); pcibios_resource_to_bus(pdev->bus, &bus_addr,
&pdev->resource[i]);
device->ram_base = bus_addr.start; device->ram_base = bus_addr.start;
} }

View file

@ -139,25 +139,14 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
/* /*
* Careful, device_lock may already be held. This is the case if * Try to reset the device. The success of this is dependent on
* a driver unbind is blocked. Try to get the locks ourselves to * being able to lock the device, which is not always possible.
* prevent a deadlock.
*/ */
if (vdev->reset_works) { if (vdev->reset_works) {
bool reset_done = false; int ret = pci_try_reset_function(pdev);
if (ret)
if (pci_cfg_access_trylock(pdev)) { pr_warn("%s: Failed to reset device %s (%d)\n",
if (device_trylock(&pdev->dev)) { __func__, dev_name(&pdev->dev), ret);
__pci_reset_function_locked(pdev);
reset_done = true;
device_unlock(&pdev->dev);
}
pci_cfg_access_unlock(pdev);
}
if (!reset_done)
pr_warn("%s: Unable to acquire locks for reset of %s\n",
__func__, dev_name(&pdev->dev));
} }
pci_restore_state(pdev); pci_restore_state(pdev);
@ -514,7 +503,7 @@ static long vfio_pci_ioctl(void *device_data,
} else if (cmd == VFIO_DEVICE_RESET) { } else if (cmd == VFIO_DEVICE_RESET) {
return vdev->reset_works ? return vdev->reset_works ?
pci_reset_function(vdev->pdev) : -EINVAL; pci_try_reset_function(vdev->pdev) : -EINVAL;
} else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) { } else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {
struct vfio_pci_hot_reset_info hdr; struct vfio_pci_hot_reset_info hdr;
@ -684,8 +673,8 @@ reset_info_exit:
&info, slot); &info, slot);
if (!ret) if (!ret)
/* User has access, do the reset */ /* User has access, do the reset */
ret = slot ? pci_reset_slot(vdev->pdev->slot) : ret = slot ? pci_try_reset_slot(vdev->pdev->slot) :
pci_reset_bus(vdev->pdev->bus); pci_try_reset_bus(vdev->pdev->bus);
hot_reset_release: hot_reset_release:
for (i--; i >= 0; i--) for (i--; i >= 0; i--)

View file

@ -975,20 +975,20 @@ static int vfio_vc_cap_len(struct vfio_pci_device *vdev, u16 pos)
int ret, evcc, phases, vc_arb; int ret, evcc, phases, vc_arb;
int len = PCI_CAP_VC_BASE_SIZEOF; int len = PCI_CAP_VC_BASE_SIZEOF;
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG1, &tmp); ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP1, &tmp);
if (ret) if (ret)
return pcibios_err_to_errno(ret); return pcibios_err_to_errno(ret);
evcc = tmp & PCI_VC_REG1_EVCC; /* extended vc count */ evcc = tmp & PCI_VC_CAP1_EVCC; /* extended vc count */
ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG2, &tmp); ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP2, &tmp);
if (ret) if (ret)
return pcibios_err_to_errno(ret); return pcibios_err_to_errno(ret);
if (tmp & PCI_VC_REG2_128_PHASE) if (tmp & PCI_VC_CAP2_128_PHASE)
phases = 128; phases = 128;
else if (tmp & PCI_VC_REG2_64_PHASE) else if (tmp & PCI_VC_CAP2_64_PHASE)
phases = 64; phases = 64;
else if (tmp & PCI_VC_REG2_32_PHASE) else if (tmp & PCI_VC_CAP2_32_PHASE)
phases = 32; phases = 32;
else else
phases = 0; phases = 0;

Some files were not shown because too many files have changed in this diff Show more