3a37872316
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmbseugUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vxdwxAAvdvDyTuiPo2R8pQtvKg4YL2IUnK5 UR28mBxZDK5DFhLtD/QzmVVG/eaLY6bJHthHgJgTApzekkqU0h9dcRI0eegXrvcz I3HRsZK2yatUky9l8O148OLzF897r7vXL3QtGe6qjKU+9D83IEeooLKgBca+GoBC bRLvG/fYRzdjOe8UHFqCoeMIg3IOY7CNifvFOihAGpJpxfZQktj6hSKu6q7BL1Rx NRgYlxh0eLcb7vAJqz6RZpQ8PRCwhAjlDuu0BOkES8/6EwisD1xUh3qdDxfVgNA6 FpcAb/53yr46cs4tM9ZTwluka86AskuXj3jwSKf7nE3zqr4nM9OD3sGOSYzK8UdE EDBKj+9iEpYRC6rJMk5gNH2AZkR1OEpNUisR6+kEn81A9yNNoTmkHdHUOWo8TuxD btc0sTM+eWApvTiZwgL4VjMZulQllV51K8tcfvODRhlMkbOPNWGWdmpWqEbUS2HU i7+zzQC3DC5iPlAKgRSeYB0aad6la6brqPW16sGhGovNhgwbzakDLCUJJGn/LNuO wd0UNpJTnHlfChbvNh2bBxiMOo0cab1tJ5Jp97STQYhLg2nW93s/dAfdpSAsYO4S 5YzjSADWeyeuDsHE1RdUdDvYAPMb1VZBUd2OSHis5zw7kmh25c9KYXEkDJ25q/ju sVXK4oMNW/Gnd5M= =L3s9 -----END PGP SIGNATURE----- Merge tag 'pci-v6.12-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci Pull pci updates from Bjorn Helgaas: "Enumeration: - Wait for device readiness after reset by polling Vendor ID and looking for Configuration RRS instead of polling the Command register and looking for non-error completions, to avoid hardware retries done for RRS on non-Vendor ID reads (Bjorn Helgaas) - Rename CRS Completion Status to RRS ('Request Retry Status') to match PCIe r6.0 spec usage (Bjorn Helgaas) - Clear LBMS bit after a manual link retrain so we don't try to retrain a link when there's no downstream device anymore (Maciej W. Rozycki) - Revert to the original link speed after retraining fails instead of leaving it restricted to 2.5GT/s, so a future device has a chance to use higher speeds (Maciej W. Rozycki) - Wait for each level of downstream bus, not just the first, to become accessible before restoring devices on that bus (Ilpo Järvinen) - Add ARCH_PCI_DEV_GROUPS so s390 can add its own attribute_groups without having to stomp on the core's pdev->dev.groups (Lukas Wunner) Driver binding: - Export pcim_request_region(), a managed counterpart of pci_request_region(), for use by drivers (Philipp Stanner) - Export pcim_iomap_region() and deprecate pcim_iomap_regions() (Philipp Stanner) - Request the PCI BAR used by xboxvideo (Philipp Stanner) - Request and map drm/ast BARs with pcim_iomap_region() (Philipp Stanner) MSI: - Add MSI_FLAG_NO_AFFINITY flag for devices that mux MSIs onto a single IRQ line and cannot set the affinity of each MSI to a specific CPU core (Marek Vasut) - Use MSI_FLAG_NO_AFFINITY and remove unnecessary .irq_set_affinity() implementations in aardvark, altera, brcmstb, dwc, mediatek-gen3, mediatek, mobiveil, plda, rcar, tegra, vmd, xilinx-nwl, xilinx-xdma, and xilinx drivers to avoid 'IRQ: set affinity failed' warnings (Marek Vasut) Power management: - Add pwrctl support for ATH11K inside the WCN6855 package (Konrad Dybcio) PCI device hotplug: - Remove unnecessary hpc_ops struct from shpchp (ngn) - Check for PCI_POSSIBLE_ERROR(), not 0xffffffff, in cpqphp (weiyufeng) Virtualization: - Mark Creative Labs EMU20k2 INTx masking as broken (Alex Williamson) - Add an ACS quirk for Qualcomm SA8775P, which doesn't advertise ACS but does provide ACS-like features (Subramanian Ananthanarayanan) IOMMU: - Add function 0 DMA alias quirk for Glenfly Arise audio function, which uses the function 0 Requester ID (WangYuli) NPEM: - Add Native PCIe Enclosure Management (NPEM) support for sysfs control of NVMe RAID storage indicators (ok/fail/locate/ rebuild/etc) (Mariusz Tkaczyk) - Add support for the ACPI _DSM PCIe SSD status LED management, which is functionally similar to NPEM but mediated by platform firmware (Mariusz Tkaczyk) Device trees: - Drop minItems and maxItems from ranges in PCI generic host binding since host bridges may have several MMIO and I/O port apertures (Frank Li) - Add kirin, rcar-gen2, uniphier DT binding top-level constraints for clocks (Krzysztof Kozlowski) Altera PCIe controller driver: - Convert altera DT bindings from text to YAML (Matthew Gerlach) - Replace TLP_REQ_ID() with macro PCI_DEVID(), which does the same thing and is what other drivers use (Jinjie Ruan) Broadcom STB PCIe controller driver: - Add DT binding maxItems for reset controllers (Jim Quinlan) - Use the 'bridge' reset method if described in the DT (Jim Quinlan) - Use the 'swinit' reset method if described in the DT (Jim Quinlan) - Add 'has_phy' so the existence of a 'rescal' reset controller doesn't imply software control of it (Jim Quinlan) - Add support for many inbound DMA windows (Jim Quinlan) - Rename SoC 'type' to 'soc_base' express the fact that SoCs come in families of multiple similar devices (Jim Quinlan) - Add Broadcom 7712 DT description and driver support (Jim Quinlan) - Sort enums, pcie_offsets[], pcie_cfg_data, .compatible strings for maintainability (Bjorn Helgaas) Freescale i.MX6 PCIe controller driver: - Add imx6q-pcie 'dbi2' and 'atu' reg-names for i.MX8M Endpoints (Richard Zhu) - Fix a code restructuring error that caused i.MX8MM and i.MX8MP Endpoints to fail to establish link (Richard Zhu) - Fix i.MX8MP Endpoint occasional failure to trigger MSI by enforcing outbound alignment requirement (Richard Zhu) - Call phy_power_off() in the .probe() error path (Frank Li) - Rename internal names from imx6_* to imx_* since i.MX7/8/9 are also supported (Frank Li) - Manage Refclk by using SoC-specific callbacks instead of switch statements (Frank Li) - Manage core reset by using SoC-specific callbacks instead of switch statements (Frank Li) - Expand comments for erratum ERR010728 workaround (Frank Li) - Use generic PHY APIs to configure mode, speed, and submode, which is harmless for devices that implement their own internal PHY management and don't set the generic imx_pcie->phy (Frank Li) - Add i.MX8Q (i.MX8QM, i.MX8QXP, and i.MX8DXL) DT binding and driver Root Complex support (Richard Zhu) Freescale Layerscape PCIe controller driver: - Replace layerscape-pcie DT binding compatible fsl,lx2160a-pcie with fsl,lx2160ar2-pcie (Frank Li) - Add layerscape-pcie DT binding deprecated 'num-viewport' property to address a DT checker warning (Frank Li) - Change layerscape-pcie DT binding 'fsl,pcie-scfg' to phandle-array (Frank Li) Loongson PCIe controller driver: - Increase max PCI hosts to 8 for Loongson-3C6000 and newer chipsets (Huacai Chen) Marvell Aardvark PCIe controller driver: - Fix issue with emulating Configuration RRS for two-byte reads of Vendor ID; previously it only worked for four-byte reads (Bjorn Helgaas) MediaTek PCIe Gen3 controller driver: - Add per-SoC struct mtk_gen3_pcie_pdata to support multiple SoC types (Lorenzo Bianconi) - Use reset_bulk APIs to manage PHY reset lines (Lorenzo Bianconi) - Add DT and driver support for Airoha EN7581 PCIe controller (Lorenzo Bianconi) Qualcomm PCIe controller driver: - Update qcom,pcie-sc7280 DT binding with eight interrupts (Rayyan Ansari) - Add back DT 'vddpe-3v3-supply', which was incorrectly removed earlier (Johan Hovold) - Drop endpoint redundant masking of global IRQ events (Manivannan Sadhasivam) - Clarify unknown global IRQ message and only log it once to avoid a flood (Manivannan Sadhasivam) - Add 'linux,pci-domain' property to endpoint DT binding (Manivannan Sadhasivam) - Assign PCI domain number for endpoint controllers (Manivannan Sadhasivam) - Add 'qcom_pcie_ep' and the PCI domain number to IRQ names for endpoint controller (Manivannan Sadhasivam) - Add global SPI interrupt for PCIe link events to DT binding (Manivannan Sadhasivam) - Add global RC interrupt handler to handle 'Link up' events and automatically enumerate hot-added devices (Manivannan Sadhasivam) - Avoid mirroring of DBI and iATU register space so it doesn't overlap BAR MMIO space (Prudhvi Yarlagadda) - Enable controller resources like PHY only after PERST# is deasserted to partially avoid the problem that the endpoint SoC crashes when accessing things when Refclk is absent (Manivannan Sadhasivam) - Add 16.0 GT/s equalization and RX lane margining settings (Shashank Babu Chinta Venkata) - Pass domain number to pci_bus_release_domain_nr() explicitly to avoid a NULL pointer dereference (Manivannan Sadhasivam) Renesas R-Car PCIe controller driver: - Make the read-only const array 'check_addr' static (Colin Ian King) - Add R-Car V4M (R8A779H0) PCIe host and endpoint to DT binding (Yoshihiro Shimoda) TI DRA7xx PCIe controller driver: - Request IRQF_ONESHOT for 'dra7xx-pcie-main' IRQ since the primary handler is NULL (Siddharth Vadapalli) - Handle IRQ request errors during root port and endpoint probe (Siddharth Vadapalli) TI J721E PCIe driver: - Add DT 'ti,syscon-acspcie-proxy-ctrl' and driver support to enable the ACSPCIE module to drive Refclk for the Endpoint (Siddharth Vadapalli) - Extract the cadence link setup from cdns_pcie_host_setup() so link setup can be done separately during resume (Thomas Richard) - Add T_PERST_CLK_US definition for the mandatory delay between Refclk becoming stable and PERST# being deasserted (Thomas Richard) - Add j721e suspend and resume support (Théo Lebrun) TI Keystone PCIe controller driver: - Fix NULL pointer checking when applying MRRS limitation quirk for AM65x SR 1.0 Errata #i2037 (Dan Carpenter) Xilinx NWL PCIe controller driver: - Fix off-by-one error in INTx IRQ handler that caused INTx interrupts to be lost or delivered as the wrong interrupt (Sean Anderson) - Rate-limit misc interrupt messages (Sean Anderson) - Turn off the clock on probe failure and device removal (Sean Anderson) - Add DT binding and driver support for enabling/disabling PHYs (Sean Anderson) - Add PCIe phy bindings for the ZCU102 (Sean Anderson) Xilinx XDMA PCIe controller driver: - Add support for Xilinx QDMA Soft IP PCIe Root Port Bridge to DT binding and xilinx-dma-pl driver (Thippeswamy Havalige) Miscellaneous: - Fix buffer overflow in kirin_pcie_parse_port() (Alexandra Diupina) - Fix minor kerneldoc issues and typos (Bjorn Helgaas) - Use PCI_DEVID() macro in aer_inject() instead of open-coding it (Jinjie Ruan) - Check pcie_find_root_port() return in x86 fixups to avoid NULL pointer dereferences (Samasth Norway Ananda) - Make pci_bus_type constant (Kunwu Chan) - Remove unused declarations of __pci_pme_wakeup() and pci_vpd_release() (Yue Haibing) - Remove any leftover .*.cmd files with make clean (zhang jiao) - Remove unused BILLION macro (zhang jiao)" * tag 'pci-v6.12-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (132 commits) PCI: Fix typos dt-bindings: PCI: qcom: Allow 'vddpe-3v3-supply' again tools: PCI: Remove unused BILLION macro tools: PCI: Remove .*.cmd files with make clean PCI: Pass domain number to pci_bus_release_domain_nr() explicitly PCI: dra7xx: Fix error handling when IRQ request fails in probe PCI: dra7xx: Fix threaded IRQ request for "dra7xx-pcie-main" IRQ PCI: qcom: Add RX lane margining settings for 16.0 GT/s PCI: qcom: Add equalization settings for 16.0 GT/s PCI: dwc: Always cache the maximum link speed value in dw_pcie::max_link_speed PCI: dwc: Rename 'dw_pcie::link_gen' to 'dw_pcie::max_link_speed' PCI: qcom-ep: Enable controller resources like PHY only after refclk is available PCI: Mark Creative Labs EMU20k2 INTx masking as broken dt-bindings: PCI: imx6q-pcie: Add reg-name "dbi2" and "atu" for i.MX8M PCIe Endpoint dt-bindings: PCI: altera: msi: Convert to YAML PCI: imx6: Add i.MX8Q PCIe Root Complex (RC) support PCI: Rename CRS Completion Status to RRS PCI: aardvark: Correct Configuration RRS checking PCI: Wait for device readiness with Configuration RRS PCI: brcmstb: Sort enums, pcie_offsets[], pcie_cfg_data, .compatible strings ...
542 lines
12 KiB
C
542 lines
12 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* PCI Express I/O Virtualization (IOV) support
|
|
* Address Translation Service 1.0
|
|
* Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
|
|
* PASID support added by Joerg Roedel <joerg.roedel@amd.com>
|
|
*
|
|
* Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
|
|
* Copyright (C) 2011 Advanced Micro Devices,
|
|
*/
|
|
|
|
#include <linux/bitfield.h>
|
|
#include <linux/export.h>
|
|
#include <linux/pci-ats.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "pci.h"
|
|
|
|
void pci_ats_init(struct pci_dev *dev)
|
|
{
|
|
int pos;
|
|
|
|
if (pci_ats_disabled())
|
|
return;
|
|
|
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
|
|
if (!pos)
|
|
return;
|
|
|
|
dev->ats_cap = pos;
|
|
}
|
|
|
|
/**
|
|
* pci_ats_supported - check if the device can use ATS
|
|
* @dev: the PCI device
|
|
*
|
|
* Returns true if the device supports ATS and is allowed to use it, false
|
|
* otherwise.
|
|
*/
|
|
bool pci_ats_supported(struct pci_dev *dev)
|
|
{
|
|
if (!dev->ats_cap)
|
|
return false;
|
|
|
|
return (dev->untrusted == 0);
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_ats_supported);
|
|
|
|
/**
|
|
* pci_prepare_ats - Setup the PS for ATS
|
|
* @dev: the PCI device
|
|
* @ps: the IOMMU page shift
|
|
*
|
|
* This must be done by the IOMMU driver on the PF before any VFs are created to
|
|
* ensure that the VF can have ATS enabled.
|
|
*
|
|
* Returns 0 on success, or negative on failure.
|
|
*/
|
|
int pci_prepare_ats(struct pci_dev *dev, int ps)
|
|
{
|
|
u16 ctrl;
|
|
|
|
if (!pci_ats_supported(dev))
|
|
return -EINVAL;
|
|
|
|
if (WARN_ON(dev->ats_enabled))
|
|
return -EBUSY;
|
|
|
|
if (ps < PCI_ATS_MIN_STU)
|
|
return -EINVAL;
|
|
|
|
if (dev->is_virtfn)
|
|
return 0;
|
|
|
|
dev->ats_stu = ps;
|
|
ctrl = PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_prepare_ats);
|
|
|
|
/**
|
|
* pci_enable_ats - enable the ATS capability
|
|
* @dev: the PCI device
|
|
* @ps: the IOMMU page shift
|
|
*
|
|
* Returns 0 on success, or negative on failure.
|
|
*/
|
|
int pci_enable_ats(struct pci_dev *dev, int ps)
|
|
{
|
|
u16 ctrl;
|
|
struct pci_dev *pdev;
|
|
|
|
if (!pci_ats_supported(dev))
|
|
return -EINVAL;
|
|
|
|
if (WARN_ON(dev->ats_enabled))
|
|
return -EBUSY;
|
|
|
|
if (ps < PCI_ATS_MIN_STU)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* Note that enabling ATS on a VF fails unless it's already enabled
|
|
* with the same STU on the PF.
|
|
*/
|
|
ctrl = PCI_ATS_CTRL_ENABLE;
|
|
if (dev->is_virtfn) {
|
|
pdev = pci_physfn(dev);
|
|
if (pdev->ats_stu != ps)
|
|
return -EINVAL;
|
|
} else {
|
|
dev->ats_stu = ps;
|
|
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
|
}
|
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
|
|
|
dev->ats_enabled = 1;
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_enable_ats);
|
|
|
|
/**
|
|
* pci_disable_ats - disable the ATS capability
|
|
* @dev: the PCI device
|
|
*/
|
|
void pci_disable_ats(struct pci_dev *dev)
|
|
{
|
|
u16 ctrl;
|
|
|
|
if (WARN_ON(!dev->ats_enabled))
|
|
return;
|
|
|
|
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, &ctrl);
|
|
ctrl &= ~PCI_ATS_CTRL_ENABLE;
|
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
|
|
|
dev->ats_enabled = 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_disable_ats);
|
|
|
|
void pci_restore_ats_state(struct pci_dev *dev)
|
|
{
|
|
u16 ctrl;
|
|
|
|
if (!dev->ats_enabled)
|
|
return;
|
|
|
|
ctrl = PCI_ATS_CTRL_ENABLE;
|
|
if (!dev->is_virtfn)
|
|
ctrl |= PCI_ATS_CTRL_STU(dev->ats_stu - PCI_ATS_MIN_STU);
|
|
pci_write_config_word(dev, dev->ats_cap + PCI_ATS_CTRL, ctrl);
|
|
}
|
|
|
|
/**
|
|
* pci_ats_queue_depth - query the ATS Invalidate Queue Depth
|
|
* @dev: the PCI device
|
|
*
|
|
* Returns the queue depth on success, or negative on failure.
|
|
*
|
|
* The ATS spec uses 0 in the Invalidate Queue Depth field to
|
|
* indicate that the function can accept 32 Invalidate Request.
|
|
* But here we use the `real' values (i.e. 1~32) for the Queue
|
|
* Depth; and 0 indicates the function shares the Queue with
|
|
* other functions (doesn't exclusively own a Queue).
|
|
*/
|
|
int pci_ats_queue_depth(struct pci_dev *dev)
|
|
{
|
|
u16 cap;
|
|
|
|
if (!dev->ats_cap)
|
|
return -EINVAL;
|
|
|
|
if (dev->is_virtfn)
|
|
return 0;
|
|
|
|
pci_read_config_word(dev, dev->ats_cap + PCI_ATS_CAP, &cap);
|
|
return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP;
|
|
}
|
|
|
|
/**
|
|
* pci_ats_page_aligned - Return Page Aligned Request bit status.
|
|
* @pdev: the PCI device
|
|
*
|
|
* Returns 1, if the Untranslated Addresses generated by the device
|
|
* are always aligned or 0 otherwise.
|
|
*
|
|
* Per PCIe spec r4.0, sec 10.5.1.2, if the Page Aligned Request bit
|
|
* is set, it indicates the Untranslated Addresses generated by the
|
|
* device are always aligned to a 4096 byte boundary.
|
|
*/
|
|
int pci_ats_page_aligned(struct pci_dev *pdev)
|
|
{
|
|
u16 cap;
|
|
|
|
if (!pdev->ats_cap)
|
|
return 0;
|
|
|
|
pci_read_config_word(pdev, pdev->ats_cap + PCI_ATS_CAP, &cap);
|
|
|
|
if (cap & PCI_ATS_CAP_PAGE_ALIGNED)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_PCI_PRI
|
|
void pci_pri_init(struct pci_dev *pdev)
|
|
{
|
|
u16 status;
|
|
|
|
pdev->pri_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PRI);
|
|
|
|
if (!pdev->pri_cap)
|
|
return;
|
|
|
|
pci_read_config_word(pdev, pdev->pri_cap + PCI_PRI_STATUS, &status);
|
|
if (status & PCI_PRI_STATUS_PASID)
|
|
pdev->pasid_required = 1;
|
|
}
|
|
|
|
/**
|
|
* pci_enable_pri - Enable PRI capability
|
|
* @pdev: PCI device structure
|
|
* @reqs: outstanding requests
|
|
*
|
|
* Returns 0 on success, negative value on error
|
|
*/
|
|
int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
|
|
{
|
|
u16 control, status;
|
|
u32 max_requests;
|
|
int pri = pdev->pri_cap;
|
|
|
|
/*
|
|
* VFs must not implement the PRI Capability. If their PF
|
|
* implements PRI, it is shared by the VFs, so if the PF PRI is
|
|
* enabled, it is also enabled for the VF.
|
|
*/
|
|
if (pdev->is_virtfn) {
|
|
if (pci_physfn(pdev)->pri_enabled)
|
|
return 0;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (WARN_ON(pdev->pri_enabled))
|
|
return -EBUSY;
|
|
|
|
if (!pri)
|
|
return -EINVAL;
|
|
|
|
pci_read_config_word(pdev, pri + PCI_PRI_STATUS, &status);
|
|
if (!(status & PCI_PRI_STATUS_STOPPED))
|
|
return -EBUSY;
|
|
|
|
pci_read_config_dword(pdev, pri + PCI_PRI_MAX_REQ, &max_requests);
|
|
reqs = min(max_requests, reqs);
|
|
pdev->pri_reqs_alloc = reqs;
|
|
pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
|
|
|
|
control = PCI_PRI_CTRL_ENABLE;
|
|
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
|
|
|
|
pdev->pri_enabled = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pci_disable_pri - Disable PRI capability
|
|
* @pdev: PCI device structure
|
|
*
|
|
* Only clears the enabled-bit, regardless of its former value
|
|
*/
|
|
void pci_disable_pri(struct pci_dev *pdev)
|
|
{
|
|
u16 control;
|
|
int pri = pdev->pri_cap;
|
|
|
|
/* VFs share the PF PRI */
|
|
if (pdev->is_virtfn)
|
|
return;
|
|
|
|
if (WARN_ON(!pdev->pri_enabled))
|
|
return;
|
|
|
|
if (!pri)
|
|
return;
|
|
|
|
pci_read_config_word(pdev, pri + PCI_PRI_CTRL, &control);
|
|
control &= ~PCI_PRI_CTRL_ENABLE;
|
|
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
|
|
|
|
pdev->pri_enabled = 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_disable_pri);
|
|
|
|
/**
|
|
* pci_restore_pri_state - Restore PRI
|
|
* @pdev: PCI device structure
|
|
*/
|
|
void pci_restore_pri_state(struct pci_dev *pdev)
|
|
{
|
|
u16 control = PCI_PRI_CTRL_ENABLE;
|
|
u32 reqs = pdev->pri_reqs_alloc;
|
|
int pri = pdev->pri_cap;
|
|
|
|
if (pdev->is_virtfn)
|
|
return;
|
|
|
|
if (!pdev->pri_enabled)
|
|
return;
|
|
|
|
if (!pri)
|
|
return;
|
|
|
|
pci_write_config_dword(pdev, pri + PCI_PRI_ALLOC_REQ, reqs);
|
|
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
|
|
}
|
|
|
|
/**
|
|
* pci_reset_pri - Resets device's PRI state
|
|
* @pdev: PCI device structure
|
|
*
|
|
* The PRI capability must be disabled before this function is called.
|
|
* Returns 0 on success, negative value on error.
|
|
*/
|
|
int pci_reset_pri(struct pci_dev *pdev)
|
|
{
|
|
u16 control;
|
|
int pri = pdev->pri_cap;
|
|
|
|
if (pdev->is_virtfn)
|
|
return 0;
|
|
|
|
if (WARN_ON(pdev->pri_enabled))
|
|
return -EBUSY;
|
|
|
|
if (!pri)
|
|
return -EINVAL;
|
|
|
|
control = PCI_PRI_CTRL_RESET;
|
|
pci_write_config_word(pdev, pri + PCI_PRI_CTRL, control);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* pci_prg_resp_pasid_required - Return PRG Response PASID Required bit
|
|
* status.
|
|
* @pdev: PCI device structure
|
|
*
|
|
* Returns 1 if PASID is required in PRG Response Message, 0 otherwise.
|
|
*/
|
|
int pci_prg_resp_pasid_required(struct pci_dev *pdev)
|
|
{
|
|
if (pdev->is_virtfn)
|
|
pdev = pci_physfn(pdev);
|
|
|
|
return pdev->pasid_required;
|
|
}
|
|
|
|
/**
|
|
* pci_pri_supported - Check if PRI is supported.
|
|
* @pdev: PCI device structure
|
|
*
|
|
* Returns true if PRI capability is present, false otherwise.
|
|
*/
|
|
bool pci_pri_supported(struct pci_dev *pdev)
|
|
{
|
|
/* VFs share the PF PRI */
|
|
if (pci_physfn(pdev)->pri_cap)
|
|
return true;
|
|
return false;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_pri_supported);
|
|
#endif /* CONFIG_PCI_PRI */
|
|
|
|
#ifdef CONFIG_PCI_PASID
|
|
void pci_pasid_init(struct pci_dev *pdev)
|
|
{
|
|
pdev->pasid_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_PASID);
|
|
}
|
|
|
|
/**
|
|
* pci_enable_pasid - Enable the PASID capability
|
|
* @pdev: PCI device structure
|
|
* @features: Features to enable
|
|
*
|
|
* Returns 0 on success, negative value on error. This function checks
|
|
* whether the features are actually supported by the device and returns
|
|
* an error if not.
|
|
*/
|
|
int pci_enable_pasid(struct pci_dev *pdev, int features)
|
|
{
|
|
u16 control, supported;
|
|
int pasid = pdev->pasid_cap;
|
|
|
|
/*
|
|
* VFs must not implement the PASID Capability, but if a PF
|
|
* supports PASID, its VFs share the PF PASID configuration.
|
|
*/
|
|
if (pdev->is_virtfn) {
|
|
if (pci_physfn(pdev)->pasid_enabled)
|
|
return 0;
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (WARN_ON(pdev->pasid_enabled))
|
|
return -EBUSY;
|
|
|
|
if (!pdev->eetlp_prefix_path && !pdev->pasid_no_tlp)
|
|
return -EINVAL;
|
|
|
|
if (!pasid)
|
|
return -EINVAL;
|
|
|
|
if (!pci_acs_path_enabled(pdev, NULL, PCI_ACS_RR | PCI_ACS_UF))
|
|
return -EINVAL;
|
|
|
|
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
|
|
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
|
|
|
/* User wants to enable anything unsupported? */
|
|
if ((supported & features) != features)
|
|
return -EINVAL;
|
|
|
|
control = PCI_PASID_CTRL_ENABLE | features;
|
|
pdev->pasid_features = features;
|
|
|
|
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
|
|
|
|
pdev->pasid_enabled = 1;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_enable_pasid);
|
|
|
|
/**
|
|
* pci_disable_pasid - Disable the PASID capability
|
|
* @pdev: PCI device structure
|
|
*/
|
|
void pci_disable_pasid(struct pci_dev *pdev)
|
|
{
|
|
u16 control = 0;
|
|
int pasid = pdev->pasid_cap;
|
|
|
|
/* VFs share the PF PASID configuration */
|
|
if (pdev->is_virtfn)
|
|
return;
|
|
|
|
if (WARN_ON(!pdev->pasid_enabled))
|
|
return;
|
|
|
|
if (!pasid)
|
|
return;
|
|
|
|
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
|
|
|
|
pdev->pasid_enabled = 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_disable_pasid);
|
|
|
|
/**
|
|
* pci_restore_pasid_state - Restore PASID capabilities
|
|
* @pdev: PCI device structure
|
|
*/
|
|
void pci_restore_pasid_state(struct pci_dev *pdev)
|
|
{
|
|
u16 control;
|
|
int pasid = pdev->pasid_cap;
|
|
|
|
if (pdev->is_virtfn)
|
|
return;
|
|
|
|
if (!pdev->pasid_enabled)
|
|
return;
|
|
|
|
if (!pasid)
|
|
return;
|
|
|
|
control = PCI_PASID_CTRL_ENABLE | pdev->pasid_features;
|
|
pci_write_config_word(pdev, pasid + PCI_PASID_CTRL, control);
|
|
}
|
|
|
|
/**
|
|
* pci_pasid_features - Check which PASID features are supported
|
|
* @pdev: PCI device structure
|
|
*
|
|
* Return a negative value when no PASID capability is present.
|
|
* Otherwise return a bitmask with supported features. Current
|
|
* features reported are:
|
|
* PCI_PASID_CAP_EXEC - Execute permission supported
|
|
* PCI_PASID_CAP_PRIV - Privileged mode supported
|
|
*/
|
|
int pci_pasid_features(struct pci_dev *pdev)
|
|
{
|
|
u16 supported;
|
|
int pasid;
|
|
|
|
if (pdev->is_virtfn)
|
|
pdev = pci_physfn(pdev);
|
|
|
|
pasid = pdev->pasid_cap;
|
|
if (!pasid)
|
|
return -EINVAL;
|
|
|
|
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
|
|
|
|
supported &= PCI_PASID_CAP_EXEC | PCI_PASID_CAP_PRIV;
|
|
|
|
return supported;
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_pasid_features);
|
|
|
|
/**
|
|
* pci_max_pasids - Get maximum number of PASIDs supported by device
|
|
* @pdev: PCI device structure
|
|
*
|
|
* Returns negative value when PASID capability is not present.
|
|
* Otherwise it returns the number of supported PASIDs.
|
|
*/
|
|
int pci_max_pasids(struct pci_dev *pdev)
|
|
{
|
|
u16 supported;
|
|
int pasid;
|
|
|
|
if (pdev->is_virtfn)
|
|
pdev = pci_physfn(pdev);
|
|
|
|
pasid = pdev->pasid_cap;
|
|
if (!pasid)
|
|
return -EINVAL;
|
|
|
|
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
|
|
|
|
return (1 << FIELD_GET(PCI_PASID_CAP_WIDTH, supported));
|
|
}
|
|
EXPORT_SYMBOL_GPL(pci_max_pasids);
|
|
#endif /* CONFIG_PCI_PASID */
|