mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 07:12:09 +00:00
pci-v4.19-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAlt1f9AUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vxbdhAArnhRvkwOk4m4/LCuKF6HpmlxbBNC TjnBCenNf+lFXzWskfDFGFl/Wif4UzGbRTSCNQrwMzj3Ww3f/6R2QIq9rEJvyNC4 VdxQnaBEZSUgN87q5UGqgdjMTo3zFvlFH6fpb5XDiQ5IX/QZeXeYqoB64w+HvKPU M+IsoOvnA5gb7pMcpchrGUnSfS1e6AqQbbTt6tZflore6YCEA4cH5OnpGx8qiZIp ut+CMBvQjQB01fHeBc/wGrVte4NwXdONrXqpUb4sHF7HqRNfEh0QVyPhvebBi+k1 kquqoBQfPFTqgcab31VOcQhg70dEx+1qGm5/YBAwmhCpHR/g2gioFXoROsr+iUOe BtF6LZr+Y8cySuhJnkCrJBqWvvBaKbJLg0KMbI+7p4o9MZpod2u7LS5LFrlRDyKW 3nz3o+b1+v3tCCKVKIhKo0ljolgkweQtR1f6KIHvq93wBODHVQnAOt9NlPfHVyks ryGBnOhMjoU5hvfexgIWFk9Ph9MEVQSffkI+TeFPO/tyGBfGfQyGtESiXuEaMQaH FGdZHX2RLkY3pWHOtWeMzRHzOnr2XjpDFcAqL3HBGPdJ30K3Umv3WOgoFe2SaocG 0gaddPjKSwwM4Sa/VP+O5cjGuzi7QnczSDdpYjxIGZzBav32hqx4/rsnLw7bHH8y XkEme7cYJc8MGsA= =2Dmn -----END PGP SIGNATURE----- Merge tag 'pci-v4.19-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull pci updates from Bjorn Helgaas: - Decode AER errors with names similar to "lspci" (Tyler Baicar) - Expose AER statistics in sysfs (Rajat Jain) - Clear AER status bits selectively based on the type of recovery (Oza Pawandeep) - Honor "pcie_ports=native" even if HEST sets FIRMWARE_FIRST (Alexandru Gagniuc) - Don't clear AER status bits if we're using the "Firmware-First" strategy where firmware owns the registers (Alexandru Gagniuc) - Use sysfs_match_string() to simplify ASPM sysfs parsing (Andy Shevchenko) - Remove unnecessary includes of <linux/pci-aspm.h> (Bjorn Helgaas) - Defer DPC event handling to work queue (Keith Busch) - Use threaded IRQ for DPC bottom half (Keith Busch) - Print AER status while handling DPC events (Keith Busch) - Work around IDT switch ACS Source Validation erratum (James Puthukattukaran) - Emit diagnostics for all cases of PCIe Link downtraining (Links operating slower than they're capable of) (Alexandru Gagniuc) - Skip VFs when configuring Max Payload Size (Myron Stowe) - Reduce Root Port Max Payload Size if necessary when hot-adding a device below it (Myron Stowe) - Simplify SHPC existence/permission checks (Bjorn Helgaas) - Remove hotplug sample skeleton driver (Lukas Wunner) - Convert pciehp to threaded IRQ handling (Lukas Wunner) - Improve pciehp tolerance of missed events and initially unstable links (Lukas Wunner) - Clear spurious pciehp events on resume (Lukas Wunner) - Add pciehp runtime PM support, including for Thunderbolt controllers (Lukas Wunner) - Support interrupts from pciehp bridges in D3hot (Lukas Wunner) - Mark fall-through switch cases before enabling -Wimplicit-fallthrough (Gustavo A. R. Silva) - Move DMA-debug PCI init from arch code to PCI core (Christoph Hellwig) - Fix pci_request_irq() usage of IRQF_ONESHOT when no handler is supplied (Heiner Kallweit) - Unify PCI and DMA direction #defines (Shunyong Yang) - Add PCI_DEVICE_DATA() macro (Andy Shevchenko) - Check for VPD completion before checking for timeout (Bert Kenward) - Limit Netronome NFP5000 config space size to work around erratum (Jakub Kicinski) - Set IRQCHIP_ONESHOT_SAFE for PCI MSI irqchips (Heiner Kallweit) - Document ACPI description of PCI host bridges (Bjorn Helgaas) - Add "pci=disable_acs_redir=" parameter to disable ACS redirection for peer-to-peer DMA support (we don't have the peer-to-peer support yet; this is just one piece) (Logan Gunthorpe) - Clean up devm_of_pci_get_host_bridge_resources() resource allocation (Jan Kiszka) - Fixup resizable BARs after suspend/resume (Christian König) - Make "pci=earlydump" generic (Sinan Kaya) - Fix ROM BAR access routines to stay in bounds and check for signature correctly (Rex Zhu) - Add DMA alias quirk for Microsemi Switchtec NTB (Doug Meyer) - Expand documentation for pci_add_dma_alias() (Logan Gunthorpe) - To avoid bus errors, enable PASID only if entire path supports End-End TLP prefixes (Sinan Kaya) - Unify slot and bus reset functions and remove hotplug knowledge from callers (Sinan Kaya) - Add Function-Level Reset quirks for Intel and Samsung NVMe devices to fix guest reboot issues (Alex Williamson) - Add function 1 DMA alias quirk for Marvell 88SS9183 PCIe SSD Controller (Bjorn Helgaas) - Remove Xilinx AXI-PCIe host bridge arch dependency (Palmer Dabbelt) - Remove Aardvark outbound window configuration (Evan Wang) - Fix Aardvark bridge window sizing issue (Zachary Zhang) - Convert Aardvark to use pci_host_probe() to reduce code duplication (Thomas Petazzoni) - Correct the Cadence cdns_pcie_writel() signature (Alan Douglas) - Add Cadence support for optional generic PHYs (Alan Douglas) - Add Cadence power management ops (Alan Douglas) - Remove redundant variable from Cadence driver (Colin Ian King) - Add Kirin MSI support (Xiaowei Song) - Drop unnecessary root_bus_nr setting from exynos, imx6, keystone, armada8k, artpec6, designware-plat, histb, qcom, spear13xx (Shawn Guo) - Move link notification settings from DesignWare core to individual drivers (Gustavo Pimentel) - Add endpoint library MSI-X interfaces (Gustavo Pimentel) - Correct signature of endpoint library IRQ interfaces (Gustavo Pimentel) - Add DesignWare endpoint library MSI-X callbacks (Gustavo Pimentel) - Add endpoint library MSI-X test support (Gustavo Pimentel) - Remove unnecessary GFP_ATOMIC from Hyper-V "new child" allocation (Jia-Ju Bai) - Add more devices to Broadcom PAXC quirk (Ray Jui) - Work around corrupted Broadcom PAXC config space to enable SMMU and GICv3 ITS (Ray Jui) - Disable MSI parsing to work around broken Broadcom PAXC logic in some devices (Ray Jui) - Hide unconfigured functions to work around a Broadcom PAXC defect (Ray Jui) - Lower iproc log level to reduce console output during boot (Ray Jui) - Fix mobiveil iomem/phys_addr_t type usage (Lorenzo Pieralisi) - Fix mobiveil missing include file (Lorenzo Pieralisi) - Add mobiveil Kconfig/Makefile support (Lorenzo Pieralisi) - Fix mvebu I/O space remapping issues (Thomas Petazzoni) - Use generic pci_host_bridge in mvebu instead of ARM-specific API (Thomas Petazzoni) - Whitelist VMD devices with fast interrupt handlers to avoid sharing vectors with slow handlers (Keith Busch) * tag 'pci-v4.19-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (153 commits) PCI/AER: Don't clear AER bits if error handling is Firmware-First PCI: Limit config space size for Netronome NFP5000 PCI/MSI: Set IRQCHIP_ONESHOT_SAFE for PCI-MSI irqchips PCI/VPD: Check for VPD access completion before checking for timeout PCI: Add PCI_DEVICE_DATA() macro to fully describe device ID entry PCI: Match Root Port's MPS to endpoint's MPSS as necessary PCI: Skip MPS logic for Virtual Functions (VFs) PCI: Add function 1 DMA alias quirk for Marvell 88SS9183 PCI: Check for PCIe Link downtraining PCI: Add ACS Redirect disable quirk for Intel Sunrise Point PCI: Add device-specific ACS Redirect disable infrastructure PCI: Convert device-specific ACS quirks from NULL termination to ARRAY_SIZE PCI: Add "pci=disable_acs_redir=" parameter for peer-to-peer support PCI: Allow specifying devices using a base bus and path of devfns PCI: Make specifying PCI devices in kernel parameters reusable PCI: Hide ACS quirk declarations inside PCI core PCI: Delay after FLR of Intel DC P3700 NVMe PCI: Disable Samsung SM961/PM961 NVMe before FLR PCI: Export pcie_has_flr() PCI: mvebu: Drop bogus comment above mvebu_pcie_map_registers() ...
This commit is contained in:
commit
4e31843f68
115 changed files with 3593 additions and 1808 deletions
|
@ -23,7 +23,6 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/logic_pio.h>
|
||||
#include <linux/pci-aspm.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -115,6 +114,9 @@ static bool pcie_ari_disabled;
|
|||
/* If set, the PCIe ATS capability will not be used. */
|
||||
static bool pcie_ats_disabled;
|
||||
|
||||
/* If set, the PCI config space of each device is printed during boot. */
|
||||
bool pci_early_dump;
|
||||
|
||||
bool pci_ats_disabled(void)
|
||||
{
|
||||
return pcie_ats_disabled;
|
||||
|
@ -191,6 +193,168 @@ void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar)
|
|||
EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* pci_dev_str_match_path - test if a path string matches a device
|
||||
* @dev: the PCI device to test
|
||||
* @p: string to match the device against
|
||||
* @endptr: pointer to the string after the match
|
||||
*
|
||||
* Test if a string (typically from a kernel parameter) formatted as a
|
||||
* path of device/function addresses matches a PCI device. The string must
|
||||
* be of the form:
|
||||
*
|
||||
* [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
|
||||
*
|
||||
* A path for a device can be obtained using 'lspci -t'. Using a path
|
||||
* is more robust against bus renumbering than using only a single bus,
|
||||
* device and function address.
|
||||
*
|
||||
* Returns 1 if the string matches the device, 0 if it does not and
|
||||
* a negative error code if it fails to parse the string.
|
||||
*/
|
||||
static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
|
||||
const char **endptr)
|
||||
{
|
||||
int ret;
|
||||
int seg, bus, slot, func;
|
||||
char *wpath, *p;
|
||||
char end;
|
||||
|
||||
*endptr = strchrnul(path, ';');
|
||||
|
||||
wpath = kmemdup_nul(path, *endptr - path, GFP_KERNEL);
|
||||
if (!wpath)
|
||||
return -ENOMEM;
|
||||
|
||||
while (1) {
|
||||
p = strrchr(wpath, '/');
|
||||
if (!p)
|
||||
break;
|
||||
ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
|
||||
if (ret != 2) {
|
||||
ret = -EINVAL;
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
if (dev->devfn != PCI_DEVFN(slot, func)) {
|
||||
ret = 0;
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: we don't need to get a reference to the upstream
|
||||
* bridge because we hold a reference to the top level
|
||||
* device which should hold a reference to the bridge,
|
||||
* and so on.
|
||||
*/
|
||||
dev = pci_upstream_bridge(dev);
|
||||
if (!dev) {
|
||||
ret = 0;
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
|
||||
&func, &end);
|
||||
if (ret != 4) {
|
||||
seg = 0;
|
||||
ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
|
||||
if (ret != 3) {
|
||||
ret = -EINVAL;
|
||||
goto free_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = (seg == pci_domain_nr(dev->bus) &&
|
||||
bus == dev->bus->number &&
|
||||
dev->devfn == PCI_DEVFN(slot, func));
|
||||
|
||||
free_and_exit:
|
||||
kfree(wpath);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_dev_str_match - test if a string matches a device
|
||||
* @dev: the PCI device to test
|
||||
* @p: string to match the device against
|
||||
* @endptr: pointer to the string after the match
|
||||
*
|
||||
* Test if a string (typically from a kernel parameter) matches a specified
|
||||
* PCI device. The string may be of one of the following formats:
|
||||
*
|
||||
* [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
|
||||
* pci:<vendor>:<device>[:<subvendor>:<subdevice>]
|
||||
*
|
||||
* The first format specifies a PCI bus/device/function address which
|
||||
* may change if new hardware is inserted, if motherboard firmware changes,
|
||||
* or due to changes caused in kernel parameters. If the domain is
|
||||
* left unspecified, it is taken to be 0. In order to be robust against
|
||||
* bus renumbering issues, a path of PCI device/function numbers may be used
|
||||
* to address the specific device. The path for a device can be determined
|
||||
* through the use of 'lspci -t'.
|
||||
*
|
||||
* The second format matches devices using IDs in the configuration
|
||||
* space which may match multiple devices in the system. A value of 0
|
||||
* for any field will match all devices. (Note: this differs from
|
||||
* in-kernel code that uses PCI_ANY_ID which is ~0; this is for
|
||||
* legacy reasons and convenience so users don't have to specify
|
||||
* FFFFFFFFs on the command line.)
|
||||
*
|
||||
* Returns 1 if the string matches the device, 0 if it does not and
|
||||
* a negative error code if the string cannot be parsed.
|
||||
*/
|
||||
static int pci_dev_str_match(struct pci_dev *dev, const char *p,
|
||||
const char **endptr)
|
||||
{
|
||||
int ret;
|
||||
int count;
|
||||
unsigned short vendor, device, subsystem_vendor, subsystem_device;
|
||||
|
||||
if (strncmp(p, "pci:", 4) == 0) {
|
||||
/* PCI vendor/device (subvendor/subdevice) IDs are specified */
|
||||
p += 4;
|
||||
ret = sscanf(p, "%hx:%hx:%hx:%hx%n", &vendor, &device,
|
||||
&subsystem_vendor, &subsystem_device, &count);
|
||||
if (ret != 4) {
|
||||
ret = sscanf(p, "%hx:%hx%n", &vendor, &device, &count);
|
||||
if (ret != 2)
|
||||
return -EINVAL;
|
||||
|
||||
subsystem_vendor = 0;
|
||||
subsystem_device = 0;
|
||||
}
|
||||
|
||||
p += count;
|
||||
|
||||
if ((!vendor || vendor == dev->vendor) &&
|
||||
(!device || device == dev->device) &&
|
||||
(!subsystem_vendor ||
|
||||
subsystem_vendor == dev->subsystem_vendor) &&
|
||||
(!subsystem_device ||
|
||||
subsystem_device == dev->subsystem_device))
|
||||
goto found;
|
||||
} else {
|
||||
/*
|
||||
* PCI Bus, Device, Function IDs are specified
|
||||
* (optionally, may include a path of devfns following it)
|
||||
*/
|
||||
ret = pci_dev_str_match_path(dev, p, &p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret)
|
||||
goto found;
|
||||
}
|
||||
|
||||
*endptr = p;
|
||||
return 0;
|
||||
|
||||
found:
|
||||
*endptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap, int *ttl)
|
||||
|
@ -1171,6 +1335,33 @@ static void pci_restore_config_space(struct pci_dev *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
static void pci_restore_rebar_state(struct pci_dev *pdev)
|
||||
{
|
||||
unsigned int pos, nbars, i;
|
||||
u32 ctrl;
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR);
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
|
||||
for (i = 0; i < nbars; i++, pos += 8) {
|
||||
struct resource *res;
|
||||
int bar_idx, size;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
|
||||
res = pdev->resource + bar_idx;
|
||||
size = order_base_2((resource_size(res) >> 20) | 1) - 1;
|
||||
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
|
||||
ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_restore_state - Restore the saved state of a PCI device
|
||||
* @dev: - PCI device that we're dealing with
|
||||
|
@ -1186,6 +1377,7 @@ void pci_restore_state(struct pci_dev *dev)
|
|||
pci_restore_pri_state(dev);
|
||||
pci_restore_ats_state(dev);
|
||||
pci_restore_vc_state(dev);
|
||||
pci_restore_rebar_state(dev);
|
||||
|
||||
pci_cleanup_aer_error_status_regs(dev);
|
||||
|
||||
|
@ -2045,6 +2237,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
|
|||
case PCI_D2:
|
||||
if (pci_no_d1d2(dev))
|
||||
break;
|
||||
/* else: fall through */
|
||||
default:
|
||||
target_state = state;
|
||||
}
|
||||
|
@ -2290,7 +2483,7 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev)
|
|||
* @bridge: Bridge to check
|
||||
*
|
||||
* This function checks if it is possible to move the bridge to D3.
|
||||
* Currently we only allow D3 for recent enough PCIe ports.
|
||||
* Currently we only allow D3 for recent enough PCIe ports and Thunderbolt.
|
||||
*/
|
||||
bool pci_bridge_d3_possible(struct pci_dev *bridge)
|
||||
{
|
||||
|
@ -2305,18 +2498,27 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge)
|
|||
return false;
|
||||
|
||||
/*
|
||||
* Hotplug interrupts cannot be delivered if the link is down,
|
||||
* so parents of a hotplug port must stay awake. In addition,
|
||||
* hotplug ports handled by firmware in System Management Mode
|
||||
* Hotplug ports handled by firmware in System Management Mode
|
||||
* may not be put into D3 by the OS (Thunderbolt on non-Macs).
|
||||
* For simplicity, disallow in general for now.
|
||||
*/
|
||||
if (bridge->is_hotplug_bridge)
|
||||
if (bridge->is_hotplug_bridge && !pciehp_is_native(bridge))
|
||||
return false;
|
||||
|
||||
if (pci_bridge_d3_force)
|
||||
return true;
|
||||
|
||||
/* Even the oldest 2010 Thunderbolt controller supports D3. */
|
||||
if (bridge->is_thunderbolt)
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Hotplug ports handled natively by the OS were not validated
|
||||
* by vendors for runtime D3 at least until 2018 because there
|
||||
* was no OS support.
|
||||
*/
|
||||
if (bridge->is_hotplug_bridge)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* It should be safe to put PCIe ports from 2015 or newer
|
||||
* to D3.
|
||||
|
@ -2820,6 +3022,66 @@ void pci_request_acs(void)
|
|||
pci_acs_enable = 1;
|
||||
}
|
||||
|
||||
static const char *disable_acs_redir_param;
|
||||
|
||||
/**
|
||||
* pci_disable_acs_redir - disable ACS redirect capabilities
|
||||
* @dev: the PCI device
|
||||
*
|
||||
* For only devices specified in the disable_acs_redir parameter.
|
||||
*/
|
||||
static void pci_disable_acs_redir(struct pci_dev *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *p;
|
||||
int pos;
|
||||
u16 ctrl;
|
||||
|
||||
if (!disable_acs_redir_param)
|
||||
return;
|
||||
|
||||
p = disable_acs_redir_param;
|
||||
while (*p) {
|
||||
ret = pci_dev_str_match(dev, p, &p);
|
||||
if (ret < 0) {
|
||||
pr_info_once("PCI: Can't parse disable_acs_redir parameter: %s\n",
|
||||
disable_acs_redir_param);
|
||||
|
||||
break;
|
||||
} else if (ret == 1) {
|
||||
/* Found a match */
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != ';' && *p != ',') {
|
||||
/* End of param or invalid format */
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (ret != 1)
|
||||
return;
|
||||
|
||||
if (!pci_dev_specific_disable_acs_redir(dev))
|
||||
return;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
|
||||
if (!pos) {
|
||||
pci_warn(dev, "cannot disable ACS redirect for this hardware as it does not have ACS capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
|
||||
|
||||
/* P2P Request & Completion Redirect */
|
||||
ctrl &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC);
|
||||
|
||||
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
|
||||
|
||||
pci_info(dev, "disabled ACS redirect\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_std_enable_acs - enable ACS on devices using standard ACS capabilites
|
||||
* @dev: the PCI device
|
||||
|
@ -2859,12 +3121,22 @@ static void pci_std_enable_acs(struct pci_dev *dev)
|
|||
void pci_enable_acs(struct pci_dev *dev)
|
||||
{
|
||||
if (!pci_acs_enable)
|
||||
return;
|
||||
goto disable_acs_redir;
|
||||
|
||||
if (!pci_dev_specific_enable_acs(dev))
|
||||
return;
|
||||
goto disable_acs_redir;
|
||||
|
||||
pci_std_enable_acs(dev);
|
||||
|
||||
disable_acs_redir:
|
||||
/*
|
||||
* Note: pci_disable_acs_redir() must be called even if ACS was not
|
||||
* enabled by the kernel because it may have been enabled by
|
||||
* platform firmware. So if we are told to disable it, we should
|
||||
* always disable it after setting the kernel's default
|
||||
* preferences.
|
||||
*/
|
||||
pci_disable_acs_redir(dev);
|
||||
}
|
||||
|
||||
static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags)
|
||||
|
@ -3070,7 +3342,7 @@ int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
|
|||
return pos;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> 8;
|
||||
return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3093,7 +3365,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
|
|||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
|
||||
ctrl |= size << 8;
|
||||
ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4077,7 +4349,7 @@ static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
|
|||
* Returns true if the device advertises support for PCIe function level
|
||||
* resets.
|
||||
*/
|
||||
static bool pcie_has_flr(struct pci_dev *dev)
|
||||
bool pcie_has_flr(struct pci_dev *dev)
|
||||
{
|
||||
u32 cap;
|
||||
|
||||
|
@ -4087,6 +4359,7 @@ static bool pcie_has_flr(struct pci_dev *dev)
|
|||
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &cap);
|
||||
return cap & PCI_EXP_DEVCAP_FLR;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pcie_has_flr);
|
||||
|
||||
/**
|
||||
* pcie_flr - initiate a PCIe function level reset
|
||||
|
@ -4262,19 +4535,18 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pci_reset_bridge_secondary_bus - Reset the secondary bus on a PCI bridge.
|
||||
* pci_bridge_secondary_bus_reset - Reset the secondary bus on a PCI bridge.
|
||||
* @dev: Bridge device
|
||||
*
|
||||
* Use the bridge control register to assert reset on the secondary bus.
|
||||
* Devices on the secondary bus are left in power-on state.
|
||||
*/
|
||||
int pci_reset_bridge_secondary_bus(struct pci_dev *dev)
|
||||
int pci_bridge_secondary_bus_reset(struct pci_dev *dev)
|
||||
{
|
||||
pcibios_reset_secondary_bus(dev);
|
||||
|
||||
return pci_dev_wait(dev, "bus reset", PCIE_RESET_READY_POLL_MS);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
|
||||
|
||||
static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
|
||||
{
|
||||
|
@ -4291,9 +4563,7 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
|
|||
if (probe)
|
||||
return 0;
|
||||
|
||||
pci_reset_bridge_secondary_bus(dev->bus->self);
|
||||
|
||||
return 0;
|
||||
return pci_bridge_secondary_bus_reset(dev->bus->self);
|
||||
}
|
||||
|
||||
static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
|
||||
|
@ -4825,7 +5095,7 @@ int pci_probe_reset_slot(struct pci_slot *slot)
|
|||
EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
|
||||
|
||||
/**
|
||||
* pci_reset_slot - reset a PCI slot
|
||||
* __pci_reset_slot - Try to reset a PCI slot
|
||||
* @slot: PCI slot to reset
|
||||
*
|
||||
* A PCI bus may host multiple slots, each slot may support a reset mechanism
|
||||
|
@ -4837,33 +5107,9 @@ EXPORT_SYMBOL_GPL(pci_probe_reset_slot);
|
|||
* through this function. PCI config space of all devices in the slot and
|
||||
* behind the slot is saved before and restored after reset.
|
||||
*
|
||||
* Return 0 on success, non-zero on error.
|
||||
*/
|
||||
int pci_reset_slot(struct pci_slot *slot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_slot_reset(slot, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_slot_save_and_disable(slot);
|
||||
|
||||
rc = pci_slot_reset(slot, 0);
|
||||
|
||||
pci_slot_restore(slot);
|
||||
|
||||
return rc;
|
||||
}
|
||||
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)
|
||||
static int __pci_reset_slot(struct pci_slot *slot)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -4884,10 +5130,11 @@ int pci_try_reset_slot(struct pci_slot *slot)
|
|||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_try_reset_slot);
|
||||
|
||||
static int pci_bus_reset(struct pci_bus *bus, int probe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!bus->self || !pci_bus_resetable(bus))
|
||||
return -ENOTTY;
|
||||
|
||||
|
@ -4898,11 +5145,11 @@ static int pci_bus_reset(struct pci_bus *bus, int probe)
|
|||
|
||||
might_sleep();
|
||||
|
||||
pci_reset_bridge_secondary_bus(bus->self);
|
||||
ret = pci_bridge_secondary_bus_reset(bus->self);
|
||||
|
||||
pci_bus_unlock(bus);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4918,39 +5165,12 @@ int pci_probe_reset_bus(struct pci_bus *bus)
|
|||
EXPORT_SYMBOL_GPL(pci_probe_reset_bus);
|
||||
|
||||
/**
|
||||
* pci_reset_bus - reset a PCI bus
|
||||
* @bus: top level PCI bus to reset
|
||||
*
|
||||
* Do a bus reset on the given bus and any subordinate buses, saving
|
||||
* and restoring state of all devices.
|
||||
*
|
||||
* Return 0 on success, non-zero on error.
|
||||
*/
|
||||
int pci_reset_bus(struct pci_bus *bus)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pci_bus_reset(bus, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_bus_save_and_disable(bus);
|
||||
|
||||
rc = pci_bus_reset(bus, 0);
|
||||
|
||||
pci_bus_restore(bus);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_reset_bus);
|
||||
|
||||
/**
|
||||
* pci_try_reset_bus - Try to reset a PCI bus
|
||||
* __pci_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)
|
||||
static int __pci_reset_bus(struct pci_bus *bus)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -4962,7 +5182,7 @@ int pci_try_reset_bus(struct pci_bus *bus)
|
|||
|
||||
if (pci_bus_trylock(bus)) {
|
||||
might_sleep();
|
||||
pci_reset_bridge_secondary_bus(bus->self);
|
||||
rc = pci_bridge_secondary_bus_reset(bus->self);
|
||||
pci_bus_unlock(bus);
|
||||
} else
|
||||
rc = -EAGAIN;
|
||||
|
@ -4971,7 +5191,19 @@ int pci_try_reset_bus(struct pci_bus *bus)
|
|||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_try_reset_bus);
|
||||
|
||||
/**
|
||||
* pci_reset_bus - Try to reset a PCI bus
|
||||
* @pdev: top level PCI device to reset via slot/bus
|
||||
*
|
||||
* Same as above except return -EAGAIN if the bus cannot be locked
|
||||
*/
|
||||
int pci_reset_bus(struct pci_dev *pdev)
|
||||
{
|
||||
return pci_probe_reset_slot(pdev->slot) ?
|
||||
__pci_reset_slot(pdev->slot) : __pci_reset_bus(pdev->bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_reset_bus);
|
||||
|
||||
/**
|
||||
* pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
|
||||
|
@ -5304,14 +5536,16 @@ u32 pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
|
|||
}
|
||||
|
||||
/**
|
||||
* pcie_print_link_status - Report the PCI device's link speed and width
|
||||
* __pcie_print_link_status - Report the PCI device's link speed and width
|
||||
* @dev: PCI device to query
|
||||
* @verbose: Print info even when enough bandwidth is available
|
||||
*
|
||||
* Report the available bandwidth at the device. If this is less than the
|
||||
* device is capable of, report the device's maximum possible bandwidth and
|
||||
* the upstream link that limits its performance to less than that.
|
||||
* If the available bandwidth at the device is less than the device is
|
||||
* capable of, report the device's maximum possible bandwidth and the
|
||||
* upstream link that limits its performance. If @verbose, always print
|
||||
* the available bandwidth, even if the device isn't constrained.
|
||||
*/
|
||||
void pcie_print_link_status(struct pci_dev *dev)
|
||||
void __pcie_print_link_status(struct pci_dev *dev, bool verbose)
|
||||
{
|
||||
enum pcie_link_width width, width_cap;
|
||||
enum pci_bus_speed speed, speed_cap;
|
||||
|
@ -5321,11 +5555,11 @@ void pcie_print_link_status(struct pci_dev *dev)
|
|||
bw_cap = pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
|
||||
bw_avail = pcie_bandwidth_available(dev, &limiting_dev, &speed, &width);
|
||||
|
||||
if (bw_avail >= bw_cap)
|
||||
if (bw_avail >= bw_cap && verbose)
|
||||
pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
|
||||
bw_cap / 1000, bw_cap % 1000,
|
||||
PCIE_SPEED2STR(speed_cap), width_cap);
|
||||
else
|
||||
else if (bw_avail < bw_cap)
|
||||
pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
|
||||
bw_avail / 1000, bw_avail % 1000,
|
||||
PCIE_SPEED2STR(speed), width,
|
||||
|
@ -5333,6 +5567,17 @@ void pcie_print_link_status(struct pci_dev *dev)
|
|||
bw_cap / 1000, bw_cap % 1000,
|
||||
PCIE_SPEED2STR(speed_cap), width_cap);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcie_print_link_status - Report the PCI device's link speed and width
|
||||
* @dev: PCI device to query
|
||||
*
|
||||
* Report the available bandwidth at the device.
|
||||
*/
|
||||
void pcie_print_link_status(struct pci_dev *dev)
|
||||
{
|
||||
__pcie_print_link_status(dev, true);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_print_link_status);
|
||||
|
||||
/**
|
||||
|
@ -5427,8 +5672,19 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
|
|||
* @dev: the PCI device for which alias is added
|
||||
* @devfn: alias slot and function
|
||||
*
|
||||
* This helper encodes 8-bit devfn as bit number in dma_alias_mask.
|
||||
* It should be called early, preferably as PCI fixup header quirk.
|
||||
* This helper encodes an 8-bit devfn as a bit number in dma_alias_mask
|
||||
* which is used to program permissible bus-devfn source addresses for DMA
|
||||
* requests in an IOMMU. These aliases factor into IOMMU group creation
|
||||
* and are useful for devices generating DMA requests beyond or different
|
||||
* from their logical bus-devfn. Examples include device quirks where the
|
||||
* device simply uses the wrong devfn, as well as non-transparent bridges
|
||||
* where the alias may be a proxy for devices in another domain.
|
||||
*
|
||||
* IOMMU group creation is performed during device discovery or addition,
|
||||
* prior to any potential DMA mapping and therefore prior to driver probing
|
||||
* (especially for userspace assigned devices where IOMMU group definition
|
||||
* cannot be left as a userspace activity). DMA aliases should therefore
|
||||
* be configured via quirks, such as the PCI fixup header quirk.
|
||||
*/
|
||||
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
|
||||
{
|
||||
|
@ -5494,10 +5750,10 @@ static DEFINE_SPINLOCK(resource_alignment_lock);
|
|||
static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
|
||||
bool *resize)
|
||||
{
|
||||
int seg, bus, slot, func, align_order, count;
|
||||
unsigned short vendor, device, subsystem_vendor, subsystem_device;
|
||||
int align_order, count;
|
||||
resource_size_t align = pcibios_default_alignment();
|
||||
char *p;
|
||||
const char *p;
|
||||
int ret;
|
||||
|
||||
spin_lock(&resource_alignment_lock);
|
||||
p = resource_alignment_param;
|
||||
|
@ -5517,58 +5773,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
|
|||
} else {
|
||||
align_order = -1;
|
||||
}
|
||||
if (strncmp(p, "pci:", 4) == 0) {
|
||||
/* PCI vendor/device (subvendor/subdevice) ids are specified */
|
||||
p += 4;
|
||||
if (sscanf(p, "%hx:%hx:%hx:%hx%n",
|
||||
&vendor, &device, &subsystem_vendor, &subsystem_device, &count) != 4) {
|
||||
if (sscanf(p, "%hx:%hx%n", &vendor, &device, &count) != 2) {
|
||||
printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: pci:%s\n",
|
||||
p);
|
||||
break;
|
||||
}
|
||||
subsystem_vendor = subsystem_device = 0;
|
||||
}
|
||||
p += count;
|
||||
if ((!vendor || (vendor == dev->vendor)) &&
|
||||
(!device || (device == dev->device)) &&
|
||||
(!subsystem_vendor || (subsystem_vendor == dev->subsystem_vendor)) &&
|
||||
(!subsystem_device || (subsystem_device == dev->subsystem_device))) {
|
||||
*resize = true;
|
||||
if (align_order == -1)
|
||||
align = PAGE_SIZE;
|
||||
else
|
||||
align = 1 << align_order;
|
||||
/* Found */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sscanf(p, "%x:%x:%x.%x%n",
|
||||
&seg, &bus, &slot, &func, &count) != 4) {
|
||||
seg = 0;
|
||||
if (sscanf(p, "%x:%x.%x%n",
|
||||
&bus, &slot, &func, &count) != 3) {
|
||||
/* Invalid format */
|
||||
printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n",
|
||||
p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p += count;
|
||||
if (seg == pci_domain_nr(dev->bus) &&
|
||||
bus == dev->bus->number &&
|
||||
slot == PCI_SLOT(dev->devfn) &&
|
||||
func == PCI_FUNC(dev->devfn)) {
|
||||
*resize = true;
|
||||
if (align_order == -1)
|
||||
align = PAGE_SIZE;
|
||||
else
|
||||
align = 1 << align_order;
|
||||
/* Found */
|
||||
break;
|
||||
}
|
||||
|
||||
ret = pci_dev_str_match(dev, p, &p);
|
||||
if (ret == 1) {
|
||||
*resize = true;
|
||||
if (align_order == -1)
|
||||
align = PAGE_SIZE;
|
||||
else
|
||||
align = 1 << align_order;
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
pr_err("PCI: Can't parse resource_alignment parameter: %s\n",
|
||||
p);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != ';' && *p != ',') {
|
||||
/* End of param or invalid format */
|
||||
break;
|
||||
|
@ -5845,6 +6064,8 @@ static int __init pci_setup(char *str)
|
|||
pcie_ats_disabled = true;
|
||||
} else if (!strcmp(str, "noaer")) {
|
||||
pci_no_aer();
|
||||
} else if (!strcmp(str, "earlydump")) {
|
||||
pci_early_dump = true;
|
||||
} else if (!strncmp(str, "realloc=", 8)) {
|
||||
pci_realloc_get_opt(str + 8);
|
||||
} else if (!strncmp(str, "realloc", 7)) {
|
||||
|
@ -5881,6 +6102,8 @@ static int __init pci_setup(char *str)
|
|||
pcie_bus_config = PCIE_BUS_PEER2PEER;
|
||||
} else if (!strncmp(str, "pcie_scan_all", 13)) {
|
||||
pci_add_flags(PCI_SCAN_ALL_PCIE_DEVS);
|
||||
} else if (!strncmp(str, "disable_acs_redir=", 18)) {
|
||||
disable_acs_redir_param = str + 18;
|
||||
} else {
|
||||
printk(KERN_ERR "PCI: Unknown option `%s'\n",
|
||||
str);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue