pci-v5.14-changes

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmDl0F8UHGJoZWxnYWFz
 QGdvb2dsZS5jb20ACgkQWYigwDrT+vxkwA//dJmplIv12k94xy8rAlfMnNLg9TaO
 VEgKopeH1IZdFSwry7qTsTn6IJ1hZ6aSRrBJo+SYB5/V+kTSbsW9htyL2ZEjU1s0
 MBb6b1T6qKwKoFqMrxSMeF7nXbLy+NE6MhvlCa1wk0rbOoL5+f/t4nHblqV/Wrwh
 syzf7+sSfuJmJtzytnZ88Jo2f6EIifGQyMNgaUk9MEJSrydhavOUKKQia/9gOBz8
 Ogjnlh5pGdFQdSaLYhO0VXcimouJLqjVb/mvkE15hjzOTYw+NFaL9C3PDisxLdvQ
 sQCSFzmwJnXd2aKETPInqMamkYja+U7bCXlbt6xh2XREWioc1KLBpJpjTQeb2VxV
 w32otXCezfFJhmY2G+lLTRcGSTJ7OmBwqjTph9Pp2b4OYRNjXFtoMrLr6LxKMUuw
 dzpWUHuC/Ca+9iiMRTXJs11Bhdk1Sax3GM/Y6DzW5i/w9HWSIgvxEB7mB8jk/p6l
 C4IGOdTp2FtBjhnv5cgllMQqWd1a2cIGgF3gj7FmP5szVgoOJSyC4GgQXIe+91XO
 DM1gclWnFNyvi40bBvhsubBFeIVgzLksN7jjzsECJDpr8ql4yHiE1vcX0NqJ/qxE
 SpKnWv0m1aqUmYWSI6mvQrcsnxH5vs6O6cVoVxMzl4uhog2UzCLeiQyzpfDJpI7g
 s0FEqop9OjHkm40=
 =d0cQ
 -----END PGP SIGNATURE-----

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

Pull pci updates from Bjorn Helgaas:
 "Enumeration:
   - Fix dsm_label_utf16s_to_utf8s() buffer overrun (Krzysztof
     Wilczyński)
   - Rely on lengths from scnprintf(), dsm_label_utf16s_to_utf8s()
     (Krzysztof Wilczyński)
   - Use sysfs_emit() and sysfs_emit_at() in "show" functions (Krzysztof
     Wilczyński)
   - Fix 'resource_alignment' newline issues (Krzysztof Wilczyński)
   - Add 'devspec' newline (Krzysztof Wilczyński)
   - Dynamically map ECAM regions (Russell King)

  Resource management:
   - Coalesce host bridge contiguous apertures (Kai-Heng Feng)

  PCIe native device hotplug:
   - Ignore Link Down/Up caused by DPC (Lukas Wunner)

  Power management:
   - Leave Apple Thunderbolt controllers on for s2idle or standby
     (Konstantin Kharlamov)

  Virtualization:
   - Work around Huawei Intelligent NIC VF FLR erratum (Chiqijun)
   - Clarify error message for unbound IOV devices (Moritz Fischer)
   - Add pci_reset_bus_function() Secondary Bus Reset interface (Raphael
     Norwitz)

  Peer-to-peer DMA:
   - Simplify distance calculation (Christoph Hellwig)
   - Finish RCU conversion of pdev->p2pdma (Eric Dumazet)
   - Rename upstream_bridge_distance() and rework doc (Logan Gunthorpe)
   - Collect acs list in stack buffer to avoid sleeping (Logan
     Gunthorpe)
   - Use correct calc_map_type_and_dist() return type (Logan Gunthorpe)
   - Warn if host bridge not in whitelist (Logan Gunthorpe)
   - Refactor pci_p2pdma_map_type() (Logan Gunthorpe)
   - Avoid pci_get_slot(), which may sleep (Logan Gunthorpe)

  Altera PCIe controller driver:
   - Add Joyce Ooi as Altera PCIe maintainer (Joyce Ooi)

  Broadcom iProc PCIe controller driver:
   - Fix multi-MSI base vector number allocation (Sandor Bodo-Merle)
   - Support multi-MSI only on uniprocessor kernel (Sandor Bodo-Merle)

  Freescale i.MX6 PCIe controller driver:
   - Limit DBI register length for imx6qp PCIe (Richard Zhu)
   - Add "vph-supply" for PHY supply voltage (Richard Zhu)
   - Enable PHY internal regulator when supplied >3V (Richard Zhu)
   - Remove imx6_pcie_probe() redundant error message (Zhen Lei)

  Intel Gateway PCIe controller driver:
   - Fix INTx enable (Martin Blumenstingl)

  Marvell Aardvark PCIe controller driver:
   - Fix checking for PIO Non-posted Request (Pali Rohár)
   - Implement workaround for the readback value of VEND_ID (Pali Rohár)

  MediaTek PCIe controller driver:
   - Remove redundant error printing in mtk_pcie_subsys_powerup() (Zhen
     Lei)

  MediaTek PCIe Gen3 controller driver:
   - Add missing MODULE_DEVICE_TABLE (Zou Wei)

  Microchip PolarFlare PCIe controller driver:
   - Make struct event_descs static (Krzysztof Wilczyński)

  Microsoft Hyper-V host bridge driver:
   - Fix race condition when removing the device (Long Li)
   - Remove bus device removal unused refcount/functions (Long Li)

  Mobiveil PCIe controller driver:
   - Remove unused readl and writel functions (Krzysztof Wilczyński)

  NVIDIA Tegra PCIe controller driver:
   - Add missing MODULE_DEVICE_TABLE (Zou Wei)

  NVIDIA Tegra194 PCIe controller driver:
   - Fix tegra_pcie_ep_raise_msi_irq() ill-defined shift (Jon Hunter)
   - Fix host initialization during resume (Vidya Sagar)

  Rockchip PCIe controller driver:
   - Register IRQ handlers after device and data are ready (Javier
     Martinez Canillas)"

* tag 'pci-v5.14-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (48 commits)
  PCI/P2PDMA: Finish RCU conversion of pdev->p2pdma
  PCI: xgene: Annotate __iomem pointer
  PCI: Fix kernel-doc formatting
  PCI: cpcihp: Declare cpci_debug in header file
  MAINTAINERS: Add Joyce Ooi as Altera PCIe maintainer
  PCI: rockchip: Register IRQ handlers after device and data are ready
  PCI: tegra194: Fix tegra_pcie_ep_raise_msi_irq() ill-defined shift
  PCI: aardvark: Implement workaround for the readback value of VEND_ID
  PCI: aardvark: Fix checking for PIO Non-posted Request
  PCI: tegra194: Fix host initialization during resume
  PCI: tegra: Add missing MODULE_DEVICE_TABLE
  PCI: imx6: Enable PHY internal regulator when supplied >3V
  dt-bindings: imx6q-pcie: Add "vph-supply" for PHY supply voltage
  PCI: imx6: Limit DBI register length for imx6qp PCIe
  PCI: imx6: Remove imx6_pcie_probe() redundant error message
  PCI: intel-gw: Fix INTx enable
  PCI: iproc: Support multi-MSI only on uniprocessor kernel
  PCI: iproc: Fix multi-MSI base vector number allocation
  PCI: mediatek-gen3: Add missing MODULE_DEVICE_TABLE
  PCI: Dynamically map ECAM regions
  ...
This commit is contained in:
Linus Torvalds 2021-07-08 12:06:20 -07:00
commit 316a2c9b6a
52 changed files with 725 additions and 432 deletions

View File

@ -295,7 +295,7 @@ and let the driver restart normal I/O processing.
A driver can still return a critical failure for this function if
it can't get the device operational after reset. If the platform
previously tried a soft reset, it might now try a hard reset (power
cycle) and then call slot_reset() again. It the device still can't
cycle) and then call slot_reset() again. If the device still can't
be recovered, there is nothing more that can be done; the platform
will typically report a "permanent failure" in such a case. The
device will be considered "dead" in this case.

View File

@ -38,6 +38,9 @@ Optional properties:
The regulator will be enabled when initializing the PCIe host and
disabled either as part of the init process or when shutting down the
host.
- vph-supply: Should specify the regulator in charge of VPH one of the three
PCIe PHY powers. This regulator can be supplied by both 1.8v and 3.3v voltage
supplies.
Additional required properties for imx6sx-pcie:
- clock names: Must include the following additional entries:

View File

@ -14106,8 +14106,7 @@ F: Documentation/devicetree/bindings/pci/aardvark-pci.txt
F: drivers/pci/controller/pci-aardvark.c
PCI DRIVER FOR ALTERA PCIE IP
M: Ley Foon Tan <ley.foon.tan@intel.com>
L: rfi@lists.rocketboards.org (moderated for non-subscribers)
M: Joyce Ooi <joyce.ooi@intel.com>
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/pci/altera-pcie.txt
@ -14305,8 +14304,7 @@ S: Supported
F: Documentation/PCI/pci-error-recovery.rst
PCI MSI DRIVER FOR ALTERA MSI IP
M: Ley Foon Tan <ley.foon.tan@intel.com>
L: rfi@lists.rocketboards.org (moderated for non-subscribers)
M: Joyce Ooi <joyce.ooi@intel.com>
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/pci/altera-pcie-msi.txt

View File

@ -461,7 +461,7 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
}
if (size < (16UL<<20) && size != old_size)
return 0;
return false;
if (dev)
dev_info(dev, "MMCONFIG at %pR reserved in %s\n",
@ -493,7 +493,7 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
&cfg->res, (unsigned long) cfg->address);
}
return 1;
return true;
}
static bool __ref
@ -501,7 +501,7 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e
{
if (!early && !acpi_disabled) {
if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, 0))
return 1;
return true;
if (dev)
dev_info(dev, FW_INFO
@ -522,14 +522,14 @@ pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int e
* _CBA method, just assume it's reserved.
*/
if (pci_mmcfg_running_state)
return 1;
return true;
/* Don't try to do this check unless configuration
type 1 is available. how about type 2 ?*/
if (raw_pci_ops)
return is_mmconf_reserved(e820__mapped_all, cfg, dev, 1);
return 0;
return false;
}
static void __init pci_mmcfg_reject_broken(int early)

View File

@ -263,9 +263,12 @@ struct cdns_pcie_ops {
* struct cdns_pcie - private data for Cadence PCIe controller drivers
* @reg_base: IO mapped register base
* @mem_res: start/end offsets in the physical system memory to map PCI accesses
* @dev: PCIe controller
* @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
* @bus: In Root Complex mode, the bus number
* @ops: Platform specific ops to control various inputs from Cadence PCIe
* @phy_count: number of supported PHY devices
* @phy: list of pointers to specific PHY control blocks
* @link: list of pointers to corresponding device link representations
* @ops: Platform-specific ops to control various inputs from Cadence PCIe
* wrapper
*/
struct cdns_pcie {

View File

@ -37,6 +37,7 @@
#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
#define IMX8MQ_GPR_PCIE_VREG_BYPASS BIT(12)
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
@ -80,6 +81,7 @@ struct imx6_pcie {
u32 tx_swing_full;
u32 tx_swing_low;
struct regulator *vpcie;
struct regulator *vph;
void __iomem *phy_base;
/* power domain for pcie */
@ -621,6 +623,17 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_REF_USE_PAD,
IMX8MQ_GPR_PCIE_REF_USE_PAD);
/*
* Regarding the datasheet, the PCIE_VPH is suggested
* to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the
* VREG_BYPASS should be cleared to zero.
*/
if (imx6_pcie->vph &&
regulator_get_voltage(imx6_pcie->vph) > 3000000)
regmap_update_bits(imx6_pcie->iomuxc_gpr,
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_VREG_BYPASS,
0);
break;
case IMX7D:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
@ -1002,10 +1015,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
return ret;
}
imx6_pcie->phy_base = devm_ioremap_resource(dev, &res);
if (IS_ERR(imx6_pcie->phy_base)) {
dev_err(dev, "Unable to map PCIe PHY\n");
if (IS_ERR(imx6_pcie->phy_base))
return PTR_ERR(imx6_pcie->phy_base);
}
}
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -1130,6 +1141,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
imx6_pcie->vpcie = NULL;
}
imx6_pcie->vph = devm_regulator_get_optional(&pdev->dev, "vph");
if (IS_ERR(imx6_pcie->vph)) {
if (PTR_ERR(imx6_pcie->vph) != -ENODEV)
return PTR_ERR(imx6_pcie->vph);
imx6_pcie->vph = NULL;
}
platform_set_drvdata(pdev, imx6_pcie);
ret = imx6_pcie_attach_pd(dev);
@ -1175,6 +1193,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
.variant = IMX6QP,
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
.dbi_length = 0x200,
},
[IMX7D] = {
.variant = IMX7D,

View File

@ -39,6 +39,10 @@
#define PCIE_APP_IRN_PM_TO_ACK BIT(9)
#define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11)
#define PCIE_APP_IRN_BW_MGT BIT(12)
#define PCIE_APP_IRN_INTA BIT(13)
#define PCIE_APP_IRN_INTB BIT(14)
#define PCIE_APP_IRN_INTC BIT(15)
#define PCIE_APP_IRN_INTD BIT(16)
#define PCIE_APP_IRN_MSG_LTR BIT(18)
#define PCIE_APP_IRN_SYS_ERR_RC BIT(29)
#define PCIE_APP_INTX_OFST 12
@ -48,10 +52,8 @@
PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \
PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \
PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTA) | \
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTB) | \
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTC) | \
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTD))
PCIE_APP_IRN_INTA | PCIE_APP_IRN_INTB | \
PCIE_APP_IRN_INTC | PCIE_APP_IRN_INTD)
#define BUS_IATU_OFFSET SZ_256M
#define RESET_INTERVAL_MS 100

View File

@ -1826,7 +1826,7 @@ static int tegra_pcie_ep_raise_msi_irq(struct tegra_pcie_dw *pcie, u16 irq)
if (unlikely(irq > 31))
return -EINVAL;
appl_writel(pcie, (1 << irq), APPL_MSI_CTRL_1);
appl_writel(pcie, BIT(irq), APPL_MSI_CTRL_1);
return 0;
}
@ -2214,6 +2214,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
goto fail_host_init;
}
dw_pcie_setup_rc(&pcie->pci.pp);
ret = tegra_pcie_dw_start_link(&pcie->pci);
if (ret < 0)
goto fail_host_init;

View File

@ -42,17 +42,6 @@ struct ls_pcie_g4 {
int irq;
};
static inline u32 ls_pcie_g4_lut_readl(struct ls_pcie_g4 *pcie, u32 off)
{
return ioread32(pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
}
static inline void ls_pcie_g4_lut_writel(struct ls_pcie_g4 *pcie,
u32 off, u32 val)
{
iowrite32(val, pcie->pci.csr_axi_slave_base + PCIE_LUT_OFF + off);
}
static inline u32 ls_pcie_g4_pf_readl(struct ls_pcie_g4 *pcie, u32 off)
{
return ioread32(pcie->pci.csr_axi_slave_base + PCIE_PF_OFF + off);

View File

@ -57,7 +57,7 @@
#define PIO_COMPLETION_STATUS_UR 1
#define PIO_COMPLETION_STATUS_CRS 2
#define PIO_COMPLETION_STATUS_CA 4
#define PIO_NON_POSTED_REQ BIT(0)
#define PIO_NON_POSTED_REQ BIT(10)
#define PIO_ADDR_LS (PIO_BASE_ADDR + 0x8)
#define PIO_ADDR_MS (PIO_BASE_ADDR + 0xc)
#define PIO_WR_DATA (PIO_BASE_ADDR + 0x10)
@ -125,6 +125,7 @@
#define LTSSM_MASK 0x3f
#define LTSSM_L0 0x10
#define RC_BAR_CONFIG 0x300
#define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44)
/* PCIe core controller registers */
#define CTRL_CORE_BASE_ADDR 0x18000
@ -385,6 +386,16 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
reg |= (IS_RC_MSK << IS_RC_SHIFT);
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/*
* Replace incorrect PCI vendor id value 0x1b4b by correct value 0x11ab.
* VENDOR_ID_REG contains vendor id in low 16 bits and subsystem vendor
* id in high 16 bits. Updating this register changes readback value of
* read-only vendor id bits in PCIE_CORE_DEV_ID_REG register. Workaround
* for erratum 4.1: "The value of device and vendor ID is incorrect".
*/
reg = (PCI_VENDOR_ID_MARVELL << 16) | PCI_VENDOR_ID_MARVELL;
advk_writel(pcie, reg, VENDOR_ID_REG);
/* Set Advanced Error Capabilities and Control PF0 register */
reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX |
PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN |

View File

@ -34,12 +34,12 @@
* Special configuration registers directly in the first few words
* in I/O space.
*/
#define PCI_IOSIZE 0x00
#define PCI_PROT 0x04 /* AHB protection */
#define PCI_CTRL 0x08 /* PCI control signal */
#define PCI_SOFTRST 0x10 /* Soft reset counter and response error enable */
#define PCI_CONFIG 0x28 /* PCI configuration command register */
#define PCI_DATA 0x2C
#define FTPCI_IOSIZE 0x00
#define FTPCI_PROT 0x04 /* AHB protection */
#define FTPCI_CTRL 0x08 /* PCI control signal */
#define FTPCI_SOFTRST 0x10 /* Soft reset counter and response error enable */
#define FTPCI_CONFIG 0x28 /* PCI configuration command register */
#define FTPCI_DATA 0x2C
#define FARADAY_PCI_STATUS_CMD 0x04 /* Status and command */
#define FARADAY_PCI_PMC 0x40 /* Power management control */
@ -195,9 +195,9 @@ static int faraday_raw_pci_read_config(struct faraday_pci *p, int bus_number,
PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
PCI_CONF_WHERE(config) |
PCI_CONF_ENABLE,
p->base + PCI_CONFIG);
p->base + FTPCI_CONFIG);
*value = readl(p->base + PCI_DATA);
*value = readl(p->base + FTPCI_DATA);
if (size == 1)
*value = (*value >> (8 * (config & 3))) & 0xFF;
@ -230,17 +230,17 @@ static int faraday_raw_pci_write_config(struct faraday_pci *p, int bus_number,
PCI_CONF_FUNCTION(PCI_FUNC(fn)) |
PCI_CONF_WHERE(config) |
PCI_CONF_ENABLE,
p->base + PCI_CONFIG);
p->base + FTPCI_CONFIG);
switch (size) {
case 4:
writel(value, p->base + PCI_DATA);
writel(value, p->base + FTPCI_DATA);
break;
case 2:
writew(value, p->base + PCI_DATA + (config & 3));
writew(value, p->base + FTPCI_DATA + (config & 3));
break;
case 1:
writeb(value, p->base + PCI_DATA + (config & 3));
writeb(value, p->base + FTPCI_DATA + (config & 3));
break;
default:
ret = PCIBIOS_BAD_REGISTER_NUMBER;
@ -469,7 +469,7 @@ static int faraday_pci_probe(struct platform_device *pdev)
if (!faraday_res_to_memcfg(io->start - win->offset,
resource_size(io), &val)) {
/* setup I/O space size */
writel(val, p->base + PCI_IOSIZE);
writel(val, p->base + FTPCI_IOSIZE);
} else {
dev_err(dev, "illegal IO mem size\n");
return -EINVAL;
@ -477,11 +477,11 @@ static int faraday_pci_probe(struct platform_device *pdev)
}
/* Setup hostbridge */
val = readl(p->base + PCI_CTRL);
val = readl(p->base + FTPCI_CTRL);
val |= PCI_COMMAND_IO;
val |= PCI_COMMAND_MEMORY;
val |= PCI_COMMAND_MASTER;
writel(val, p->base + PCI_CTRL);
writel(val, p->base + FTPCI_CTRL);
/* Mask and clear all interrupts */
faraday_raw_pci_write_config(p, 0, 0, FARADAY_PCI_CTRL2 + 2, 2, 0xF000);
if (variant->cascaded_irq) {

View File

@ -444,7 +444,6 @@ enum hv_pcibus_state {
hv_pcibus_probed,
hv_pcibus_installed,
hv_pcibus_removing,
hv_pcibus_removed,
hv_pcibus_maximum
};
@ -453,7 +452,6 @@ struct hv_pcibus_device {
/* Protocol version negotiated with the host */
enum pci_protocol_version_t protocol_version;
enum hv_pcibus_state state;
refcount_t remove_lock;
struct hv_device *hdev;
resource_size_t low_mmio_space;
resource_size_t high_mmio_space;
@ -461,7 +459,6 @@ struct hv_pcibus_device {
struct resource *low_mmio_res;
struct resource *high_mmio_res;
struct completion *survey_event;
struct completion remove_event;
struct pci_bus *pci_bus;
spinlock_t config_lock; /* Avoid two threads writing index page */
spinlock_t device_list_lock; /* Protect lists below */
@ -593,9 +590,6 @@ static void put_pcichild(struct hv_pci_dev *hpdev)
kfree(hpdev);
}
static void get_hvpcibus(struct hv_pcibus_device *hv_pcibus);
static void put_hvpcibus(struct hv_pcibus_device *hv_pcibus);
/*
* There is no good way to get notified from vmbus_onoffer_rescind(),
* so let's use polling here, since this is not a hot path.
@ -2064,10 +2058,8 @@ static void pci_devices_present_work(struct work_struct *work)
}
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
if (!dr) {
put_hvpcibus(hbus);
if (!dr)
return;
}
/* First, mark all existing children as reported missing. */
spin_lock_irqsave(&hbus->device_list_lock, flags);
@ -2150,7 +2142,6 @@ static void pci_devices_present_work(struct work_struct *work)
break;
}
put_hvpcibus(hbus);
kfree(dr);
}
@ -2191,12 +2182,10 @@ static int hv_pci_start_relations_work(struct hv_pcibus_device *hbus,
list_add_tail(&dr->list_entry, &hbus->dr_list);
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
if (pending_dr) {
if (pending_dr)
kfree(dr_wrk);
} else {
get_hvpcibus(hbus);
else
queue_work(hbus->wq, &dr_wrk->wrk);
}
return 0;
}
@ -2339,8 +2328,6 @@ static void hv_eject_device_work(struct work_struct *work)
put_pcichild(hpdev);
put_pcichild(hpdev);
/* hpdev has been freed. Do not use it any more. */
put_hvpcibus(hbus);
}
/**
@ -2364,7 +2351,6 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
hpdev->state = hv_pcichild_ejecting;
get_pcichild(hpdev);
INIT_WORK(&hpdev->wrk, hv_eject_device_work);
get_hvpcibus(hbus);
queue_work(hbus->wq, &hpdev->wrk);
}
@ -2964,17 +2950,6 @@ static int hv_send_resources_released(struct hv_device *hdev)
return 0;
}
static void get_hvpcibus(struct hv_pcibus_device *hbus)
{
refcount_inc(&hbus->remove_lock);
}
static void put_hvpcibus(struct hv_pcibus_device *hbus)
{
if (refcount_dec_and_test(&hbus->remove_lock))
complete(&hbus->remove_event);
}
#define HVPCI_DOM_MAP_SIZE (64 * 1024)
static DECLARE_BITMAP(hvpci_dom_map, HVPCI_DOM_MAP_SIZE);
@ -3094,14 +3069,12 @@ static int hv_pci_probe(struct hv_device *hdev,
hbus->sysdata.domain = dom;
hbus->hdev = hdev;
refcount_set(&hbus->remove_lock, 1);
INIT_LIST_HEAD(&hbus->children);
INIT_LIST_HEAD(&hbus->dr_list);
INIT_LIST_HEAD(&hbus->resources_for_children);
spin_lock_init(&hbus->config_lock);
spin_lock_init(&hbus->device_list_lock);
spin_lock_init(&hbus->retarget_msi_interrupt_lock);
init_completion(&hbus->remove_event);
hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0,
hbus->sysdata.domain);
if (!hbus->wq) {
@ -3243,8 +3216,9 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
struct pci_packet teardown_packet;
u8 buffer[sizeof(struct pci_message)];
} pkt;
struct hv_dr_state *dr;
struct hv_pci_compl comp_pkt;
struct hv_pci_dev *hpdev, *tmp;
unsigned long flags;
int ret;
/*
@ -3256,9 +3230,16 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
if (!keep_devs) {
/* Delete any children which might still exist. */
dr = kzalloc(sizeof(*dr), GFP_KERNEL);
if (dr && hv_pci_start_relations_work(hbus, dr))
kfree(dr);
spin_lock_irqsave(&hbus->device_list_lock, flags);
list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) {
list_del(&hpdev->list_entry);
if (hpdev->pci_slot)
pci_destroy_slot(hpdev->pci_slot);
/* For the two refs got in new_pcichild_device() */
put_pcichild(hpdev);
put_pcichild(hpdev);
}
spin_unlock_irqrestore(&hbus->device_list_lock, flags);
}
ret = hv_send_resources_released(hdev);
@ -3301,13 +3282,23 @@ static int hv_pci_remove(struct hv_device *hdev)
hbus = hv_get_drvdata(hdev);
if (hbus->state == hv_pcibus_installed) {
tasklet_disable(&hdev->channel->callback_event);
hbus->state = hv_pcibus_removing;
tasklet_enable(&hdev->channel->callback_event);
destroy_workqueue(hbus->wq);
hbus->wq = NULL;
/*
* At this point, no work is running or can be scheduled
* on hbus-wq. We can't race with hv_pci_devices_present()
* or hv_pci_eject_device(), it's safe to proceed.
*/
/* Remove the bus from PCI's point of view. */
pci_lock_rescan_remove();
pci_stop_root_bus(hbus->pci_bus);
hv_pci_remove_slots(hbus);
pci_remove_root_bus(hbus->pci_bus);
pci_unlock_rescan_remove();
hbus->state = hv_pcibus_removed;
}
ret = hv_pci_bus_exit(hdev, false);
@ -3320,9 +3311,6 @@ static int hv_pci_remove(struct hv_device *hdev)
hv_pci_free_bridge_windows(hbus);
irq_domain_remove(hbus->irq_domain);
irq_domain_free_fwnode(hbus->sysdata.fwnode);
put_hvpcibus(hbus);
wait_for_completion(&hbus->remove_event);
destroy_workqueue(hbus->wq);
hv_put_dom_num(hbus->sysdata.domain);

View File

@ -2539,6 +2539,7 @@ static const struct of_device_id tegra_pcie_of_match[] = {
{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_pcie_of_match);
static void *tegra_pcie_ports_seq_start(struct seq_file *s, loff_t *pos)
{

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/**
/*
* APM X-Gene PCIe Driver
*
* Copyright (c) 2014 Applied Micro Circuits Corporation.
@ -485,7 +485,7 @@ static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
{
void __iomem *cfg_base = port->cfg_base;
struct device *dev = port->dev;
void *bar_addr;
void __iomem *bar_addr;
u32 pim_reg;
u64 cpu_addr = entry->res->start;
u64 pci_addr = cpu_addr - entry->offset;

View File

@ -49,7 +49,7 @@ enum iproc_msi_reg {
struct iproc_msi;
/**
* iProc MSI group
* struct iproc_msi_grp - iProc MSI group
*
* One MSI group is allocated per GIC interrupt, serviced by one iProc MSI
* event queue.
@ -65,7 +65,7 @@ struct iproc_msi_grp {
};
/**
* iProc event queue based MSI
* struct iproc_msi - iProc event queue based MSI
*
* Only meant to be used on platforms without MSI support integrated into the
* GIC.
@ -171,7 +171,7 @@ static struct irq_chip iproc_msi_irq_chip = {
static struct msi_domain_info iproc_msi_domain_info = {
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
MSI_FLAG_PCI_MSIX,
.chip = &iproc_msi_irq_chip,
};
@ -250,20 +250,23 @@ static int iproc_msi_irq_domain_alloc(struct irq_domain *domain,
struct iproc_msi *msi = domain->host_data;
int hwirq, i;
if (msi->nr_cpus > 1 && nr_irqs > 1)
return -EINVAL;
mutex_lock(&msi->bitmap_lock);
/* Allocate 'nr_cpus' number of MSI vectors each time */
hwirq = bitmap_find_next_zero_area(msi->bitmap, msi->nr_msi_vecs, 0,
msi->nr_cpus, 0);
if (hwirq < msi->nr_msi_vecs) {
bitmap_set(msi->bitmap, hwirq, msi->nr_cpus);
} else {
mutex_unlock(&msi->bitmap_lock);
return -ENOSPC;
}
/*
* Allocate 'nr_irqs' multiplied by 'nr_cpus' number of MSI vectors
* each time
*/
hwirq = bitmap_find_free_region(msi->bitmap, msi->nr_msi_vecs,
order_base_2(msi->nr_cpus * nr_irqs));
mutex_unlock(&msi->bitmap_lock);
if (hwirq < 0)
return -ENOSPC;
for (i = 0; i < nr_irqs; i++) {
irq_domain_set_info(domain, virq + i, hwirq + i,
&iproc_msi_bottom_irq_chip,
@ -284,7 +287,8 @@ static void iproc_msi_irq_domain_free(struct irq_domain *domain,
mutex_lock(&msi->bitmap_lock);
hwirq = hwirq_to_canonical_hwirq(msi, data->hwirq);
bitmap_clear(msi->bitmap, hwirq, msi->nr_cpus);
bitmap_release_region(msi->bitmap, hwirq,
order_base_2(msi->nr_cpus * nr_irqs));
mutex_unlock(&msi->bitmap_lock);
@ -539,6 +543,9 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node)
mutex_init(&msi->bitmap_lock);
msi->nr_cpus = num_possible_cpus();
if (msi->nr_cpus == 1)
iproc_msi_domain_info.flags |= MSI_FLAG_MULTI_PCI_MSI;
msi->nr_irqs = of_irq_count(node);
if (!msi->nr_irqs) {
dev_err(pcie->dev, "found no MSI GIC interrupt\n");

View File

@ -89,8 +89,8 @@
#define IPROC_PCIE_REG_INVALID 0xffff
/**
* iProc PCIe outbound mapping controller specific parameters
*
* struct iproc_pcie_ob_map - iProc PCIe outbound mapping controller-specific
* parameters
* @window_sizes: list of supported outbound mapping window sizes in MB
* @nr_sizes: number of supported outbound mapping window sizes
*/
@ -136,22 +136,20 @@ static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = {
};
/**
* iProc PCIe inbound mapping type
* enum iproc_pcie_ib_map_type - iProc PCIe inbound mapping type
* @IPROC_PCIE_IB_MAP_MEM: DDR memory
* @IPROC_PCIE_IB_MAP_IO: device I/O memory
* @IPROC_PCIE_IB_MAP_INVALID: invalid or unused
*/
enum iproc_pcie_ib_map_type {
/* for DDR memory */
IPROC_PCIE_IB_MAP_MEM = 0,
/* for device I/O memory */
IPROC_PCIE_IB_MAP_IO,
/* invalid or unused */
IPROC_PCIE_IB_MAP_INVALID
};
/**
* iProc PCIe inbound mapping controller specific parameters
*
* struct iproc_pcie_ib_map - iProc PCIe inbound mapping controller-specific
* parameters
* @type: inbound mapping region type
* @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or
* SZ_1G
@ -437,7 +435,7 @@ static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie,
writel(val, pcie->base + offset);
}
/**
/*
* APB error forwarding can be disabled during access of configuration
* registers of the endpoint device, to prevent unsupported requests
* (typically seen during enumeration with multi-function devices) from
@ -619,7 +617,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
/**
/*
* Note access to the configuration registers are protected at the higher layer
* by 'pci_lock' in drivers/pci/access.c
*/
@ -897,7 +895,7 @@ static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx,
return 0;
}
/**
/*
* Some iProc SoCs require the SW to configure the outbound address mapping
*
* Outbound address translation:

View File

@ -7,7 +7,13 @@
#define _PCIE_IPROC_H
/**
* iProc PCIe interface type
* enum iproc_pcie_type - iProc PCIe interface type
* @IPROC_PCIE_PAXB_BCMA: BCMA-based host controllers
* @IPROC_PCIE_PAXB: PAXB-based host controllers for
* NS, NSP, Cygnus, NS2, and Pegasus SOCs
* @IPROC_PCIE_PAXB_V2: PAXB-based host controllers for Stingray SoCs
* @IPROC_PCIE_PAXC: PAXC-based host controllers
* @IPROC_PCIE_PAXC_V2: PAXC-based host controllers (second generation)
*
* PAXB is the wrapper used in root complex that can be connected to an
* external endpoint device.
@ -24,7 +30,7 @@ enum iproc_pcie_type {
};
/**
* iProc PCIe outbound mapping
* struct iproc_pcie_ob - iProc PCIe outbound mapping
* @axi_offset: offset from the AXI address to the internal address used by
* the iProc PCIe core
* @nr_windows: total number of supported outbound mapping windows
@ -35,7 +41,7 @@ struct iproc_pcie_ob {
};
/**
* iProc PCIe inbound mapping
* struct iproc_pcie_ib - iProc PCIe inbound mapping
* @nr_regions: total number of supported inbound mapping regions
*/
struct iproc_pcie_ib {
@ -47,13 +53,13 @@ struct iproc_pcie_ib_map;
struct iproc_msi;
/**
* iProc PCIe device
*
* struct iproc_pcie - iProc PCIe device
* @dev: pointer to device data structure
* @type: iProc PCIe interface type
* @reg_offsets: register offsets
* @base: PCIe host controller I/O register base
* @base_addr: PCIe host controller register base physical address
* @mem: host bridge memory window resource
* @phy: optional PHY device that controls the Serdes
* @map_irq: function callback to map interrupts
* @ep_is_internal: indicates an internal emulated endpoint device is connected

View File

@ -1012,6 +1012,7 @@ static const struct of_device_id mtk_pcie_of_match[] = {
{ .compatible = "mediatek,mt8192-pcie" },
{},
};
MODULE_DEVICE_TABLE(of, mtk_pcie_of_match);
static struct platform_driver mtk_pcie_driver = {
.probe = mtk_pcie_probe,

View File

@ -991,10 +991,8 @@ static int mtk_pcie_subsys_powerup(struct mtk_pcie *pcie)
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "subsys");
if (regs) {
pcie->base = devm_ioremap_resource(dev, regs);
if (IS_ERR(pcie->base)) {
dev_err(dev, "failed to map shared register\n");
if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);
}
}
pcie->free_ck = devm_clk_get(dev, "free_ck");

View File

@ -341,7 +341,7 @@ static struct event_map local_status_to_event[] = {
LOCAL_STATUS_TO_EVENT_MAP(PM_MSI_INT_SYS_ERR),
};
struct {
static struct {
u32 base;
u32 offset;
u32 mask;

View File

@ -592,10 +592,6 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip)
if (err)
return err;
err = rockchip_pcie_setup_irq(rockchip);
if (err)
return err;
rockchip->vpcie12v = devm_regulator_get_optional(dev, "vpcie12v");
if (IS_ERR(rockchip->vpcie12v)) {
if (PTR_ERR(rockchip->vpcie12v) != -ENODEV)
@ -973,8 +969,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
if (err)
goto err_vpcie;
rockchip_pcie_enable_interrupts(rockchip);
err = rockchip_pcie_init_irq_domain(rockchip);
if (err < 0)
goto err_deinit_port;
@ -992,6 +986,12 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
bridge->sysdata = rockchip;
bridge->ops = &rockchip_pcie_ops;
err = rockchip_pcie_setup_irq(rockchip);
if (err)
goto err_remove_irq_domain;
rockchip_pcie_enable_interrupts(rockchip);
err = pci_host_probe(bridge);
if (err < 0)
goto err_remove_irq_domain;

View File

@ -32,7 +32,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz;
struct resource *conflict;
int i, err;
int err;
if (busr->start > busr->end)
return ERR_PTR(-EINVAL);
@ -50,6 +50,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
cfg->busr.start = busr->start;
cfg->busr.end = busr->end;
cfg->busr.flags = IORESOURCE_BUS;
cfg->bus_shift = bus_shift;
bus_range = resource_size(&cfg->busr);
bus_range_max = resource_size(cfgres) >> bus_shift;
if (bus_range > bus_range_max) {
@ -77,13 +78,6 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
cfg->winp = kcalloc(bus_range, sizeof(*cfg->winp), GFP_KERNEL);
if (!cfg->winp)
goto err_exit_malloc;
for (i = 0; i < bus_range; i++) {
cfg->winp[i] =
pci_remap_cfgspace(cfgres->start + i * bsz,
bsz);
if (!cfg->winp[i])
goto err_exit_iomap;
}
} else {
cfg->win = pci_remap_cfgspace(cfgres->start, bus_range * bsz);
if (!cfg->win)
@ -129,6 +123,44 @@ void pci_ecam_free(struct pci_config_window *cfg)
}
EXPORT_SYMBOL_GPL(pci_ecam_free);
static int pci_ecam_add_bus(struct pci_bus *bus)
{
struct pci_config_window *cfg = bus->sysdata;
unsigned int bsz = 1 << cfg->bus_shift;
unsigned int busn = bus->number;
phys_addr_t start;
if (!per_bus_mapping)
return 0;
if (busn < cfg->busr.start || busn > cfg->busr.end)
return -EINVAL;
busn -= cfg->busr.start;
start = cfg->res.start + busn * bsz;
cfg->winp[busn] = pci_remap_cfgspace(start, bsz);
if (!cfg->winp[busn])
return -ENOMEM;
return 0;
}
static void pci_ecam_remove_bus(struct pci_bus *bus)
{
struct pci_config_window *cfg = bus->sysdata;
unsigned int busn = bus->number;
if (!per_bus_mapping || busn < cfg->busr.start || busn > cfg->busr.end)
return;
busn -= cfg->busr.start;
if (cfg->winp[busn]) {
iounmap(cfg->winp[busn]);
cfg->winp[busn] = NULL;
}
}
/*
* Function to implement the pci_ops ->map_bus method
*/
@ -167,6 +199,8 @@ EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */
const struct pci_ecam_ops pci_generic_ecam_ops = {
.pci_ops = {
.add_bus = pci_ecam_add_bus,
.remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
@ -178,6 +212,8 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
/* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = {
.pci_ops = {
.add_bus = pci_ecam_add_bus,
.remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write32,
@ -187,6 +223,8 @@ const struct pci_ecam_ops pci_32b_ops = {
/* ECAM ops for 32-bit read only (non-compliant) */
const struct pci_ecam_ops pci_32b_read_ops = {
.pci_ops = {
.add_bus = pci_ecam_add_bus,
.remove_bus = pci_ecam_remove_bus,
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write,

View File

@ -75,6 +75,9 @@ int cpci_hp_unregister_bus(struct pci_bus *bus);
int cpci_hp_start(void);
int cpci_hp_stop(void);
/* Global variables */
extern int cpci_debug;
/*
* Internal function prototypes, these functions should not be used by
* board/chassis drivers.

View File

@ -19,8 +19,6 @@
#define MY_NAME "cpci_hotplug"
extern int cpci_debug;
#define dbg(format, arg...) \
do { \
if (cpci_debug) \

View File

@ -296,9 +296,10 @@ static int ctrl_slot_cleanup(struct controller *ctrl)
*
* Won't work for more than one PCI-PCI bridge in a slot.
*
* @bus_num - bus number of PCI device
* @dev_num - device number of PCI device
* @slot - Pointer to u8 where slot number will be returned
* @bus: pointer to the PCI bus structure
* @bus_num: bus number of PCI device
* @dev_num: device number of PCI device
* @slot: Pointer to u8 where slot number will be returned
*
* Output: SUCCESS or FAILURE
*/

View File

@ -1877,7 +1877,7 @@ static void interrupt_event_handler(struct controller *ctrl)
/**
* cpqhp_pushbutton_thread - handle pushbutton events
* @slot: target slot (struct)
* @t: pointer to struct timer_list which holds all timer-related callbacks
*
* Scheduled procedure to handle blocking stuff for the pushbuttons.
* Handles all pending events and exits.

View File

@ -73,7 +73,7 @@ static ssize_t power_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
return sprintf(buf, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
@ -130,7 +130,7 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
return sprintf(buf, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
@ -175,7 +175,7 @@ static ssize_t latch_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
return sprintf(buf, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static struct pci_slot_attribute hotplug_slot_attr_latch = {
@ -192,7 +192,7 @@ static ssize_t presence_read_file(struct pci_slot *pci_slot, char *buf)
if (retval)
return retval;
return sprintf(buf, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static struct pci_slot_attribute hotplug_slot_attr_presence = {

View File

@ -47,6 +47,9 @@ extern int pciehp_poll_time;
* struct controller - PCIe hotplug controller
* @pcie: pointer to the controller's PCIe port service device
* @slot_cap: cached copy of the Slot Capabilities register
* @inband_presence_disabled: In-Band Presence Detect Disable supported by
* controller and disabled per spec recommendation (PCIe r5.0, appendix I
* implementation note)
* @slot_ctrl: cached copy of the Slot Control register
* @ctrl_lock: serializes writes to the Slot Control register
* @cmd_started: jiffies when the Slot Control register was last written;

View File

@ -563,6 +563,32 @@ void pciehp_power_off_slot(struct controller *ctrl)
PCI_EXP_SLTCTL_PWR_OFF);
}
static void pciehp_ignore_dpc_link_change(struct controller *ctrl,
struct pci_dev *pdev, int irq)
{
/*
* Ignore link changes which occurred while waiting for DPC recovery.
* Could be several if DPC triggered multiple times consecutively.
*/
synchronize_hardirq(irq);
atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events);
if (pciehp_poll_mode)
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_DLLSC);
ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n",
slot_name(ctrl));
/*
* If the link is unexpectedly down after successful recovery,
* the corresponding link change may have been ignored above.
* Synthesize it to ensure that it is acted on.
*/
down_read(&ctrl->reset_lock);
if (!pciehp_check_link_active(ctrl))
pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
up_read(&ctrl->reset_lock);
}
static irqreturn_t pciehp_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
@ -706,6 +732,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
PCI_EXP_SLTCTL_ATTN_IND_ON);
}
/*
* Ignore Link Down/Up events caused by Downstream Port Containment
* if recovery from the error succeeded.
*/
if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) &&
ctrl->state == ON_STATE) {
events &= ~PCI_EXP_SLTSTA_DLLSC;
pciehp_ignore_dpc_link_change(ctrl, pdev, irq);
}
/*
* Disable requests have higher priority than Presence Detect Changed
* or Data Link Layer State Changed events.

View File

@ -50,7 +50,7 @@ static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr,
static ssize_t add_slot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "0\n");
return sysfs_emit(buf, "0\n");
}
static ssize_t remove_slot_store(struct kobject *kobj,
@ -80,7 +80,7 @@ static ssize_t remove_slot_store(struct kobject *kobj,
static ssize_t remove_slot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "0\n");
return sysfs_emit(buf, "0\n");
}
static struct kobj_attribute add_slot_attr =

View File

@ -24,50 +24,54 @@
static ssize_t show_ctrl(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev;
char *out = buf;
int index, busnr;
struct resource *res;
struct pci_bus *bus;
size_t len = 0;
pdev = to_pci_dev(dev);
bus = pdev->subordinate;
out += sprintf(buf, "Free resources: memory\n");
len += sysfs_emit_at(buf, len, "Free resources: memory\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
!(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
len += sysfs_emit_at(buf, len,
"start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
}
}
out += sprintf(out, "Free resources: prefetchable memory\n");
len += sysfs_emit_at(buf, len, "Free resources: prefetchable memory\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_PREFETCH)) {
out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
len += sysfs_emit_at(buf, len,
"start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
}
}
out += sprintf(out, "Free resources: IO\n");
len += sysfs_emit_at(buf, len, "Free resources: IO\n");
pci_bus_for_each_resource(bus, res, index) {
if (res && (res->flags & IORESOURCE_IO)) {
out += sprintf(out, "start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
len += sysfs_emit_at(buf, len,
"start = %8.8llx, length = %8.8llx\n",
(unsigned long long)res->start,
(unsigned long long)resource_size(res));
}
}
out += sprintf(out, "Free resources: bus numbers\n");
len += sysfs_emit_at(buf, len, "Free resources: bus numbers\n");
for (busnr = bus->busn_res.start; busnr <= bus->busn_res.end; busnr++) {
if (!pci_find_bus(pci_domain_nr(bus), busnr))
break;
}
if (busnr < bus->busn_res.end)
out += sprintf(out, "start = %8.8x, length = %8.8x\n",
busnr, (int)(bus->busn_res.end - busnr));
len += sysfs_emit_at(buf, len,
"start = %8.8x, length = %8.8x\n",
busnr, (int)(bus->busn_res.end - busnr));
return out - buf;
return len;
}
static DEVICE_ATTR(ctrl, S_IRUGO, show_ctrl, NULL);

View File

@ -346,7 +346,7 @@ static ssize_t sriov_totalvfs_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
return sysfs_emit(buf, "%u\n", pci_sriov_get_totalvfs(pdev));
}
static ssize_t sriov_numvfs_show(struct device *dev,
@ -361,7 +361,7 @@ static ssize_t sriov_numvfs_show(struct device *dev,
num_vfs = pdev->sriov->num_VFs;
device_unlock(&pdev->dev);
return sprintf(buf, "%u\n", num_vfs);
return sysfs_emit(buf, "%u\n", num_vfs);
}
/*
@ -391,9 +391,16 @@ static ssize_t sriov_numvfs_store(struct device *dev,
if (num_vfs == pdev->sriov->num_VFs)
goto exit;
/* is PF driver loaded */
if (!pdev->driver) {
pci_info(pdev, "no driver bound to device; cannot configure SR-IOV\n");
ret = -ENOENT;
goto exit;
}
/* is PF driver loaded w/callback */
if (!pdev->driver || !pdev->driver->sriov_configure) {
pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n");
if (!pdev->driver->sriov_configure) {
pci_info(pdev, "driver does not support SR-IOV configuration via sysfs\n");
ret = -ENOENT;
goto exit;
}
@ -435,7 +442,7 @@ static ssize_t sriov_offset_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%u\n", pdev->sriov->offset);
return sysfs_emit(buf, "%u\n", pdev->sriov->offset);
}
static ssize_t sriov_stride_show(struct device *dev,
@ -444,7 +451,7 @@ static ssize_t sriov_stride_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%u\n", pdev->sriov->stride);
return sysfs_emit(buf, "%u\n", pdev->sriov->stride);
}
static ssize_t sriov_vf_device_show(struct device *dev,
@ -453,7 +460,7 @@ static ssize_t sriov_vf_device_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%x\n", pdev->sriov->vf_device);
return sysfs_emit(buf, "%x\n", pdev->sriov->vf_device);
}
static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
@ -462,7 +469,7 @@ static ssize_t sriov_drivers_autoprobe_show(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe);
return sysfs_emit(buf, "%u\n", pdev->sriov->drivers_autoprobe);
}
static ssize_t sriov_drivers_autoprobe_store(struct device *dev,

View File

@ -464,11 +464,11 @@ static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr,
return retval;
entry = irq_get_msi_desc(irq);
if (entry)
return sprintf(buf, "%s\n",
entry->msi_attrib.is_msix ? "msix" : "msi");
if (!entry)
return -ENODEV;
return -ENODEV;
return sysfs_emit(buf, "%s\n",
entry->msi_attrib.is_msix ? "msix" : "msi");
}
static int populate_msi_sysfs(struct pci_dev *pdev)

View File

@ -48,12 +48,16 @@ static ssize_t size_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_p2pdma *p2pdma;
size_t size = 0;
if (pdev->p2pdma->pool)
size = gen_pool_size(pdev->p2pdma->pool);
rcu_read_lock();
p2pdma = rcu_dereference(pdev->p2pdma);
if (p2pdma && p2pdma->pool)
size = gen_pool_size(p2pdma->pool);
rcu_read_unlock();
return scnprintf(buf, PAGE_SIZE, "%zd\n", size);
return sysfs_emit(buf, "%zd\n", size);
}
static DEVICE_ATTR_RO(size);
@ -61,12 +65,16 @@ static ssize_t available_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_p2pdma *p2pdma;
size_t avail = 0;
if (pdev->p2pdma->pool)
avail = gen_pool_avail(pdev->p2pdma->pool);
rcu_read_lock();
p2pdma = rcu_dereference(pdev->p2pdma);
if (p2pdma && p2pdma->pool)
avail = gen_pool_avail(p2pdma->pool);
rcu_read_unlock();
return scnprintf(buf, PAGE_SIZE, "%zd\n", avail);
return sysfs_emit(buf, "%zd\n", avail);
}
static DEVICE_ATTR_RO(available);
@ -74,9 +82,16 @@ static ssize_t published_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pci_p2pdma *p2pdma;
bool published = false;
return scnprintf(buf, PAGE_SIZE, "%d\n",
pdev->p2pdma->p2pmem_published);
rcu_read_lock();
p2pdma = rcu_dereference(pdev->p2pdma);
if (p2pdma)
published = p2pdma->p2pmem_published;
rcu_read_unlock();
return sysfs_emit(buf, "%d\n", published);
}
static DEVICE_ATTR_RO(published);
@ -95,8 +110,9 @@ static const struct attribute_group p2pmem_group = {
static void pci_p2pdma_release(void *data)
{
struct pci_dev *pdev = data;
struct pci_p2pdma *p2pdma = pdev->p2pdma;
struct pci_p2pdma *p2pdma;
p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
if (!p2pdma)
return;
@ -128,16 +144,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev)
if (error)
goto out_pool_destroy;
pdev->p2pdma = p2p;
error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group);
if (error)
goto out_pool_destroy;
rcu_assign_pointer(pdev->p2pdma, p2p);
return 0;
out_pool_destroy:
pdev->p2pdma = NULL;
gen_pool_destroy(p2p->pool);
out:
devm_kfree(&pdev->dev, p2p);
@ -159,6 +173,7 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
{
struct pci_p2pdma_pagemap *p2p_pgmap;
struct dev_pagemap *pgmap;
struct pci_p2pdma *p2pdma;
void *addr;
int error;
@ -200,7 +215,8 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
goto pgmap_free;
}
error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr,
p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
error = gen_pool_add_owner(p2pdma->pool, (unsigned long)addr,
pci_bus_address(pdev, bar) + offset,
range_len(&pgmap->range), dev_to_node(&pdev->dev),
pgmap->ref);
@ -308,10 +324,41 @@ static const struct pci_p2pdma_whitelist_entry {
{}
};
static bool __host_bridge_whitelist(struct pci_host_bridge *host,
bool same_host_bridge)
/*
* This lookup function tries to find the PCI device corresponding to a given
* host bridge.
*
* It assumes the host bridge device is the first PCI device in the
* bus->devices list and that the devfn is 00.0. These assumptions should hold
* for all the devices in the whitelist above.
*
* This function is equivalent to pci_get_slot(host->bus, 0), however it does
* not take the pci_bus_sem lock seeing __host_bridge_whitelist() must not
* sleep.
*
* For this to be safe, the caller should hold a reference to a device on the
* bridge, which should ensure the host_bridge device will not be freed
* or removed from the head of the devices list.
*/
static struct pci_dev *pci_host_bridge_dev(struct pci_host_bridge *host)
{
struct pci_dev *root = pci_get_slot(host->bus, PCI_DEVFN(0, 0));
struct pci_dev *root;
root = list_first_entry_or_null(&host->bus->devices,
struct pci_dev, bus_list);
if (!root)
return NULL;
if (root->devfn != PCI_DEVFN(0, 0))
return NULL;
return root;
}
static bool __host_bridge_whitelist(struct pci_host_bridge *host,
bool same_host_bridge, bool warn)
{
struct pci_dev *root = pci_host_bridge_dev(host);
const struct pci_p2pdma_whitelist_entry *entry;
unsigned short vendor, device;
@ -320,7 +367,6 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
vendor = root->vendor;
device = root->device;
pci_dev_put(root);
for (entry = pci_p2pdma_whitelist; entry->vendor; entry++) {
if (vendor != entry->vendor || device != entry->device)
@ -331,6 +377,10 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
return true;
}
if (warn)
pci_warn(root, "Host bridge not in P2PDMA whitelist: %04x:%04x\n",
vendor, device);
return false;
}
@ -338,44 +388,90 @@ static bool __host_bridge_whitelist(struct pci_host_bridge *host,
* If we can't find a common upstream bridge take a look at the root
* complex and compare it to a whitelist of known good hardware.
*/
static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b)
static bool host_bridge_whitelist(struct pci_dev *a, struct pci_dev *b,
bool warn)
{
struct pci_host_bridge *host_a = pci_find_host_bridge(a->bus);
struct pci_host_bridge *host_b = pci_find_host_bridge(b->bus);
if (host_a == host_b)
return __host_bridge_whitelist(host_a, true);
return __host_bridge_whitelist(host_a, true, warn);
if (__host_bridge_whitelist(host_a, false) &&
__host_bridge_whitelist(host_b, false))
if (__host_bridge_whitelist(host_a, false, warn) &&
__host_bridge_whitelist(host_b, false, warn))
return true;
return false;
}
static enum pci_p2pdma_map_type
__upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
int *dist, bool *acs_redirects, struct seq_buf *acs_list)
static unsigned long map_types_idx(struct pci_dev *client)
{
return (pci_domain_nr(client->bus) << 16) |
(client->bus->number << 8) | client->devfn;
}
/*
* Calculate the P2PDMA mapping type and distance between two PCI devices.
*
* If the two devices are the same PCI function, return
* PCI_P2PDMA_MAP_BUS_ADDR and a distance of 0.
*
* If they are two functions of the same device, return
* PCI_P2PDMA_MAP_BUS_ADDR and a distance of 2 (one hop up to the bridge,
* then one hop back down to another function of the same device).
*
* In the case where two devices are connected to the same PCIe switch,
* return a distance of 4. This corresponds to the following PCI tree:
*
* -+ Root Port
* \+ Switch Upstream Port
* +-+ Switch Downstream Port 0
* + \- Device A
* \-+ Switch Downstream Port 1
* \- Device B
*
* The distance is 4 because we traverse from Device A to Downstream Port 0
* to the common Switch Upstream Port, back down to Downstream Port 1 and
* then to Device B. The mapping type returned depends on the ACS
* redirection setting of the ports along the path.
*
* If ACS redirect is set on any port in the path, traffic between the
* devices will go through the host bridge, so return
* PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; otherwise return
* PCI_P2PDMA_MAP_BUS_ADDR.
*
* Any two devices that have a data path that goes through the host bridge
* will consult a whitelist. If the host bridge is in the whitelist, return
* PCI_P2PDMA_MAP_THRU_HOST_BRIDGE with the distance set to the number of
* ports per above. If the device is not in the whitelist, return
* PCI_P2PDMA_MAP_NOT_SUPPORTED.
*/
static enum pci_p2pdma_map_type
calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
int *dist, bool verbose)
{
enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
struct pci_dev *a = provider, *b = client, *bb;
bool acs_redirects = false;
struct pci_p2pdma *p2pdma;
struct seq_buf acs_list;
int acs_cnt = 0;
int dist_a = 0;
int dist_b = 0;
int acs_cnt = 0;
char buf[128];
if (acs_redirects)
*acs_redirects = false;
seq_buf_init(&acs_list, buf, sizeof(buf));
/*
* Note, we don't need to take references to devices returned by
* pci_upstream_bridge() seeing we hold a reference to a child
* device which will already hold a reference to the upstream bridge.
*/
while (a) {
dist_b = 0;
if (pci_bridge_has_acs_redir(a)) {
seq_buf_print_bus_devfn(acs_list, a);
seq_buf_print_bus_devfn(&acs_list, a);
acs_cnt++;
}
@ -393,10 +489,8 @@ __upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
dist_a++;
}
if (dist)
*dist = dist_a + dist_b;
return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
*dist = dist_a + dist_b;
goto map_through_host_bridge;
check_b_path_acs:
bb = b;
@ -406,124 +500,45 @@ check_b_path_acs:
break;
if (pci_bridge_has_acs_redir(bb)) {
seq_buf_print_bus_devfn(acs_list, bb);
seq_buf_print_bus_devfn(&acs_list, bb);
acs_cnt++;
}
bb = pci_upstream_bridge(bb);
}
if (dist)
*dist = dist_a + dist_b;
*dist = dist_a + dist_b;
if (acs_cnt) {
if (acs_redirects)
*acs_redirects = true;
return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
if (!acs_cnt) {
map_type = PCI_P2PDMA_MAP_BUS_ADDR;
goto done;
}
return PCI_P2PDMA_MAP_BUS_ADDR;
}
static unsigned long map_types_idx(struct pci_dev *client)
{
return (pci_domain_nr(client->bus) << 16) |
(client->bus->number << 8) | client->devfn;
}
/*
* Find the distance through the nearest common upstream bridge between
* two PCI devices.
*
* If the two devices are the same device then 0 will be returned.
*
* If there are two virtual functions of the same device behind the same
* bridge port then 2 will be returned (one step down to the PCIe switch,
* then one step back to the same device).
*
* In the case where two devices are connected to the same PCIe switch, the
* value 4 will be returned. This corresponds to the following PCI tree:
*
* -+ Root Port
* \+ Switch Upstream Port
* +-+ Switch Downstream Port
* + \- Device A
* \-+ Switch Downstream Port
* \- Device B
*
* The distance is 4 because we traverse from Device A through the downstream
* port of the switch, to the common upstream port, back up to the second
* downstream port and then to Device B.
*
* Any two devices that cannot communicate using p2pdma will return
* PCI_P2PDMA_MAP_NOT_SUPPORTED.
*
* Any two devices that have a data path that goes through the host bridge
* will consult a whitelist. If the host bridges are on the whitelist,
* this function will return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE.
*
* If either bridge is not on the whitelist this function returns
* PCI_P2PDMA_MAP_NOT_SUPPORTED.
*
* If a bridge which has any ACS redirection bits set is in the path,
* acs_redirects will be set to true. In this case, a list of all infringing
* bridge addresses will be populated in acs_list (assuming it's non-null)
* for printk purposes.
*/
static enum pci_p2pdma_map_type
upstream_bridge_distance(struct pci_dev *provider, struct pci_dev *client,
int *dist, bool *acs_redirects, struct seq_buf *acs_list)
{
enum pci_p2pdma_map_type map_type;
map_type = __upstream_bridge_distance(provider, client, dist,
acs_redirects, acs_list);
if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) {
if (!cpu_supports_p2pdma() &&
!host_bridge_whitelist(provider, client))
map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
}
if (provider->p2pdma)
xa_store(&provider->p2pdma->map_types, map_types_idx(client),
xa_mk_value(map_type), GFP_KERNEL);
return map_type;
}
static enum pci_p2pdma_map_type
upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client,
int *dist)
{
struct seq_buf acs_list;
bool acs_redirects;
int ret;
seq_buf_init(&acs_list, kmalloc(PAGE_SIZE, GFP_KERNEL), PAGE_SIZE);
if (!acs_list.buffer)
return -ENOMEM;
ret = upstream_bridge_distance(provider, client, dist, &acs_redirects,
&acs_list);
if (acs_redirects) {
if (verbose) {
acs_list.buffer[acs_list.len-1] = 0; /* drop final semicolon */
pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
pci_name(provider));
/* Drop final semicolon */
acs_list.buffer[acs_list.len-1] = 0;
pci_warn(client, "to disable ACS redirect for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
acs_list.buffer);
}
acs_redirects = true;
if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED) {
pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
pci_name(provider));
map_through_host_bridge:
if (!cpu_supports_p2pdma() &&
!host_bridge_whitelist(provider, client, acs_redirects)) {
if (verbose)
pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
pci_name(provider));
map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
}
kfree(acs_list.buffer);
return ret;
done:
rcu_read_lock();
p2pdma = rcu_dereference(provider->p2pdma);
if (p2pdma)
xa_store(&p2pdma->map_types, map_types_idx(client),
xa_mk_value(map_type), GFP_KERNEL);
rcu_read_unlock();
return map_type;
}
/**
@ -546,11 +561,11 @@ upstream_bridge_distance_warn(struct pci_dev *provider, struct pci_dev *client,
int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
int num_clients, bool verbose)
{
enum pci_p2pdma_map_type map;
bool not_supported = false;
struct pci_dev *pci_client;
int total_dist = 0;
int distance;
int i, ret;
int i, distance;
if (num_clients == 0)
return -1;
@ -564,16 +579,12 @@ int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
return -1;
}
if (verbose)
ret = upstream_bridge_distance_warn(provider,
pci_client, &distance);
else
ret = upstream_bridge_distance(provider, pci_client,
&distance, NULL, NULL);
map = calc_map_type_and_dist(provider, pci_client, &distance,
verbose);
pci_dev_put(pci_client);
if (ret == PCI_P2PDMA_MAP_NOT_SUPPORTED)
if (map == PCI_P2PDMA_MAP_NOT_SUPPORTED)
not_supported = true;
if (not_supported && !verbose)
@ -595,7 +606,15 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_distance_many);
*/
bool pci_has_p2pmem(struct pci_dev *pdev)
{
return pdev->p2pdma && pdev->p2pdma->p2pmem_published;
struct pci_p2pdma *p2pdma;
bool res;
rcu_read_lock();
p2pdma = rcu_dereference(pdev->p2pdma);
res = p2pdma && p2pdma->p2pmem_published;
rcu_read_unlock();
return res;
}
EXPORT_SYMBOL_GPL(pci_has_p2pmem);
@ -675,6 +694,7 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
{
void *ret = NULL;
struct percpu_ref *ref;
struct pci_p2pdma *p2pdma;
/*
* Pairs with synchronize_rcu() in pci_p2pdma_release() to
@ -682,16 +702,16 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
* read-lock.
*/
rcu_read_lock();
if (unlikely(!pdev->p2pdma))
p2pdma = rcu_dereference(pdev->p2pdma);
if (unlikely(!p2pdma))
goto out;
ret = (void *)gen_pool_alloc_owner(pdev->p2pdma->pool, size,
(void **) &ref);
ret = (void *)gen_pool_alloc_owner(p2pdma->pool, size, (void **) &ref);
if (!ret)
goto out;
if (unlikely(!percpu_ref_tryget_live(ref))) {
gen_pool_free(pdev->p2pdma->pool, (unsigned long) ret, size);
gen_pool_free(p2pdma->pool, (unsigned long) ret, size);
ret = NULL;
goto out;
}
@ -710,8 +730,9 @@ EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
{
struct percpu_ref *ref;
struct pci_p2pdma *p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
gen_pool_free_owner(pdev->p2pdma->pool, (uintptr_t)addr, size,
gen_pool_free_owner(p2pdma->pool, (uintptr_t)addr, size,
(void **) &ref);
percpu_ref_put(ref);
}
@ -725,9 +746,13 @@ EXPORT_SYMBOL_GPL(pci_free_p2pmem);
*/
pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
{
struct pci_p2pdma *p2pdma;
if (!addr)
return 0;
if (!pdev->p2pdma)
p2pdma = rcu_dereference_protected(pdev->p2pdma, 1);
if (!p2pdma)
return 0;
/*
@ -735,7 +760,7 @@ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
* bus address as the physical address. So gen_pool_virt_to_phys()
* actually returns the bus address despite the misleading name.
*/
return gen_pool_virt_to_phys(pdev->p2pdma->pool, (unsigned long)addr);
return gen_pool_virt_to_phys(p2pdma->pool, (unsigned long)addr);
}
EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
@ -806,19 +831,40 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
*/
void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
{
if (pdev->p2pdma)
pdev->p2pdma->p2pmem_published = publish;
struct pci_p2pdma *p2pdma;
rcu_read_lock();
p2pdma = rcu_dereference(pdev->p2pdma);
if (p2pdma)
p2pdma->p2pmem_published = publish;
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct pci_dev *provider,
struct pci_dev *client)
static enum pci_p2pdma_map_type pci_p2pdma_map_type(struct dev_pagemap *pgmap,
struct device *dev)
{
enum pci_p2pdma_map_type type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
struct pci_dev *provider = to_p2p_pgmap(pgmap)->provider;
struct pci_dev *client;
struct pci_p2pdma *p2pdma;
if (!provider->p2pdma)
return PCI_P2PDMA_MAP_NOT_SUPPORTED;
return xa_to_value(xa_load(&provider->p2pdma->map_types,
map_types_idx(client)));
if (!dev_is_pci(dev))
return PCI_P2PDMA_MAP_NOT_SUPPORTED;
client = to_pci_dev(dev);
rcu_read_lock();
p2pdma = rcu_dereference(provider->p2pdma);
if (p2pdma)
type = xa_to_value(xa_load(&p2pdma->map_types,
map_types_idx(client)));
rcu_read_unlock();
return type;
}
static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
@ -853,14 +899,8 @@ int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
{
struct pci_p2pdma_pagemap *p2p_pgmap =
to_p2p_pgmap(sg_page(sg)->pgmap);
struct pci_dev *client;
if (WARN_ON_ONCE(!dev_is_pci(dev)))
return 0;
client = to_pci_dev(dev);
switch (pci_p2pdma_map_type(p2p_pgmap->provider, client)) {
switch (pci_p2pdma_map_type(sg_page(sg)->pgmap, dev)) {
case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE:
return dma_map_sg_attrs(dev, sg, nents, dir, attrs);
case PCI_P2PDMA_MAP_BUS_ADDR:
@ -884,17 +924,9 @@ EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs);
void pci_p2pdma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir, unsigned long attrs)
{
struct pci_p2pdma_pagemap *p2p_pgmap =
to_p2p_pgmap(sg_page(sg)->pgmap);
enum pci_p2pdma_map_type map_type;
struct pci_dev *client;
if (WARN_ON_ONCE(!dev_is_pci(dev)))
return;
client = to_pci_dev(dev);
map_type = pci_p2pdma_map_type(p2p_pgmap->provider, client);
map_type = pci_p2pdma_map_type(sg_page(sg)->pgmap, dev);
if (map_type == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE)
dma_unmap_sg_attrs(dev, sg, nents, dir, attrs);

View File

@ -139,14 +139,17 @@ enum acpi_attr_enum {
ACPI_ATTR_INDEX_SHOW,
};
static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
static int dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
{
int len;
len = utf16s_to_utf8s((const wchar_t *)obj->buffer.pointer,
obj->buffer.length,
UTF16_LITTLE_ENDIAN,
buf, PAGE_SIZE);
buf[len] = '\n';
buf, PAGE_SIZE - 1);
buf[len++] = '\n';
return len;
}
static int dsm_get_label(struct device *dev, char *buf,
@ -154,7 +157,7 @@ static int dsm_get_label(struct device *dev, char *buf,
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object *obj, *tmp;
int len = -1;
int len = 0;
if (!handle)
return -1;
@ -175,20 +178,19 @@ static int dsm_get_label(struct device *dev, char *buf,
* this entry must return a null string.
*/
if (attr == ACPI_ATTR_INDEX_SHOW) {
scnprintf(buf, PAGE_SIZE, "%llu\n", tmp->integer.value);
len = sysfs_emit(buf, "%llu\n", tmp->integer.value);
} else if (attr == ACPI_ATTR_LABEL_SHOW) {
if (tmp[1].type == ACPI_TYPE_STRING)
scnprintf(buf, PAGE_SIZE, "%s\n",
tmp[1].string.pointer);
len = sysfs_emit(buf, "%s\n",
tmp[1].string.pointer);
else if (tmp[1].type == ACPI_TYPE_BUFFER)
dsm_label_utf16s_to_utf8s(tmp + 1, buf);
len = dsm_label_utf16s_to_utf8s(tmp + 1, buf);
}
len = strlen(buf) > 0 ? strlen(buf) : -1;
}
ACPI_FREE(obj);
return len;
return len > 0 ? len : -1;
}
static ssize_t label_show(struct device *dev, struct device_attribute *attr,

View File

@ -537,7 +537,7 @@ static ssize_t devspec_show(struct device *dev,
if (np == NULL)
return 0;
return sysfs_emit(buf, "%pOF", np);
return sysfs_emit(buf, "%pOF\n", np);
}
static DEVICE_ATTR_RO(devspec);
#endif

View File

@ -5030,6 +5030,16 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
return pci_reset_hotplug_slot(dev->slot->hotplug, probe);
}
static int pci_reset_bus_function(struct pci_dev *dev, int probe)
{
int rc;
rc = pci_dev_reset_slot_function(dev, probe);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, probe);
}
static void pci_dev_lock(struct pci_dev *dev)
{
pci_cfg_access_lock(dev);
@ -5152,10 +5162,7 @@ int __pci_reset_function_locked(struct pci_dev *dev)
rc = pci_pm_reset(dev, 0);
if (rc != -ENOTTY)
return rc;
rc = pci_dev_reset_slot_function(dev, 0);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, 0);
return pci_reset_bus_function(dev, 0);
}
EXPORT_SYMBOL_GPL(__pci_reset_function_locked);
@ -5185,13 +5192,10 @@ int pci_probe_reset_function(struct pci_dev *dev)
if (rc != -ENOTTY)
return rc;
rc = pci_pm_reset(dev, 1);
if (rc != -ENOTTY)
return rc;
rc = pci_dev_reset_slot_function(dev, 1);
if (rc != -ENOTTY)
return rc;
return pci_parent_bus_reset(dev, 1);
return pci_reset_bus_function(dev, 1);
}
/**
@ -6451,34 +6455,40 @@ static ssize_t resource_alignment_show(struct bus_type *bus, char *buf)
spin_lock(&resource_alignment_lock);
if (resource_alignment_param)
count = scnprintf(buf, PAGE_SIZE, "%s", resource_alignment_param);
count = sysfs_emit(buf, "%s\n", resource_alignment_param);
spin_unlock(&resource_alignment_lock);
/*
* When set by the command line, resource_alignment_param will not
* have a trailing line feed, which is ugly. So conditionally add
* it here.
*/
if (count >= 2 && buf[count - 2] != '\n' && count < PAGE_SIZE - 1) {
buf[count - 1] = '\n';
buf[count++] = 0;
}
return count;
}
static ssize_t resource_alignment_store(struct bus_type *bus,
const char *buf, size_t count)
{
char *param = kstrndup(buf, count, GFP_KERNEL);
char *param, *old, *end;
if (count >= (PAGE_SIZE - 1))
return -EINVAL;
param = kstrndup(buf, count, GFP_KERNEL);
if (!param)
return -ENOMEM;
end = strchr(param, '\n');
if (end)
*end = '\0';
spin_lock(&resource_alignment_lock);
kfree(resource_alignment_param);
resource_alignment_param = param;
old = resource_alignment_param;
if (strlen(param)) {
resource_alignment_param = param;
} else {
kfree(param);
resource_alignment_param = NULL;
}
spin_unlock(&resource_alignment_lock);
kfree(old);
return count;
}

View File

@ -324,8 +324,8 @@ struct pci_sriov {
/**
* pci_dev_set_io_state - Set the new error state if possible.
*
* @dev - pci device to set new error_state
* @new - the state we want dev to be in
* @dev: PCI device to set new error_state
* @new: the state we want dev to be in
*
* Must be called with device_lock held.
*
@ -385,6 +385,8 @@ static inline bool pci_dev_is_disconnected(const struct pci_dev *dev)
/* pci_dev priv_flags */
#define PCI_DEV_ADDED 0
#define PCI_DPC_RECOVERED 1
#define PCI_DPC_RECOVERING 2
static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
{
@ -439,10 +441,12 @@ void pci_restore_dpc_state(struct pci_dev *dev);
void pci_dpc_init(struct pci_dev *pdev);
void dpc_process_error(struct pci_dev *pdev);
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
bool pci_dpc_recovered(struct pci_dev *pdev);
#else
static inline void pci_save_dpc_state(struct pci_dev *dev) {}
static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
static inline void pci_dpc_init(struct pci_dev *pdev) {}
static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
#endif
#ifdef CONFIG_PCIEPORTBUS

View File

@ -529,21 +529,23 @@ static const char *aer_agent_string[] = {
char *buf) \
{ \
unsigned int i; \
char *str = buf; \
struct pci_dev *pdev = to_pci_dev(dev); \
u64 *stats = pdev->aer_stats->stats_array; \
size_t len = 0; \
\
for (i = 0; i < ARRAY_SIZE(strings_array); i++) { \
if (strings_array[i]) \
str += sprintf(str, "%s %llu\n", \
strings_array[i], stats[i]); \
len += sysfs_emit_at(buf, len, "%s %llu\n", \
strings_array[i], \
stats[i]); \
else if (stats[i]) \
str += sprintf(str, #stats_array "_bit[%d] %llu\n",\
i, stats[i]); \
len += sysfs_emit_at(buf, len, \
#stats_array "_bit[%d] %llu\n",\
i, stats[i]); \
} \
str += sprintf(str, "TOTAL_%s %llu\n", total_string, \
pdev->aer_stats->total_field); \
return str-buf; \
len += sysfs_emit_at(buf, len, "TOTAL_%s %llu\n", total_string, \
pdev->aer_stats->total_field); \
return len; \
} \
static DEVICE_ATTR_RO(name)
@ -563,7 +565,7 @@ aer_stats_dev_attr(aer_dev_nonfatal, dev_nonfatal_errs,
char *buf) \
{ \
struct pci_dev *pdev = to_pci_dev(dev); \
return sprintf(buf, "%llu\n", pdev->aer_stats->field); \
return sysfs_emit(buf, "%llu\n", pdev->aer_stats->field); \
} \
static DEVICE_ATTR_RO(name)
@ -983,7 +985,7 @@ static void aer_recover_work_func(struct work_struct *work)
pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus,
entry.devfn);
if (!pdev) {
pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n",
pr_err("no pci_dev for %04x:%02x:%02x.%x\n",
entry.domain, entry.bus,
PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
continue;
@ -1022,7 +1024,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
&aer_recover_ring_lock))
schedule_work(&aer_recover_work);
else
pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n",
pr_err("buffer overflow in recovery for %04x:%02x:%02x.%x\n",
domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
}
EXPORT_SYMBOL_GPL(aer_recover_queue);

View File

@ -1208,7 +1208,7 @@ static ssize_t aspm_attr_show_common(struct device *dev,
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
return sprintf(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
return sysfs_emit(buf, "%d\n", (link->aspm_enabled & state) ? 1 : 0);
}
static ssize_t aspm_attr_store_common(struct device *dev,
@ -1265,7 +1265,7 @@ static ssize_t clkpm_show(struct device *dev,
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link = pcie_aspm_get_link(pdev);
return sprintf(buf, "%d\n", link->clkpm_enabled);
return sysfs_emit(buf, "%d\n", link->clkpm_enabled);
}
static ssize_t clkpm_store(struct device *dev,

View File

@ -71,6 +71,58 @@ void pci_restore_dpc_state(struct pci_dev *dev)
pci_write_config_word(dev, dev->dpc_cap + PCI_EXP_DPC_CTL, *cap);
}
static DECLARE_WAIT_QUEUE_HEAD(dpc_completed_waitqueue);
#ifdef CONFIG_HOTPLUG_PCI_PCIE
static bool dpc_completed(struct pci_dev *pdev)
{
u16 status;
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, &status);
if ((status != 0xffff) && (status & PCI_EXP_DPC_STATUS_TRIGGER))
return false;
if (test_bit(PCI_DPC_RECOVERING, &pdev->priv_flags))
return false;
return true;
}
/**
* pci_dpc_recovered - whether DPC triggered and has recovered successfully
* @pdev: PCI device
*
* Return true if DPC was triggered for @pdev and has recovered successfully.
* Wait for recovery if it hasn't completed yet. Called from the PCIe hotplug
* driver to recognize and ignore Link Down/Up events caused by DPC.
*/
bool pci_dpc_recovered(struct pci_dev *pdev)
{
struct pci_host_bridge *host;
if (!pdev->dpc_cap)
return false;
/*
* Synchronization between hotplug and DPC is not supported
* if DPC is owned by firmware and EDR is not enabled.
*/
host = pci_find_host_bridge(pdev->bus);
if (!host->native_dpc && !IS_ENABLED(CONFIG_PCIE_EDR))
return false;
/*
* Need a timeout in case DPC never completes due to failure of
* dpc_wait_rp_inactive(). The spec doesn't mandate a time limit,
* but reports indicate that DPC completes within 4 seconds.
*/
wait_event_timeout(dpc_completed_waitqueue, dpc_completed(pdev),
msecs_to_jiffies(4000));
return test_and_clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
}
#endif /* CONFIG_HOTPLUG_PCI_PCIE */
static int dpc_wait_rp_inactive(struct pci_dev *pdev)
{
unsigned long timeout = jiffies + HZ;
@ -91,8 +143,11 @@ static int dpc_wait_rp_inactive(struct pci_dev *pdev)
pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
{
pci_ers_result_t ret;
u16 cap;
set_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
/*
* DPC disables the Link automatically in hardware, so it has
* already been reset by the time we get here.
@ -106,18 +161,27 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
if (!pcie_wait_for_link(pdev, false))
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
return PCI_ERS_RESULT_DISCONNECT;
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) {
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_DISCONNECT;
goto out;
}
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
if (!pcie_wait_for_link(pdev, true)) {
pci_info(pdev, "Data Link Layer Link Active not set in 1000 msec\n");
return PCI_ERS_RESULT_DISCONNECT;
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_DISCONNECT;
} else {
set_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
ret = PCI_ERS_RESULT_RECOVERED;
}
return PCI_ERS_RESULT_RECOVERED;
out:
clear_bit(PCI_DPC_RECOVERING, &pdev->priv_flags);
wake_up_all(&dpc_completed_waitqueue);
return ret;
}
static void dpc_process_rp_pio_error(struct pci_dev *pdev)

View File

@ -19,6 +19,7 @@
#include <linux/hypervisor.h>
#include <linux/irqdomain.h>
#include <linux/pm_runtime.h>
#include <linux/list_sort.h>
#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@ -874,14 +875,31 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus)
dev_set_msi_domain(&bus->dev, d);
}
static int res_cmp(void *priv, const struct list_head *a,
const struct list_head *b)
{
struct resource_entry *entry1, *entry2;
entry1 = container_of(a, struct resource_entry, node);
entry2 = container_of(b, struct resource_entry, node);
if (entry1->res->flags != entry2->res->flags)
return entry1->res->flags > entry2->res->flags;
if (entry1->offset != entry2->offset)
return entry1->offset > entry2->offset;
return entry1->res->start > entry2->res->start;
}
static int pci_register_host_bridge(struct pci_host_bridge *bridge)
{
struct device *parent = bridge->dev.parent;
struct resource_entry *window, *n;
struct resource_entry *window, *next, *n;
struct pci_bus *bus, *b;
resource_size_t offset;
resource_size_t offset, next_offset;
LIST_HEAD(resources);
struct resource *res;
struct resource *res, *next_res;
char addr[64], *fmt;
const char *name;
int err;
@ -961,11 +979,35 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
if (nr_node_ids > 1 && pcibus_to_node(bus) == NUMA_NO_NODE)
dev_warn(&bus->dev, "Unknown NUMA node; performance will be reduced\n");
/* Add initial resources to the bus */
/* Sort and coalesce contiguous windows */
list_sort(NULL, &resources, res_cmp);
resource_list_for_each_entry_safe(window, n, &resources) {
list_move_tail(&window->node, &bridge->windows);
if (list_is_last(&window->node, &resources))
break;
next = list_next_entry(window, node);
offset = window->offset;
res = window->res;
next_offset = next->offset;
next_res = next->res;
if (res->flags != next_res->flags || offset != next_offset)
continue;
if (res->end + 1 == next_res->start) {
next_res->start = res->start;
res->flags = res->start = res->end = 0;
}
}
/* Add initial resources to the bus */
resource_list_for_each_entry_safe(window, n, &resources) {
offset = window->offset;
res = window->res;
if (!res->end)
continue;
list_move_tail(&window->node, &bridge->windows);
if (res->flags & IORESOURCE_BUS)
pci_bus_insert_busn_res(bus, bus->number, res->end);
@ -2249,6 +2291,7 @@ static void pci_release_dev(struct device *dev)
pci_bus_put(pci_dev->bus);
kfree(pci_dev->driver_override);
bitmap_free(pci_dev->dma_alias_mask);
dev_dbg(dev, "device released\n");
kfree(pci_dev);
}

View File

@ -27,6 +27,7 @@
#include <linux/nvme.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
#include <linux/switchtec.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
@ -3656,6 +3657,16 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
return;
if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM)
return;
/*
* SXIO/SXFP/SXLF turns off power to the Thunderbolt controller.
* We don't know how to turn it back on again, but firmware does,
* so we can only use SXIO/SXFP/SXLF if we're suspending via
* firmware.
*/
if (!pm_suspend_via_firmware())
return;
bridge = ACPI_HANDLE(&dev->dev);
if (!bridge)
return;

View File

@ -39,19 +39,19 @@ static const struct sysfs_ops pci_slot_sysfs_ops = {
static ssize_t address_read_file(struct pci_slot *slot, char *buf)
{
if (slot->number == 0xff)
return sprintf(buf, "%04x:%02x\n",
pci_domain_nr(slot->bus),
slot->bus->number);
else
return sprintf(buf, "%04x:%02x:%02x\n",
pci_domain_nr(slot->bus),
slot->bus->number,
slot->number);
return sysfs_emit(buf, "%04x:%02x\n",
pci_domain_nr(slot->bus),
slot->bus->number);
return sysfs_emit(buf, "%04x:%02x:%02x\n",
pci_domain_nr(slot->bus),
slot->bus->number,
slot->number);
}
static ssize_t bus_speed_read(enum pci_bus_speed speed, char *buf)
{
return sprintf(buf, "%s\n", pci_speed_string(speed));
return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
}
static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf)

View File

@ -280,7 +280,7 @@ static ssize_t device_version_show(struct device *dev,
ver = ioread32(&stdev->mmio_sys_info->device_version);
return sprintf(buf, "%x\n", ver);
return sysfs_emit(buf, "%x\n", ver);
}
static DEVICE_ATTR_RO(device_version);
@ -292,7 +292,7 @@ static ssize_t fw_version_show(struct device *dev,
ver = ioread32(&stdev->mmio_sys_info->firmware_version);
return sprintf(buf, "%08x\n", ver);
return sysfs_emit(buf, "%08x\n", ver);
}
static DEVICE_ATTR_RO(fw_version);
@ -344,7 +344,7 @@ static ssize_t component_vendor_show(struct device *dev,
/* component_vendor field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
return sprintf(buf, "none\n");
return sysfs_emit(buf, "none\n");
return io_string_show(buf, &si->gen3.component_vendor,
sizeof(si->gen3.component_vendor));
@ -359,9 +359,9 @@ static ssize_t component_id_show(struct device *dev,
/* component_id field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
return sprintf(buf, "none\n");
return sysfs_emit(buf, "none\n");
return sprintf(buf, "PM%04X\n", id);
return sysfs_emit(buf, "PM%04X\n", id);
}
static DEVICE_ATTR_RO(component_id);
@ -373,9 +373,9 @@ static ssize_t component_revision_show(struct device *dev,
/* component_revision field not supported after gen3 */
if (stdev->gen != SWITCHTEC_GEN3)
return sprintf(buf, "255\n");
return sysfs_emit(buf, "255\n");
return sprintf(buf, "%d\n", rev);
return sysfs_emit(buf, "%d\n", rev);
}
static DEVICE_ATTR_RO(component_revision);
@ -384,7 +384,7 @@ static ssize_t partition_show(struct device *dev,
{
struct switchtec_dev *stdev = to_stdev(dev);
return sprintf(buf, "%d\n", stdev->partition);
return sysfs_emit(buf, "%d\n", stdev->partition);
}
static DEVICE_ATTR_RO(partition);
@ -393,7 +393,7 @@ static ssize_t partition_count_show(struct device *dev,
{
struct switchtec_dev *stdev = to_stdev(dev);
return sprintf(buf, "%d\n", stdev->partition_count);
return sysfs_emit(buf, "%d\n", stdev->partition_count);
}
static DEVICE_ATTR_RO(partition_count);

View File

@ -55,6 +55,7 @@ struct pci_ecam_ops {
struct pci_config_window {
struct resource res;
struct resource busr;
unsigned int bus_shift;
void *priv;
const struct pci_ecam_ops *ops;
union {

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/**
/*
* PCI Endpoint ConfigFS header file
*
* Copyright (C) 2017 Texas Instruments

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
/*
* PCI Endpoint *Controller* (EPC) header file
*
* Copyright (C) 2017 Texas Instruments
@ -58,6 +58,7 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
* @map_msi_irq: ops to map physical address to MSI address and return MSI data
* @start: ops to start the PCI link
* @stop: ops to stop the PCI link
* @get_features: ops to get the features supported by the EPC
* @owner: the module owner containing the ops
*/
struct pci_epc_ops {
@ -150,6 +151,8 @@ struct pci_epc {
/**
* struct pci_epc_features - features supported by a EPC device per function
* @linkup_notifier: indicate if the EPC device can notify EPF driver on link up
* @core_init_notifier: indicate cores that can notify about their availability
* for initialization
* @msi_capable: indicate if the endpoint function has MSI capability
* @msix_capable: indicate if the endpoint function has MSI-X capability
* @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/**
/*
* PCI Endpoint *Function* (EPF) header file
*
* Copyright (C) 2017 Texas Instruments
@ -102,6 +102,8 @@ struct pci_epf_driver {
* @phys_addr: physical address that should be mapped to the BAR
* @addr: virtual address corresponding to the @phys_addr
* @size: the size of the address space present in BAR
* @barno: BAR number
* @flags: flags that are set for the BAR
*/
struct pci_epf_bar {
dma_addr_t phys_addr;
@ -118,6 +120,7 @@ struct pci_epf_bar {
* @header: represents standard configuration header
* @bar: represents the BAR of EPF device
* @msi_interrupts: number of MSI interrupts required by this function
* @msix_interrupts: number of MSI-X interrupts required by this function
* @func_no: unique function number within this endpoint device
* @epc: the EPC device to which this EPF device is bound
* @driver: the EPF driver to which this EPF device is bound

View File

@ -497,7 +497,7 @@ struct pci_dev {
u16 pasid_features;
#endif
#ifdef CONFIG_PCI_P2PDMA
struct pci_p2pdma *p2pdma;
struct pci_p2pdma __rcu *p2pdma;
#endif
u16 acs_cap; /* ACS Capability offset */
phys_addr_t rom; /* Physical address if not from BAR */

View File

@ -50,6 +50,8 @@ struct hotplug_slot_ops {
/**
* struct hotplug_slot - used to register a physical slot with the hotplug pci core
* @ops: pointer to the &struct hotplug_slot_ops to be used for this slot
* @slot_list: internal list used to track hotplug PCI slots
* @pci_slot: represents a physical slot
* @owner: The module owner of this structure
* @mod_name: The module name (KBUILD_MODNAME) of this structure
*/

View File

@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/**
/*
* pcitest.h - PCI test uapi defines
*
* Copyright (C) 2017 Texas Instruments