pci-v5.11-changes

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAl/ZJwsUHGJoZWxnYWFz
 QGdvb2dsZS5jb20ACgkQWYigwDrT+vyGGQ//UhNBwb061zUaLWvaDy2RY67tGsED
 kSNucKqrtaJtWaZDL3fmi8e15lwc4J/xWd96X0sd0udddrVto3WBjYd+CfbfhW8M
 rQufCGlaj+VAZEzrwwbo1cTHXGH3g57BZbVlebCxJJ3mycIv716N4bdo0jz5vf9J
 /PotN6yr5bCMWfO9320cmdaFDO2PK5o+AcRxUtkmFD854yJRZvmlxczFhj33pBB1
 LLQlbi+Hr367WpK2uT2E36Z3POXwUqWOxSAs3Q4ql57/3UY1THZPIn5TmgXGqo7F
 Dr3TRlScWxftssFSAmGZat7lBEaDBh9UnHPAsic0cjlUg6+PE7O+2iLZ7XrtPokL
 Z8LVhdVlwLTNTfonsBSlMGFZJjh/zO9u1QtKYQjFhE5tUU3DUDaJz/pdcyjgaGQ1
 RJNMlsHgdg89v7IJeyote+IfIpQs9YcyDxvXbXW8EFf8ft6KprTj1YNcsjRpgmwN
 xhvTX40oDV9HwF3UUzO6xCdvmhmgD0n4m9cRR4kH+KtiImkZJ4tMh50AQnIs2wag
 I1N2XRld7dqVGWLu4TYkmzxVgjJ9n8ylIRpHy9aMAR9TN+Q/ovLYxJvQkR4NYvxX
 hft3YLgpF1ZKlyflvHmmKszLqdlPX5e56UQl3/VSRD3IQGe1+HzWOhrssWkPnNSc
 0P8b7YpJU4WnVzQ=
 =xRTv
 -----END PGP SIGNATURE-----

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

Pull PCI updates from Bjorn Helgaas:
 "Enumeration:
   - Decode PCIe 64 GT/s link speed (Gustavo Pimentel)
   - Remove unused HAVE_PCI_SET_MWI (Heiner Kallweit)
   - Reduce pci_set_cacheline_size() message to debug level (Heiner
     Kallweit)
   - Fix pci_slot_release() NULL pointer dereference (Jubin Zhong)
   - Unify ECAM constants in native PCI Express drivers (Krzysztof
     Wilczyński)
   - Return u8 from pci_find_capability() and similar (Puranjay Mohan)
   - Return u16 from pci_find_ext_capability() and similar (Bjorn
     Helgaas)
   - Fix ACPI companion lookup for device 0 on the root bus (Rafael J.
     Wysocki)

  Resource management:
   - Keep both device and resource name for config space remaps
     (Alexander Lobakin)
   - Bounds-check command-line resource alignment requests (Bjorn
     Helgaas)
   - Fix overflow in command-line resource alignment requests (Colin Ian
     King)

  Driver binding:
   - Avoid duplicate IDs in driver dynamic IDs list (Zhenzhong Duan)

  Power management:
   - Save/restore Precision Time Measurement Capability for
     suspend/resume (David E. Box)
   - Disable PTM during suspend to save power (David E. Box)
   - Add sysfs attribute for device power state (Maximilian Luz)
   - Rename pci_wakeup_bus() to pci_resume_bus() (Mika Westerberg)
   - Do not generate wakeup event when runtime resuming device (Mika
     Westerberg)
   - Save/restore ASPM L1SS Capability for suspend/resume (Vidya Sagar)

  Virtualization:
   - Mark AMD Raven iGPU ATS as broken in some platforms (Alex Deucher)
   - Add function 1 DMA alias quirk for Marvell 9215 SATA controller
     (Bjorn Helgaas)

  MSI:
   - Disable MSI for Pericom PCIe-USB adapter (Andy Shevchenko)
   - Improve warnings for 32-bit-limited MSI support (Vidya Sagar)

  Error handling:
   - Cache RCEC EA Capability offset in pci_init_capabilities() (Sean V
     Kelley)
   - Rename reset_link() to reset_subordinates() (Sean V Kelley)
   - Write AER Capability only when we control it (Sean V Kelley)
   - Clear AER status only when we control AER (Sean V Kelley)
   - Bind RCEC devices to the Root Port driver (Qiuxu Zhuo)
   - Recover from RCiEP AER errors (Qiuxu Zhuo)
   - Recover from RCEC AER errors (Sean V Kelley)
   - Add pcie_link_rcec() to associate RCiEPs (Sean V Kelley)
   - Add pcie_walk_rcec() to RCEC AER handling (Sean V Kelley)
   - Add pcie_walk_rcec() to RCEC PME handling (Sean V Kelley)
   - Add RCEC AER error injection support (Qiuxu Zhuo)

  Broadcom iProc PCIe controller driver:
   - Fix out-of-bound array accesses (Bharat Gooty)
   - Invalidate correct PAXB inbound windows (Roman Bacik)
   - Enhance PCIe Link information display (Srinath Mannam)

  Cadence PCIe controller driver:
   - Make "cdns,max-outbound-regions" property optional (Kishon Vijay
     Abraham I)

  Intel VMD host bridge driver:
   - Offset client MSI-X vectors (Jon Derrick)
   - Update type of __iomem pointers (Krzysztof Wilczyński)

  NVIDIA Tegra PCIe controller driver:
   - Move "dbi" accesses to post common DWC initialization (Vidya Sagar)
   - Read "dbi" base address to program in application logic (Vidya
     Sagar)
   - Fix ASPM-L1SS advertisement disable code (Vidya Sagar)
   - Set DesignWare IP version (Vidya Sagar)
   - Continue unconfig sequence even if parts fail (Vidya Sagar)
   - Check return value of tegra_pcie_init_controller() (Vidya Sagar)
   - Disable LTSSM during L2 entry (Vidya Sagar)

  Qualcomm PCIe controller driver:
   - Document PCIe bindings for SM8250 SoC (Manivannan Sadhasivam)
   - Add SM8250 SoC support (Manivannan Sadhasivam)
   - Add support for configuring BDF to SID mapping for SM8250
     (Manivannan Sadhasivam)

  Renesas R-Car PCIe controller driver:
   - rcar: Drop unused members from struct rcar_pcie_host (Lad
     Prabhakar)
   - PCI: rcar-pci-host: Document r8a774e1 bindings (Lad Prabhakar)
   - PCI: rcar-pci-host: Convert bindings to json-schema (Yoshihiro
     Shimoda)
   - PCI: rcar-pci-host: Document r8a77965 bindings (Yoshihiro Shimoda)

  Samsung Exynos PCIe controller driver:
   - Rework driver to support Exynos5433 PCIe PHY (Jaehoon Chung)
   - Rework driver to support Exynos5433 variant (Jaehoon Chung)
   - Drop samsung,exynos5440-pcie binding (Marek Szyprowski)
   - Add the samsung,exynos-pcie binding (Marek Szyprowski)
   - Add the samsung,exynos-pcie-phy binding (Marek Szyprowski)

  Synopsys DesignWare PCIe controller driver:
   - Support multiple ATU memory regions (Rob Herring)
   - Move intel-gw ATU offset out of driver match data (Rob Herring)
   - Move "dbi", "dbi2", and "addr_space" resource setup into common
     code (Rob Herring)
   - Remove intel-gw unneeded function wrappers (Rob Herring)
   - Ensure all outbound ATU windows are reset (Rob Herring)
   - Use the common MSI irq_chip in dra7xx (Rob Herring)
   - Drop the .set_num_vectors() host op (Rob Herring)
   - Move MSI interrupt setup into DWC common code (Rob Herring)
   - Rework MSI initialization (Rob Herring)
   - Move link handling into common code (Rob Herring)
   - Move dw_pcie_msi_init() into core (Rob Herring)
   - Move dw_pcie_setup_rc() to DWC common code (Rob Herring)
   - Remove unnecessary wrappers around dw_pcie_host_init() (Rob
     Herring)
   - Drop keystone duplicated 'num-viewport'" (Rob Herring)
   - Move inbound and outbound windows to common struct (Rob Herring)
   - Detect number of iATU windows (Rob Herring)
   - Warn if non-prefetchable memory aperture size is > 32-bit (Vidya
     Sagar)
   - Add support to program ATU for >4GB memory (Vidya Sagar)
   - Set 32-bit DMA mask for MSI target address allocation (Vidya Sagar)

  TI J721E PCIe driver:
   - Fix "ti,syscon-pcie-ctrl" to take argument (Kishon Vijay Abraham I)
   - Add host mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham
     I)
   - Add EP mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham I)
   - Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg
     (Kishon Vijay Abraham I)

  TI Keystone PCIe controller driver:
   - Enable compile-testing on !ARM (Alex Dewar)"

* tag 'pci-v5.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (100 commits)
  PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller
  PCI/ACPI: Fix companion lookup for device 0 on the root bus
  PCI: Keep both device and resource name for config space remaps
  PCI: xgene: Removed unused ".bus_shift" initialisers from pci-xgene.c
  PCI: vmd: Update type of the __iomem pointers
  PCI: iproc: Convert to use the new ECAM constants
  PCI: thunder-pem: Add constant for custom ".bus_shift" initialiser
  PCI: Unify ECAM constants in native PCI Express drivers
  PCI: Disable PTM during suspend to save power
  PCI/PTM: Save/restore Precision Time Measurement Capability for suspend/resume
  PCI: Mark AMD Raven iGPU ATS as broken in some platforms
  PCI: j721e: Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg
  dt-bindings: PCI: Add EP mode dt-bindings for TI's J7200 SoC
  dt-bindings: PCI: Add host mode dt-bindings for TI's J7200 SoC
  dt-bindings: pci: ti,j721e: Fix "ti,syscon-pcie-ctrl" to take argument
  PCI: dwc: Set 32-bit DMA mask for MSI target address allocation
  PCI: qcom: Add support for configuring BDF to SID mapping for SM8250
  PCI: Reduce pci_set_cacheline_size() message to debug level
  PCI: Remove unused HAVE_PCI_SET_MWI
  PCI: qcom: Add SM8250 SoC support
  ...
This commit is contained in:
Linus Torvalds 2020-12-15 16:49:59 -08:00
commit 489e9fea66
82 changed files with 2027 additions and 1866 deletions

View File

@ -366,3 +366,12 @@ Contact: Heiner Kallweit <hkallweit1@gmail.com>
Description: If ASPM is supported for an endpoint, these files can be
used to disable or enable the individual power management
states. Write y/1/on to enable, n/0/off to disable.
What: /sys/bus/pci/devices/.../power_state
Date: November 2020
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
Description:
This file contains the current PCI power state of the device.
The value comes from the PCI kernel device state and can be one
of: "unknown", "error", "D0", D1", "D2", "D3hot", "D3cold".
The file is read only.

View File

@ -20,7 +20,4 @@ properties:
maximum: 32
default: 32
required:
- cdns,max-outbound-regions
additionalProperties: true

View File

@ -13,6 +13,7 @@
- "qcom,pcie-ipq8074" for ipq8074
- "qcom,pcie-qcs404" for qcs404
- "qcom,pcie-sdm845" for sdm845
- "qcom,pcie-sm8250" for sm8250
- reg:
Usage: required
@ -27,6 +28,7 @@
- "dbi" DesignWare PCIe registers
- "elbi" External local bus interface registers
- "config" PCIe configuration space
- "atu" ATU address space (optional)
- device_type:
Usage: required
@ -131,7 +133,7 @@
- "slave_bus" AXI Slave clock
-clock-names:
Usage: required for sdm845
Usage: required for sdm845 and sm8250
Value type: <stringlist>
Definition: Should contain the following entries
- "aux" Auxiliary clock
@ -206,7 +208,7 @@
- "ahb" AHB reset
- reset-names:
Usage: required for sdm845
Usage: required for sdm845 and sm8250
Value type: <stringlist>
Definition: Should contain the following entries
- "pci" PCIe core reset

View File

@ -0,0 +1,115 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 Renesas Electronics Corp.
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/rcar-pci-host.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car PCIe Host
maintainers:
- Marek Vasut <marek.vasut+renesas@gmail.com>
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
allOf:
- $ref: pci-bus.yaml#
properties:
compatible:
oneOf:
- items:
- enum:
- renesas,pcie-r8a7742 # RZ/G1H
- renesas,pcie-r8a7743 # RZ/G1M
- renesas,pcie-r8a7744 # RZ/G1N
- renesas,pcie-r8a7790 # R-Car H2
- renesas,pcie-r8a7791 # R-Car M2-W
- renesas,pcie-r8a7793 # R-Car M2-N
- const: renesas,pcie-rcar-gen2 # R-Car Gen2 and RZ/G1
- items:
- enum:
- renesas,pcie-r8a774a1 # RZ/G2M
- renesas,pcie-r8a774b1 # RZ/G2N
- renesas,pcie-r8a774c0 # RZ/G2E
- renesas,pcie-r8a774e1 # RZ/G2H
- renesas,pcie-r8a7795 # R-Car H3
- renesas,pcie-r8a7796 # R-Car M3-W
- renesas,pcie-r8a77961 # R-Car M3-W+
- renesas,pcie-r8a77965 # R-Car M3-N
- renesas,pcie-r8a77980 # R-Car V3H
- renesas,pcie-r8a77990 # R-Car E3
- const: renesas,pcie-rcar-gen3 # R-Car Gen3 and RZ/G2
reg:
maxItems: 1
interrupts:
minItems: 3
maxItems: 3
clocks:
maxItems: 2
clock-names:
items:
- const: pcie
- const: pcie_bus
power-domains:
maxItems: 1
resets:
maxItems: 1
phys:
maxItems: 1
phy-names:
const: pcie
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
- resets
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7791-sysc.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie: pcie@fe000000 {
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
reg = <0 0xfe000000 0 0x80000>;
#address-cells = <3>;
#size-cells = <2>;
bus-range = <0x00 0xff>;
device_type = "pci";
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>,
<0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>,
<0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>,
<0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>,
<0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
clock-names = "pcie", "pcie_bus";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 319>;
};
};

View File

@ -1,72 +0,0 @@
* Renesas R-Car PCIe interface
Required properties:
compatible: "renesas,pcie-r8a7742" for the R8A7742 SoC;
"renesas,pcie-r8a7743" for the R8A7743 SoC;
"renesas,pcie-r8a7744" for the R8A7744 SoC;
"renesas,pcie-r8a774a1" for the R8A774A1 SoC;
"renesas,pcie-r8a774b1" for the R8A774B1 SoC;
"renesas,pcie-r8a774c0" for the R8A774C0 SoC;
"renesas,pcie-r8a7779" for the R8A7779 SoC;
"renesas,pcie-r8a7790" for the R8A7790 SoC;
"renesas,pcie-r8a7791" for the R8A7791 SoC;
"renesas,pcie-r8a7793" for the R8A7793 SoC;
"renesas,pcie-r8a7795" for the R8A7795 SoC;
"renesas,pcie-r8a7796" for the R8A77960 SoC;
"renesas,pcie-r8a77961" for the R8A77961 SoC;
"renesas,pcie-r8a77980" for the R8A77980 SoC;
"renesas,pcie-r8a77990" for the R8A77990 SoC;
"renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or
RZ/G1 compatible device.
"renesas,pcie-rcar-gen3" for a generic R-Car Gen3 or
RZ/G2 compatible device.
When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first
followed by the generic version.
- reg: base address and length of the PCIe controller registers.
- #address-cells: set to <3>
- #size-cells: set to <2>
- bus-range: PCI bus numbers covered
- device_type: set to "pci"
- ranges: ranges for the PCI memory and I/O regions.
- dma-ranges: ranges for the inbound memory regions.
- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
source for hardware related interrupts (e.g. link speed change).
- #interrupt-cells: set to <1>
- interrupt-map-mask and interrupt-map: standard PCI properties
to define the mapping of the PCIe interface to interrupt numbers.
- clocks: from common clock binding: clock specifiers for the PCIe controller
and PCIe bus clocks.
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
Optional properties:
- phys: from common PHY binding: PHY phandle and specifier (only make sense
for R-Car gen3 SoCs where the PCIe PHYs have their own register blocks).
- phy-names: from common PHY binding: should be "pcie".
Example:
SoC-specific DT Entry:
pcie: pcie@fe000000 {
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
reg = <0 0xfe000000 0 0x80000>;
#address-cells = <3>;
#size-cells = <2>;
bus-range = <0x00 0xff>;
device_type = "pci";
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
interrupts = <0 116 4>, <0 117 4>, <0 118 4>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic 0 116 4>;
clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
clock-names = "pcie", "pcie_bus";
};

View File

@ -0,0 +1,119 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/samsung,exynos-pcie.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series PCIe Host Controller Device Tree Bindings
maintainers:
- Marek Szyprowski <m.szyprowski@samsung.com>
- Jaehoon Chung <jh80.chung@samsung.com>
description: |+
Exynos5433 SoC PCIe host controller is based on the Synopsys DesignWare
PCIe IP and thus inherits all the common properties defined in
designware-pcie.txt.
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
properties:
compatible:
const: samsung,exynos5433-pcie
reg:
items:
- description: Data Bus Interface (DBI) registers.
- description: External Local Bus interface (ELBI) registers.
- description: PCIe configuration space region.
reg-names:
items:
- const: dbi
- const: elbi
- const: config
interrupts:
maxItems: 1
clocks:
items:
- description: PCIe bridge clock
- description: PCIe bus clock
clock-names:
items:
- const: pcie
- const: pcie_bus
phys:
maxItems: 1
vdd10-supply:
description:
Phandle to a regulator that provides 1.0V power to the PCIe block.
vdd18-supply:
description:
Phandle to a regulator that provides 1.8V power to the PCIe block.
num-lanes:
const: 1
num-viewport:
const: 3
required:
- reg
- reg-names
- interrupts
- "#address-cells"
- "#size-cells"
- "#interrupt-cells"
- interrupt-map
- interrupt-map-mask
- ranges
- bus-range
- device_type
- num-lanes
- num-viewport
- clocks
- clock-names
- phys
- vdd10-supply
- vdd18-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/exynos5433.h>
pcie: pcie@15700000 {
compatible = "samsung,exynos5433-pcie";
reg = <0x15700000 0x1000>, <0x156b0000 0x1000>, <0x0c000000 0x1000>;
reg-names = "dbi", "elbi", "config";
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cmu_fsys CLK_PCIE>, <&cmu_fsys CLK_PCLK_PCIE_PHY>;
clock-names = "pcie", "pcie_bus";
phys = <&pcie_phy>;
pinctrl-0 = <&pcie_bus &pcie_wlanen>;
pinctrl-names = "default";
num-lanes = <1>;
num-viewport = <3>;
bus-range = <0x00 0xff>;
ranges = <0x81000000 0 0 0x0c001000 0 0x00010000>,
<0x82000000 0 0x0c011000 0x0c011000 0 0x03feefff>;
vdd10-supply = <&ldo6_reg>;
vdd18-supply = <&ldo7_reg>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
};
...

View File

@ -1,58 +0,0 @@
* Samsung Exynos 5440 PCIe interface
This PCIe host controller is based on the Synopsys DesignWare PCIe IP
and thus inherits all the common properties defined in designware-pcie.txt.
Required properties:
- compatible: "samsung,exynos5440-pcie"
- reg: base addresses and lengths of the PCIe controller,
- reg-names : First name should be set to "elbi".
And use the "config" instead of getting the configuration address space
from "ranges".
NOTE: When using the "config" property, reg-names must be set.
- interrupts: A list of interrupt outputs for level interrupt,
pulse interrupt, special interrupt.
- phys: From PHY binding. Phandle for the generic PHY.
Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt
For other common properties, refer to
Documentation/devicetree/bindings/pci/designware-pcie.txt
Example:
SoC-specific DT Entry (with using PHY framework):
pcie_phy0: pcie-phy@270000 {
...
reg = <0x270000 0x1000>, <0x271000 0x40>;
reg-names = "phy", "block";
...
};
pcie@290000 {
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
reg = <0x290000 0x1000>, <0x40000000 0x1000>;
reg-names = "elbi", "config";
clocks = <&clock 28>, <&clock 27>;
clock-names = "pcie", "pcie_bus";
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
phys = <&pcie_phy0>;
ranges = <0x81000000 0 0 0x60001000 0 0x00010000
0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
num-lanes = <4>;
};
Board-specific DT Entry:
pcie@290000 {
reset-gpio = <&pin_ctrl 5 0>;
};
pcie@2a0000 {
reset-gpio = <&pin_ctrl 22 0>;
};

View File

@ -15,8 +15,14 @@ allOf:
properties:
compatible:
enum:
- ti,j721e-pcie-ep
oneOf:
- description: PCIe EP controller in J7200
items:
- const: ti,j7200-pcie-ep
- const: ti,j721e-pcie-ep
- description: PCIe EP controller in J721E
items:
- const: ti,j721e-pcie-ep
reg:
maxItems: 4
@ -29,9 +35,12 @@ properties:
- const: mem
ti,syscon-pcie-ctrl:
description: Phandle to the SYSCON entry required for configuring PCIe mode
and link speed.
$ref: /schemas/types.yaml#/definitions/phandle
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle to the SYSCON entry
- description: pcie_ctrl register offset within SYSCON
description: Specifier for configuring PCIe mode and link speed.
power-domains:
maxItems: 1
@ -57,7 +66,6 @@ required:
- power-domains
- clocks
- clock-names
- cdns,max-outbound-regions
- dma-coherent
- max-functions
- phys
@ -80,13 +88,12 @@ examples:
<0x00 0x0d000000 0x00 0x00800000>,
<0x00 0x10000000 0x00 0x08000000>;
reg-names = "intd_cfg", "user_cfg", "reg", "mem";
ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
max-link-speed = <3>;
num-lanes = <2>;
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
clocks = <&k3_clks 239 1>;
clock-names = "fck";
cdns,max-outbound-regions = <16>;
max-functions = /bits/ 8 <6>;
dma-coherent;
phys = <&serdes0_pcie_link>;

View File

@ -15,8 +15,14 @@ allOf:
properties:
compatible:
enum:
- ti,j721e-pcie-host
oneOf:
- description: PCIe controller in J7200
items:
- const: ti,j7200-pcie-host
- const: ti,j721e-pcie-host
- description: PCIe controller in J721E
items:
- const: ti,j721e-pcie-host
reg:
maxItems: 4
@ -29,9 +35,12 @@ properties:
- const: cfg
ti,syscon-pcie-ctrl:
description: Phandle to the SYSCON entry required for configuring PCIe mode
and link speed.
$ref: /schemas/types.yaml#/definitions/phandle
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle to the SYSCON entry
- description: pcie_ctrl register offset within SYSCON
description: Specifier for configuring PCIe mode and link speed.
power-domains:
maxItems: 1
@ -48,7 +57,11 @@ properties:
const: 0x104c
device-id:
const: 0xb00d
oneOf:
- items:
- const: 0xb00d
- items:
- const: 0xb00f
msi-map: true
@ -90,7 +103,7 @@ examples:
<0x00 0x0d000000 0x00 0x00800000>,
<0x00 0x10000000 0x00 0x00001000>;
reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
max-link-speed = <3>;
num-lanes = <2>;
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/samsung,exynos-pcie-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series PCIe PHY Device Tree Bindings
maintainers:
- Marek Szyprowski <m.szyprowski@samsung.com>
- Jaehoon Chung <jh80.chung@samsung.com>
properties:
"#phy-cells":
const: 0
compatible:
const: samsung,exynos5433-pcie-phy
reg:
maxItems: 1
samsung,pmu-syscon:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for PMU system controller interface, used to
control PMU registers bits for PCIe PHY
samsung,fsys-sysreg:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for FSYS sysreg interface, used to control
sysreg registers bits for PCIe PHY
required:
- "#phy-cells"
- compatible
- reg
- samsung,pmu-syscon
- samsung,fsys-sysreg
additionalProperties: false
examples:
- |
pcie_phy: pcie-phy@15680000 {
compatible = "samsung,exynos5433-pcie-phy";
reg = <0x15680000 0x1000>;
samsung,pmu-syscon = <&pmu_system_controller>;
samsung,fsys-sysreg = <&syscon_fsys>;
#phy-cells = <0>;
};
...

View File

@ -13656,6 +13656,8 @@ M: Kishon Vijay Abraham I <kishon@ti.com>
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/PCI/endpoint/*
F: Documentation/misc-devices/pci-endpoint-test.rst
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
F: drivers/misc/pci_endpoint_test.c
F: drivers/pci/endpoint/

View File

@ -1038,7 +1038,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
mutex_lock(&vgasr_mutex);
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
mutex_unlock(&vgasr_mutex);
pci_wakeup_bus(pdev->bus);
pci_resume_bus(pdev->bus);
return dev->bus->pm->runtime_resume(dev);
}

View File

@ -5,7 +5,7 @@
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
remove.o pci.o pci-driver.o search.o \
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
setup-bus.o vc.o mmap.o setup-irq.o
setup-bus.o vc.o mmap.o setup-irq.o msi.o
obj-$(CONFIG_PCI) += pcie/
@ -18,7 +18,6 @@ endif
obj-$(CONFIG_OF) += of.o
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o
obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o

View File

@ -12,6 +12,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
@ -153,7 +154,8 @@ static const struct cdns_pcie_ops j721e_pcie_ops = {
.link_up = j721e_pcie_link_up,
};
static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon,
unsigned int offset)
{
struct device *dev = pcie->dev;
u32 mask = J721E_MODE_RC;
@ -164,7 +166,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
if (mode == PCI_MODE_RC)
val = J721E_MODE_RC;
ret = regmap_update_bits(syscon, 0, mask, val);
ret = regmap_update_bits(syscon, offset, mask, val);
if (ret)
dev_err(dev, "failed to set pcie mode\n");
@ -172,7 +174,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
}
static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
struct regmap *syscon)
struct regmap *syscon, unsigned int offset)
{
struct device *dev = pcie->dev;
struct device_node *np = dev->of_node;
@ -185,7 +187,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
link_speed = 2;
val = link_speed - 1;
ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
ret = regmap_update_bits(syscon, offset, GENERATION_SEL_MASK, val);
if (ret)
dev_err(dev, "failed to set link speed\n");
@ -193,7 +195,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
}
static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
struct regmap *syscon)
struct regmap *syscon, unsigned int offset)
{
struct device *dev = pcie->dev;
u32 lanes = pcie->num_lanes;
@ -201,7 +203,7 @@ static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
int ret;
val = LANE_COUNT(lanes - 1);
ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
ret = regmap_update_bits(syscon, offset, LANE_COUNT_MASK, val);
if (ret)
dev_err(dev, "failed to set link count\n");
@ -212,6 +214,8 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
{
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node;
struct of_phandle_args args;
unsigned int offset = 0;
struct regmap *syscon;
int ret;
@ -221,19 +225,25 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
return PTR_ERR(syscon);
}
ret = j721e_pcie_set_mode(pcie, syscon);
/* Do not error out to maintain old DT compatibility */
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-pcie-ctrl", 1,
0, &args);
if (!ret)
offset = args.args[0];
ret = j721e_pcie_set_mode(pcie, syscon, offset);
if (ret < 0) {
dev_err(dev, "Failed to set pci mode\n");
return ret;
}
ret = j721e_pcie_set_link_speed(pcie, syscon);
ret = j721e_pcie_set_link_speed(pcie, syscon, offset);
if (ret < 0) {
dev_err(dev, "Failed to set link speed\n");
return ret;
}
ret = j721e_pcie_set_lane_count(pcie, syscon);
ret = j721e_pcie_set_lane_count(pcie, syscon, offset);
if (ret < 0) {
dev_err(dev, "Failed to set num-lanes\n");
return ret;

View File

@ -530,12 +530,9 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
}
pcie->mem_res = res;
ret = of_property_read_u32(np, "cdns,max-outbound-regions",
&ep->max_regions);
if (ret < 0) {
dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
return ret;
}
ep->max_regions = CDNS_PCIE_MAX_OB;
of_property_read_u32(np, "cdns,max-outbound-regions", &ep->max_regions);
ep->ob_addr = devm_kcalloc(dev,
ep->max_regions, sizeof(*ep->ob_addr),
GFP_KERNEL);

View File

@ -197,6 +197,7 @@ enum cdns_pcie_rp_bar {
};
#define CDNS_PCIE_RP_MAX_IB 0x3
#define CDNS_PCIE_MAX_OB 32
struct cdns_pcie_rp_ib_bar {
u64 size;

View File

@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP
selected.
config PCI_EXYNOS
bool "Samsung Exynos PCIe controller"
depends on SOC_EXYNOS5440 || COMPILE_TEST
tristate "Samsung Exynos PCIe controller"
depends on ARCH_EXYNOS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
help
Enables support for the PCIe controller in the Samsung Exynos SoCs
to work in host mode. The PCI controller is based on the DesignWare
hardware and therefore the driver re-uses the DesignWare core
functions to implement the driver.
config PCI_IMX6
bool "Freescale i.MX6/7/8 PCIe controller"
@ -107,7 +112,7 @@ config PCI_KEYSTONE
config PCI_KEYSTONE_HOST
bool "PCI Keystone Host Mode"
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
select PCI_KEYSTONE
@ -119,7 +124,7 @@ config PCI_KEYSTONE_HOST
config PCI_KEYSTONE_EP
bool "PCI Keystone Endpoint Mode"
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
depends on PCI_ENDPOINT
select PCIE_DW_EP
select PCI_KEYSTONE
@ -169,6 +174,7 @@ config PCIE_QCOM
depends on OF && (ARCH_QCOM || COMPILE_TEST)
depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST
select CRC8
help
Say Y here to enable PCIe controller support on Qualcomm SoCs. The
PCIe controller uses the DesignWare core plus Qualcomm-specific

View File

@ -181,11 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
dw_pcie_setup_rc(pp);
dra7xx_pcie_establish_link(pci);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
dra7xx_pcie_enable_interrupts(dra7xx);
return 0;
@ -377,133 +372,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
return 0;
}
static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target;
msi_target = (u64)pp->msi_data;
msg->address_lo = lower_32_bits(msi_target);
msg->address_hi = upper_32_bits(msi_target);
msg->data = d->hwirq;
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
(int)d->hwirq, msg->address_hi, msg->address_lo);
}
static int dra7xx_pcie_msi_set_affinity(struct irq_data *d,
const struct cpumask *mask,
bool force)
{
return -EINVAL;
}
static void dra7xx_pcie_bottom_mask(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags);
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] |= BIT(bit);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void dra7xx_pcie_bottom_unmask(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags);
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
pp->irq_mask[ctrl] &= ~BIT(bit);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
pp->irq_mask[ctrl]);
raw_spin_unlock_irqrestore(&pp->lock, flags);
}
static void dra7xx_pcie_bottom_ack(struct irq_data *d)
{
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
unsigned int res, bit, ctrl;
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
}
static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
.name = "DRA7XX-PCI-MSI",
.irq_ack = dra7xx_pcie_bottom_ack,
.irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg,
.irq_set_affinity = dra7xx_pcie_msi_set_affinity,
.irq_mask = dra7xx_pcie_bottom_mask,
.irq_unmask = dra7xx_pcie_bottom_unmask,
};
static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
u32 ctrl, num_ctrls;
int ret;
pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
/* Initialize IRQ Status array */
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
pp->irq_mask[ctrl] = ~0;
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
pp->irq_mask[ctrl]);
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
~0);
}
ret = dw_pcie_allocate_domains(pp);
if (ret)
return ret;
pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
sizeof(pp->msi_msg),
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
ret = dma_mapping_error(dev, pp->msi_data);
if (ret) {
dev_err(dev, "Failed to map MSI data\n");
pp->msi_data = 0;
dw_pcie_free_msi(pp);
}
return ret;
}
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
.host_init = dra7xx_pcie_host_init,
.msi_host_init = dra7xx_pcie_msi_host_init,
};
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
@ -578,7 +448,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = dra7xx->pci;
@ -594,13 +463,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
@ -622,6 +484,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
if (pp->irq < 0)
return pp->irq;
/* MSI IRQ is muxed */
pp->msi_irq = -ENODEV;
ret = dra7xx_pcie_init_irq_domain(pp);
if (ret < 0)
return ret;

View File

@ -2,26 +2,23 @@
/*
* PCIe host controller driver for Samsung Exynos SoCs
*
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
* Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
* https://www.samsung.com
*
* Author: Jingoo Han <jg1.han@samsung.com>
* Jaehoon Chung <jh80.chung@samsung.com>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/regulator/consumer.h>
#include "pcie-designware.h"
@ -37,102 +34,43 @@
#define PCIE_IRQ_SPECIAL 0x008
#define PCIE_IRQ_EN_PULSE 0x00c
#define PCIE_IRQ_EN_LEVEL 0x010
#define IRQ_MSI_ENABLE BIT(2)
#define PCIE_IRQ_EN_SPECIAL 0x014
#define PCIE_PWR_RESET 0x018
#define PCIE_SW_WAKE 0x018
#define PCIE_BUS_EN BIT(1)
#define PCIE_CORE_RESET 0x01c
#define PCIE_CORE_RESET_ENABLE BIT(0)
#define PCIE_STICKY_RESET 0x020
#define PCIE_NONSTICKY_RESET 0x024
#define PCIE_APP_INIT_RESET 0x028
#define PCIE_APP_LTSSM_ENABLE 0x02c
#define PCIE_ELBI_RDLH_LINKUP 0x064
#define PCIE_ELBI_RDLH_LINKUP 0x074
#define PCIE_ELBI_XMLH_LINKUP BIT(4)
#define PCIE_ELBI_LTSSM_ENABLE 0x1
#define PCIE_ELBI_SLV_AWMISC 0x11c
#define PCIE_ELBI_SLV_ARMISC 0x120
#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
struct exynos_pcie_mem_res {
void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
};
struct exynos_pcie_clk_res {
struct clk *clk;
struct clk *bus_clk;
};
struct exynos_pcie {
struct dw_pcie *pci;
struct exynos_pcie_mem_res *mem_res;
struct exynos_pcie_clk_res *clk_res;
const struct exynos_pcie_ops *ops;
int reset_gpio;
struct dw_pcie pci;
void __iomem *elbi_base;
struct clk *clk;
struct clk *bus_clk;
struct phy *phy;
struct regulator_bulk_data supplies[2];
};
struct exynos_pcie_ops {
int (*get_mem_resources)(struct platform_device *pdev,
struct exynos_pcie *ep);
int (*get_clk_resources)(struct exynos_pcie *ep);
int (*init_clk_resources)(struct exynos_pcie *ep);
void (*deinit_clk_resources)(struct exynos_pcie *ep);
};
static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
struct exynos_pcie *ep)
static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
if (!ep->mem_res)
return -ENOMEM;
ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ep->mem_res->elbi_base))
return PTR_ERR(ep->mem_res->elbi_base);
return 0;
}
static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
if (!ep->clk_res)
return -ENOMEM;
ep->clk_res->clk = devm_clk_get(dev, "pcie");
if (IS_ERR(ep->clk_res->clk)) {
dev_err(dev, "Failed to get pcie rc clock\n");
return PTR_ERR(ep->clk_res->clk);
}
ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
if (IS_ERR(ep->clk_res->bus_clk)) {
dev_err(dev, "Failed to get pcie bus clock\n");
return PTR_ERR(ep->clk_res->bus_clk);
}
return 0;
}
static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
struct device *dev = ep->pci.dev;
int ret;
ret = clk_prepare_enable(ep->clk_res->clk);
ret = clk_prepare_enable(ep->clk);
if (ret) {
dev_err(dev, "cannot enable pcie rc clock");
return ret;
}
ret = clk_prepare_enable(ep->clk_res->bus_clk);
ret = clk_prepare_enable(ep->bus_clk);
if (ret) {
dev_err(dev, "cannot enable pcie bus clock");
goto err_bus_clk;
@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
return 0;
err_bus_clk:
clk_disable_unprepare(ep->clk_res->clk);
clk_disable_unprepare(ep->clk);
return ret;
}
static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
{
clk_disable_unprepare(ep->clk_res->bus_clk);
clk_disable_unprepare(ep->clk_res->clk);
clk_disable_unprepare(ep->bus_clk);
clk_disable_unprepare(ep->clk);
}
static const struct exynos_pcie_ops exynos5440_pcie_ops = {
.get_mem_resources = exynos5440_pcie_get_mem_resources,
.get_clk_resources = exynos5440_pcie_get_clk_resources,
.init_clk_resources = exynos5440_pcie_init_clk_resources,
.deinit_clk_resources = exynos5440_pcie_deinit_clk_resources,
};
static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
{
writel(val, base + reg);
@ -173,115 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
{
u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE;
else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
}
static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
{
u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
if (on)
val |= PCIE_ELBI_SLV_DBI_ENABLE;
else
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
}
static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
{
u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val &= ~PCIE_CORE_RESET_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
}
static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
{
u32 val;
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
val |= PCIE_CORE_RESET_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
}
static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
static int exynos_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = ep->pci;
struct device *dev = pci->dev;
struct exynos_pcie *ep = to_exynos_pcie(pci);
u32 val;
if (ep->reset_gpio >= 0)
devm_gpio_request_one(dev, ep->reset_gpio,
GPIOF_OUT_INIT_HIGH, "RESET");
}
static int exynos_pcie_establish_link(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
if (dw_pcie_link_up(pci)) {
dev_err(dev, "Link already up\n");
return 0;
}
exynos_pcie_assert_core_reset(ep);
phy_reset(ep->phy);
exynos_pcie_writel(ep->mem_res->elbi_base, 1,
PCIE_PWR_RESET);
phy_power_on(ep->phy);
phy_init(ep->phy);
exynos_pcie_deassert_core_reset(ep);
dw_pcie_setup_rc(pp);
exynos_pcie_assert_reset(ep);
val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
val &= ~PCIE_BUS_EN;
exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
/* assert LTSSM enable */
exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */
if (!dw_pcie_wait_for_link(pci))
return 0;
phy_power_off(ep->phy);
return -ETIMEDOUT;
return 0;
}
static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
{
u32 val;
u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
}
static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
{
u32 val;
/* enable INTX interrupt */
val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
}
static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
@ -292,26 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
static void exynos_pcie_msi_init(struct exynos_pcie *ep)
static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
{
struct dw_pcie *pci = ep->pci;
struct pcie_port *pp = &pci->pp;
u32 val;
u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
dw_pcie_msi_init(pp);
/* enable MSI interrupt */
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
val |= IRQ_MSI_ENABLE;
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
}
static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep)
{
exynos_pcie_enable_irq_pulse(ep);
if (IS_ENABLED(CONFIG_PCI_MSI))
exynos_pcie_msi_init(ep);
exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
}
static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
@ -370,13 +245,9 @@ static struct pci_ops exynos_pci_ops = {
static int exynos_pcie_link_up(struct dw_pcie *pci)
{
struct exynos_pcie *ep = to_exynos_pcie(pci);
u32 val;
u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP);
if (val == PCIE_ELBI_LTSSM_ENABLE)
return 1;
return 0;
return (val & PCIE_ELBI_XMLH_LINKUP);
}
static int exynos_pcie_host_init(struct pcie_port *pp)
@ -386,8 +257,14 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
pp->bridge->ops = &exynos_pci_ops;
exynos_pcie_establish_link(ep);
exynos_pcie_enable_interrupts(ep);
exynos_pcie_assert_core_reset(ep);
phy_reset(ep->phy);
phy_power_on(ep->phy);
phy_init(ep->phy);
exynos_pcie_deassert_core_reset(ep);
exynos_pcie_enable_irq_pulse(ep);
return 0;
}
@ -396,32 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
.host_init = exynos_pcie_host_init,
};
static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
static int exynos_add_pcie_port(struct exynos_pcie *ep,
struct platform_device *pdev)
{
struct dw_pcie *pci = ep->pci;
struct dw_pcie *pci = &ep->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
pp->irq = platform_get_irq(pdev, 1);
pp->irq = platform_get_irq(pdev, 0);
if (pp->irq < 0)
return pp->irq;
ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
IRQF_SHARED, "exynos-pcie", ep);
IRQF_SHARED, "exynos-pcie", ep);
if (ret) {
dev_err(dev, "failed to request irq\n");
return ret;
}
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &exynos_pcie_host_ops;
pp->msi_irq = -ENODEV;
ret = dw_pcie_host_init(pp);
if (ret) {
@ -436,12 +308,12 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.read_dbi = exynos_pcie_read_dbi,
.write_dbi = exynos_pcie_write_dbi,
.link_up = exynos_pcie_link_up,
.start_link = exynos_pcie_start_link,
};
static int __init exynos_pcie_probe(struct platform_device *pdev)
static int exynos_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dw_pcie *pci;
struct exynos_pcie *ep;
struct device_node *np = dev->of_node;
int ret;
@ -450,42 +322,44 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
if (!ep)
return -ENOMEM;
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
if (!pci)
return -ENOMEM;
pci->dev = dev;
pci->ops = &dw_pcie_ops;
ep->pci = pci;
ep->ops = (const struct exynos_pcie_ops *)
of_device_get_match_data(dev);
ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
ep->pci.dev = dev;
ep->pci.ops = &dw_pcie_ops;
ep->phy = devm_of_phy_get(dev, np, NULL);
if (IS_ERR(ep->phy)) {
if (PTR_ERR(ep->phy) != -ENODEV)
return PTR_ERR(ep->phy);
if (IS_ERR(ep->phy))
return PTR_ERR(ep->phy);
ep->phy = NULL;
/* External Local Bus interface (ELBI) registers */
ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
if (IS_ERR(ep->elbi_base))
return PTR_ERR(ep->elbi_base);
ep->clk = devm_clk_get(dev, "pcie");
if (IS_ERR(ep->clk)) {
dev_err(dev, "Failed to get pcie rc clock\n");
return PTR_ERR(ep->clk);
}
if (ep->ops && ep->ops->get_mem_resources) {
ret = ep->ops->get_mem_resources(pdev, ep);
if (ret)
return ret;
ep->bus_clk = devm_clk_get(dev, "pcie_bus");
if (IS_ERR(ep->bus_clk)) {
dev_err(dev, "Failed to get pcie bus clock\n");
return PTR_ERR(ep->bus_clk);
}
if (ep->ops && ep->ops->get_clk_resources &&
ep->ops->init_clk_resources) {
ret = ep->ops->get_clk_resources(ep);
if (ret)
return ret;
ret = ep->ops->init_clk_resources(ep);
if (ret)
return ret;
}
ep->supplies[0].supply = "vdd18";
ep->supplies[1].supply = "vdd10";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies),
ep->supplies);
if (ret)
return ret;
ret = exynos_pcie_init_clk_resources(ep);
if (ret)
return ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ret)
return ret;
platform_set_drvdata(pdev, ep);
@ -497,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
fail_probe:
phy_exit(ep->phy);
exynos_pcie_deinit_clk_resources(ep);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ep->ops && ep->ops->deinit_clk_resources)
ep->ops->deinit_clk_resources(ep);
return ret;
}
@ -507,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
{
struct exynos_pcie *ep = platform_get_drvdata(pdev);
if (ep->ops && ep->ops->deinit_clk_resources)
ep->ops->deinit_clk_resources(ep);
dw_pcie_host_deinit(&ep->pci.pp);
exynos_pcie_assert_core_reset(ep);
phy_power_off(ep->phy);
phy_exit(ep->phy);
exynos_pcie_deinit_clk_resources(ep);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
return 0;
}
static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev)
{
struct exynos_pcie *ep = dev_get_drvdata(dev);
exynos_pcie_assert_core_reset(ep);
phy_power_off(ep->phy);
phy_exit(ep->phy);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
return 0;
}
static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev)
{
struct exynos_pcie *ep = dev_get_drvdata(dev);
struct dw_pcie *pci = &ep->pci;
struct pcie_port *pp = &pci->pp;
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
if (ret)
return ret;
/* exynos_pcie_host_init controls ep->phy */
exynos_pcie_host_init(pp);
dw_pcie_setup_rc(pp);
exynos_pcie_start_link(pci);
return dw_pcie_wait_for_link(pci);
}
static const struct dev_pm_ops exynos_pcie_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq,
exynos_pcie_resume_noirq)
};
static const struct of_device_id exynos_pcie_of_match[] = {
{
.compatible = "samsung,exynos5440-pcie",
.data = &exynos5440_pcie_ops
},
{},
{ .compatible = "samsung,exynos5433-pcie", },
{ },
};
static struct platform_driver exynos_pcie_driver = {
.probe = exynos_pcie_probe,
.remove = __exit_p(exynos_pcie_remove),
.driver = {
.name = "exynos-pcie",
.of_match_table = exynos_pcie_of_match,
.pm = &exynos_pcie_pm_ops,
},
};
/* Exynos PCIe driver does not allow module unload */
static int __init exynos_pcie_init(void)
{
return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
}
subsys_initcall(exynos_pcie_init);
module_platform_driver(exynos_pcie_driver);
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);

View File

@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
}
}
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
static int imx6_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
struct device *dev = pci->dev;
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 tmp;
@ -834,9 +834,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie);
imx6_setup_phy_mpll(imx6_pcie);
dw_pcie_setup_rc(pp);
imx6_pcie_establish_link(imx6_pcie);
dw_pcie_msi_init(pp);
return 0;
}
@ -845,33 +842,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
.host_init = imx6_pcie_host_init,
};
static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &imx6_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = {
/* No special ops needed, but pcie-designware still expects this struct */
.start_link = imx6_pcie_start_link,
};
#ifdef CONFIG_PM_SLEEP
@ -980,7 +952,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
imx6_pcie_deassert_core_reset(imx6_pcie);
dw_pcie_setup_rc(pp);
ret = imx6_pcie_establish_link(imx6_pcie);
ret = imx6_pcie_start_link(imx6_pcie->pci);
if (ret < 0)
dev_info(dev, "pcie link is down after resume.\n");
@ -1014,6 +986,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pci->pp.ops = &imx6_pcie_host_ops;
imx6_pcie->pci = pci;
imx6_pcie->drvdata = of_device_get_match_data(dev);
@ -1163,7 +1136,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;
ret = imx6_add_pcie_port(imx6_pcie, pdev);
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0)
return ret;

View File

@ -121,6 +121,7 @@ struct keystone_pcie {
int msi_host_irq;
int num_lanes;
u32 num_viewport;
struct phy **phy;
struct device_link **link;
struct device_node *msi_intc_np;
@ -272,14 +273,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
}
/*
* Dummy function so that DW core doesn't configure MSI
*/
static int ks_pcie_am654_msi_host_init(struct pcie_port *pp)
{
return 0;
}
static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
{
ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
@ -394,9 +387,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
{
u32 val;
u32 num_viewport = ks_pcie->num_viewport;
struct dw_pcie *pci = ks_pcie->pci;
struct pcie_port *pp = &pci->pp;
u32 num_viewport = pci->num_viewport;
u64 start, end;
struct resource *mem;
int i;
@ -519,14 +512,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
static int ks_pcie_start_link(struct dw_pcie *pci)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
struct device *dev = pci->dev;
u32 val;
if (dw_pcie_link_up(pci)) {
dev_dbg(dev, "link is already up\n");
return 0;
}
/* Initiate Link Training */
val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
@ -821,8 +808,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
if (ret)
return ret;
dw_pcie_setup_rc(pp);
ks_pcie_stop_link(pci);
ks_pcie_setup_rc_app_regs(ks_pcie);
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
@ -841,9 +826,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
"Asynchronous external abort");
#endif
ks_pcie_start_link(pci);
dw_pcie_wait_for_link(pci);
return 0;
}
@ -854,7 +836,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
.host_init = ks_pcie_host_init,
.msi_host_init = ks_pcie_am654_msi_host_init,
};
static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
@ -864,23 +845,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
return ks_pcie_handle_error_irq(ks_pcie);
}
static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = ks_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
u32 reg, size_t size, u32 val)
{
@ -977,33 +941,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
.get_features = &ks_pcie_am654_get_features,
};
static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = ks_pcie->pci;
ep = &pci->ep;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
{
int num_lanes = ks_pcie->num_lanes;
@ -1157,6 +1094,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
struct resource *res;
unsigned int version;
void __iomem *base;
u32 num_viewport;
struct phy **phy;
u32 num_lanes;
char name[10];
@ -1288,6 +1226,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
goto err_get_sync;
}
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
if (ret < 0) {
dev_err(dev, "unable to read *num-viewport* property\n");
goto err_get_sync;
}
/*
* "Power Sequencing and Reset Signal Timings" table in
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
@ -1301,8 +1245,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
gpiod_set_value_cansleep(gpiod, 1);
}
ks_pcie->num_viewport = num_viewport;
pci->pp.ops = host_ops;
ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0)
goto err_get_sync;
break;
@ -1313,7 +1258,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
}
pci->ep.ops = ep_ops;
ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
ret = dw_pcie_ep_init(&pci->ep);
if (ret < 0)
goto err_get_sync;
break;

View File

@ -18,8 +18,6 @@
#include "pcie-designware.h"
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
struct ls_pcie_ep_drvdata {
@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = {
{ },
};
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
struct dw_pcie_ep *ep;
struct resource *res;
int ret;
ep = &pci->ep;
ep->ops = pcie->drvdata->ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int __init ls_pcie_ep_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
struct ls_pcie_ep *pcie;
struct pci_epc_features *ls_epc;
struct resource *dbi_base;
int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
pci->ep.ops = &ls_pcie_ep_ops;
platform_set_drvdata(pdev, pcie);
ret = ls_add_pcie_ep(pcie, pdev);
return ret;
return dw_pcie_ep_init(&pci->ep);
}
static struct platform_driver ls_pcie_ep_driver = {

View File

@ -83,14 +83,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
}
static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie)
{
int i;
for (i = 0; i < PCIE_IATU_NUM; i++)
dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND);
}
static int ls1021_pcie_link_up(struct dw_pcie *pci)
{
u32 state;
@ -136,12 +128,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct ls_pcie *pcie = to_ls_pcie(pci);
/*
* Disable outbound windows configured by the bootloader to avoid
* one transaction hitting multiple outbound windows.
* dw_pcie_setup_rc() will reconfigure the outbound windows.
*/
ls_pcie_disable_outbound_atus(pcie);
ls_pcie_fix_error_response(pcie);
dw_pcie_dbi_ro_wr_en(pci);
@ -150,8 +136,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
ls_pcie_drop_msg_tlp(pcie);
dw_pcie_setup_rc(pp);
return 0;
}
@ -182,37 +166,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp)
return ls_pcie_host_init(pp);
}
static int ls_pcie_msi_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
struct device_node *np = dev->of_node;
struct device_node *msi_node;
/*
* The MSI domain is set by the generic of_msi_configure(). This
* .msi_host_init() function keeps us from doing the default MSI
* domain setup in dw_pcie_host_init() and also enforces the
* requirement that "msi-parent" exists.
*/
msi_node = of_parse_phandle(np, "msi-parent", 0);
if (!msi_node) {
dev_err(dev, "failed to find msi-parent\n");
return -EINVAL;
}
of_node_put(msi_node);
return 0;
}
static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
.host_init = ls1021_pcie_host_init,
.msi_host_init = ls_pcie_msi_host_init,
};
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
.host_init = ls_pcie_host_init,
.msi_host_init = ls_pcie_msi_host_init,
};
static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
@ -273,31 +232,12 @@ static const struct of_device_id ls_pcie_of_match[] = {
{ },
};
static int __init ls_add_pcie_port(struct ls_pcie *pcie)
{
struct dw_pcie *pci = pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
int ret;
pp->ops = pcie->drvdata->ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static int __init ls_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dw_pcie *pci;
struct ls_pcie *pcie;
struct resource *dbi_base;
int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@ -311,6 +251,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = pcie->drvdata->dw_pcie_ops;
pci->pp.ops = pcie->drvdata->ops;
pcie->pci = pci;
@ -326,11 +267,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcie);
ret = ls_add_pcie_port(pcie);
if (ret < 0)
return ret;
return 0;
return dw_pcie_host_init(&pci->pp);
}
static struct platform_driver ls_pcie_driver = {

View File

@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
gpiod_set_value_cansleep(mp->reset_gpio, 0);
}
static void meson_pcie_init_dw(struct meson_pcie *mp)
static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
{
u32 val;
@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
}
static int meson_pcie_establish_link(struct meson_pcie *mp)
static int meson_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = &mp->pci;
struct pcie_port *pp = &pci->pp;
meson_pcie_init_dw(mp);
meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
dw_pcie_setup_rc(pp);
struct meson_pcie *mp = to_meson_pcie(pci);
meson_pcie_ltssm_enable(mp);
meson_pcie_assert_reset(mp);
return dw_pcie_wait_for_link(pci);
return 0;
}
static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
@ -380,15 +374,11 @@ static int meson_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct meson_pcie *mp = to_meson_pcie(pci);
int ret;
pp->bridge->ops = &meson_pci_ops;
ret = meson_pcie_establish_link(mp);
if (ret)
return ret;
dw_pcie_msi_init(pp);
meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
return 0;
}
@ -397,33 +387,9 @@ static const struct dw_pcie_host_ops meson_pcie_host_ops = {
.host_init = meson_pcie_host_init,
};
static int meson_add_pcie_port(struct meson_pcie *mp,
struct platform_device *pdev)
{
struct dw_pcie *pci = &mp->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &meson_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = meson_pcie_link_up,
.start_link = meson_pcie_start_link,
};
static int meson_pcie_probe(struct platform_device *pdev)
@ -440,6 +406,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
pci = &mp->pci;
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pci->pp.ops = &meson_pcie_host_ops;
pci->num_lanes = 1;
mp->phy = devm_phy_get(dev, "pcie");
@ -486,7 +453,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mp);
ret = meson_add_pcie_port(mp, pdev);
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0) {
dev_err(dev, "Add PCIe port failed, %d\n", ret);
goto err_phy;

View File

@ -76,7 +76,6 @@ static int al_pcie_init(struct pci_config_window *cfg)
}
const struct pci_ecam_ops al_pcie_ops = {
.bus_shift = 20,
.init = al_pcie_init,
.pci_ops = {
.map_bus = al_pcie_map_bus,
@ -138,8 +137,6 @@ struct al_pcie {
struct al_pcie_target_bus_cfg target_bus_cfg;
};
#define PCIE_ECAM_DEVFN(x) (((x) & 0xff) << 12)
#define to_al_pcie(x) dev_get_drvdata((x)->dev)
static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
@ -226,11 +223,6 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
void __iomem *pci_base_addr;
pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
(busnr_ecam << 20) +
PCIE_ECAM_DEVFN(devfn));
if (busnr_reg != target_bus_cfg->reg_val) {
dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
@ -241,7 +233,7 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
target_bus_cfg->reg_mask);
}
return pci_base_addr + where;
return pp->va_cfg0_base + PCIE_ECAM_OFFSET(busnr_ecam, devfn, where);
}
static struct pci_ops al_child_pci_ops = {
@ -264,7 +256,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
target_bus_cfg = &pcie->target_bus_cfg;
ecam_bus_mask = (pcie->ecam_size >> 20) - 1;
ecam_bus_mask = (pcie->ecam_size >> PCIE_ECAM_BUS_SHIFT) - 1;
if (ecam_bus_mask > 255) {
dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
ecam_bus_mask = 255;
@ -322,23 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = {
.host_init = al_pcie_host_init,
};
static int al_add_pcie_port(struct pcie_port *pp,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret;
pp->ops = &al_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static const struct dw_pcie_ops dw_pcie_ops = {
};
@ -347,7 +322,6 @@ static int al_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *controller_res;
struct resource *ecam_res;
struct resource *dbi_res;
struct al_pcie *al_pcie;
struct dw_pcie *pci;
@ -361,15 +335,11 @@ static int al_pcie_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pci->pp.ops = &al_pcie_host_ops;
al_pcie->pci = pci;
al_pcie->dev = dev;
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (!ecam_res) {
dev_err(dev, "couldn't find 'config' reg in DT\n");
@ -386,12 +356,11 @@ static int al_pcie_probe(struct platform_device *pdev)
return PTR_ERR(al_pcie->controller_base);
}
dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n",
dbi_res, controller_res);
dev_dbg(dev, "From DT: controller_base: %pR\n", controller_res);
platform_set_drvdata(pdev, al_pcie);
return al_add_pcie_port(&pci->pp, pdev);
return dw_pcie_host_init(&pci->pp);
}
static const struct of_device_id al_pcie_of_match[] = {

View File

@ -154,11 +154,23 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci)
return 0;
}
static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
static int armada8k_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = pcie->pci;
u32 reg;
/* Start LTSSM */
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
reg |= PCIE_APP_LTSSM_EN;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
return 0;
}
static int armada8k_pcie_host_init(struct pcie_port *pp)
{
u32 reg;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
if (!dw_pcie_link_up(pci)) {
/* Disable LTSSM state machine to enable configuration */
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
@ -193,26 +205,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg);
if (!dw_pcie_link_up(pci)) {
/* Configuration done. Start LTSSM */
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
reg |= PCIE_APP_LTSSM_EN;
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
}
/* Wait until the link becomes active again */
if (dw_pcie_wait_for_link(pci))
dev_err(pci->dev, "Link not up after reconfiguration\n");
}
static int armada8k_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
dw_pcie_setup_rc(pp);
armada8k_pcie_establish_link(pcie);
return 0;
}
@ -269,6 +261,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = armada8k_pcie_link_up,
.start_link = armada8k_pcie_start_link,
};
static int armada8k_pcie_probe(struct platform_device *pdev)

View File

@ -328,10 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
artpec6_pcie_init_phy(artpec6_pcie);
artpec6_pcie_deassert_core_reset(artpec6_pcie);
artpec6_pcie_wait_for_phy(artpec6_pcie);
dw_pcie_setup_rc(pp);
artpec6_pcie_establish_link(pci);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
return 0;
}
@ -340,31 +336,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
.host_init = artpec6_pcie_host_init,
};
static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev)
{
struct dw_pcie *pci = artpec6_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = pci->dev;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->ops = &artpec6_pcie_host_ops;
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "failed to initialize host\n");
return ret;
}
return 0;
}
static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
@ -403,38 +374,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = {
.raise_irq = artpec6_pcie_raise_irq,
};
static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = artpec6_pcie->pci;
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int artpec6_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -469,10 +408,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
artpec6_pcie->variant = variant;
artpec6_pcie->mode = mode;
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
artpec6_pcie->phy_base =
devm_platform_ioremap_resource_byname(pdev, "phy");
if (IS_ERR(artpec6_pcie->phy_base))
@ -491,7 +426,9 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST))
return -ENODEV;
ret = artpec6_add_pcie_port(artpec6_pcie, pdev);
pci->pp.ops = &artpec6_pcie_host_ops;
ret = dw_pcie_host_init(&pci->pp);
if (ret < 0)
return ret;
break;
@ -504,9 +441,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
val &= ~PCIECFG_DEVICE_TYPE_MASK;
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
ret = artpec6_add_pcie_ep(artpec6_pcie, pdev);
if (ret < 0)
return ret;
pci->ep.ops = &pcie_ep_ops;
return dw_pcie_ep_init(&pci->ep);
break;
}
default:

View File

@ -7,6 +7,7 @@
*/
#include <linux/of.h>
#include <linux/platform_device.h>
#include "pcie-designware.h"
#include <linux/pci-epc.h>
@ -160,8 +161,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
u32 free_win;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
free_win = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
if (free_win >= ep->num_ib_windows) {
free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows);
if (free_win >= pci->num_ib_windows) {
dev_err(pci->dev, "No free inbound window\n");
return -EINVAL;
}
@ -186,8 +187,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
u32 free_win;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
free_win = find_first_zero_bit(ep->ob_window_map, ep->num_ob_windows);
if (free_win >= ep->num_ob_windows) {
free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows);
if (free_win >= pci->num_ob_windows) {
dev_err(pci->dev, "No free outbound window\n");
return -EINVAL;
}
@ -263,8 +264,9 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
u32 *atu_index)
{
u32 index;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
for (index = 0; index < ep->num_ob_windows; index++) {
for (index = 0; index < pci->num_ob_windows; index++) {
if (ep->outbound_addr[index] != addr)
continue;
*atu_index = index;
@ -676,55 +678,57 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
int ret;
void *addr;
u8 func_no;
struct resource *res;
struct pci_epc *epc;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct device *dev = pci->dev;
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
const struct pci_epc_features *epc_features;
struct dw_pcie_ep_func *ep_func;
INIT_LIST_HEAD(&ep->func_list);
if (!pci->dbi_base || !pci->dbi_base2) {
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
return -EINVAL;
if (!pci->dbi_base) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
}
ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
if (ret < 0) {
dev_err(dev, "Unable to read *num-ib-windows* property\n");
return ret;
}
if (ep->num_ib_windows > MAX_IATU_IN) {
dev_err(dev, "Invalid *num-ib-windows*\n");
return -EINVAL;
if (!pci->dbi_base2) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
if (!res)
pci->dbi_base2 = pci->dbi_base + SZ_4K;
else {
pci->dbi_base2 = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
}
}
ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows);
if (ret < 0) {
dev_err(dev, "Unable to read *num-ob-windows* property\n");
return ret;
}
if (ep->num_ob_windows > MAX_IATU_OUT) {
dev_err(dev, "Invalid *num-ob-windows*\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
}
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ep->ib_window_map = devm_kcalloc(dev,
BITS_TO_LONGS(ep->num_ib_windows),
BITS_TO_LONGS(pci->num_ib_windows),
sizeof(long),
GFP_KERNEL);
if (!ep->ib_window_map)
return -ENOMEM;
ep->ob_window_map = devm_kcalloc(dev,
BITS_TO_LONGS(ep->num_ob_windows),
BITS_TO_LONGS(pci->num_ob_windows),
sizeof(long),
GFP_KERNEL);
if (!ep->ob_window_map)
return -ENOMEM;
addr = devm_kcalloc(dev, ep->num_ob_windows, sizeof(phys_addr_t),
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
GFP_KERNEL);
if (!addr)
return -ENOMEM;

View File

@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
return 0;
}
void dw_pcie_free_msi(struct pcie_port *pp)
static void dw_pcie_free_msi(struct pcie_port *pp)
{
if (pp->msi_irq) {
irq_set_chained_handler(pp->msi_irq, NULL);
@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp)
}
}
void dw_pcie_msi_init(struct pcie_port *pp)
static void dw_pcie_msi_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
u64 msi_target = (u64)pp->msi_data;
if (!IS_ENABLED(CONFIG_PCI_MSI))
if (!pci_msi_enabled() || !pp->has_msi_ctrl)
return;
/* Program the msi_data */
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
}
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
int dw_pcie_host_init(struct pcie_port *pp)
{
@ -310,6 +309,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
dev_err(dev, "Missing *config* reg space\n");
}
if (!pci->dbi_base) {
struct resource *dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
}
bridge = devm_pci_alloc_host_bridge(dev, 0);
if (!bridge)
return -ENOMEM;
@ -350,44 +356,54 @@ int dw_pcie_host_init(struct pcie_port *pp)
}
}
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
if (ret)
pci->num_viewport = 2;
if (pci->link_gen < 1)
pci->link_gen = of_pci_get_max_link_speed(np);
if (pci_msi_enabled()) {
/*
* If a specific SoC driver needs to change the
* default number of vectors, it needs to implement
* the set_num_vectors callback.
*/
if (!pp->ops->set_num_vectors) {
pp->num_vectors = MSI_DEF_NUM_VECTORS;
} else {
pp->ops->set_num_vectors(pp);
pp->has_msi_ctrl = !(pp->ops->msi_host_init ||
of_property_read_bool(np, "msi-parent") ||
of_property_read_bool(np, "msi-map"));
if (pp->num_vectors > MAX_MSI_IRQS ||
pp->num_vectors == 0) {
dev_err(dev,
"Invalid number of vectors\n");
return -EINVAL;
}
if (!pp->num_vectors) {
pp->num_vectors = MSI_DEF_NUM_VECTORS;
} else if (pp->num_vectors > MAX_MSI_IRQS) {
dev_err(dev, "Invalid number of vectors\n");
return -EINVAL;
}
if (!pp->ops->msi_host_init) {
if (pp->ops->msi_host_init) {
ret = pp->ops->msi_host_init(pp);
if (ret < 0)
return ret;
} else if (pp->has_msi_ctrl) {
if (!pp->msi_irq) {
pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
if (pp->msi_irq < 0) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
}
pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
ret = dw_pcie_allocate_domains(pp);
if (ret)
return ret;
if (pp->msi_irq)
if (pp->msi_irq > 0)
irq_set_chained_handler_and_data(pp->msi_irq,
dw_chained_msi_isr,
pp);
ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32));
if (!ret) {
dev_warn(pci->dev,
"Failed to set DMA mask to 32-bit. "
"Devices with only 32-bit MSI support"
" may not work properly\n");
}
pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
sizeof(pp->msi_msg),
DMA_FROM_DEVICE,
@ -397,10 +413,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
pp->msi_data = 0;
goto err_free_msi;
}
} else {
ret = pp->ops->msi_host_init(pp);
if (ret < 0)
return ret;
}
}
@ -414,6 +426,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
goto err_free_msi;
}
dw_pcie_setup_rc(pp);
dw_pcie_msi_init(pp);
if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
ret = pci->ops->start_link(pci);
if (ret)
goto err_free_msi;
}
/* Ignore errors, the link may come up later */
dw_pcie_wait_for_link(pci);
bridge->sysdata = pp;
ret = pci_host_probe(bridge);
@ -421,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
return 0;
err_free_msi:
if (pci_msi_enabled() && !pp->ops->msi_host_init)
if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp);
return ret;
}
@ -431,7 +455,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
{
pci_stop_root_bus(pp->bridge->bus);
pci_remove_root_bus(pp->bridge->bus);
if (pci_msi_enabled() && !pp->ops->msi_host_init)
if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp);
}
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
@ -464,9 +488,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
type = PCIE_ATU_TYPE_CFG1;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
type, pp->cfg0_base,
busdev, pp->cfg0_size);
dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
return pp->va_cfg0_base + where;
}
@ -480,9 +502,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_read(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_IO, pp->io_base,
if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
return ret;
@ -497,9 +518,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
ret = pci_generic_config_write(bus, devfn, where, size, val);
if (!ret && pci->num_viewport <= 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_IO, pp->io_base,
if (!ret && pci->io_cfg_atu_shared)
dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
return ret;
@ -531,6 +551,7 @@ static struct pci_ops dw_pcie_ops = {
void dw_pcie_setup_rc(struct pcie_port *pp)
{
int i;
u32 val, ctrl, num_ctrls;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@ -542,7 +563,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
dw_pcie_setup(pci);
if (pci_msi_enabled() && !pp->ops->msi_host_init) {
if (pp->has_msi_ctrl) {
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
/* Initialize IRQ Status array */
@ -580,27 +601,45 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
/* Ensure all outbound windows are disabled so there are multiple matches */
for (i = 0; i < pci->num_ob_windows; i++)
dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND);
/*
* If the platform provides its own child bus config accesses, it means
* the platform uses its own address translation component rather than
* ATU, so we should not program the ATU here.
*/
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
struct resource_entry *tmp, *entry = NULL;
int atu_idx = 0;
struct resource_entry *entry;
/* Get last memory resource entry */
resource_list_for_each_entry(tmp, &pp->bridge->windows)
if (resource_type(tmp->res) == IORESOURCE_MEM)
entry = tmp;
resource_list_for_each_entry(entry, &pp->bridge->windows) {
if (resource_type(entry->res) != IORESOURCE_MEM)
continue;
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM, entry->res->start,
entry->res->start - entry->offset,
resource_size(entry->res));
if (pci->num_viewport > 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
if (pci->num_ob_windows <= ++atu_idx)
break;
dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_MEM, entry->res->start,
entry->res->start - entry->offset,
resource_size(entry->res));
}
if (pp->io_size) {
if (pci->num_ob_windows > ++atu_idx)
dw_pcie_prog_outbound_atu(pci, atu_idx,
PCIE_ATU_TYPE_IO, pp->io_base,
pp->io_bus_addr, pp->io_size);
else
pci->io_cfg_atu_shared = true;
}
if (pci->num_ob_windows <= atu_idx)
dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
pci->num_ob_windows);
}
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);

View File

@ -33,25 +33,7 @@ struct dw_plat_pcie_of_data {
static const struct of_device_id dw_plat_pcie_of_match[];
static int dw_plat_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
dw_pcie_setup_rc(pp);
dw_pcie_wait_for_link(pci);
dw_pcie_msi_init(pp);
return 0;
}
static void dw_plat_set_num_vectors(struct pcie_port *pp)
{
pp->num_vectors = MAX_MSI_IRQS;
}
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
.host_init = dw_plat_pcie_host_init,
.set_num_vectors = dw_plat_set_num_vectors,
};
static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
@ -122,12 +104,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
if (pp->irq < 0)
return pp->irq;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq(pdev, 0);
if (pp->msi_irq < 0)
return pp->msi_irq;
}
pp->num_vectors = MAX_MSI_IRQS;
pp->ops = &dw_plat_pcie_host_ops;
ret = dw_pcie_host_init(pp);
@ -139,43 +116,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
return 0;
}
static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
struct platform_device *pdev)
{
int ret;
struct dw_pcie_ep *ep;
struct resource *res;
struct device *dev = &pdev->dev;
struct dw_pcie *pci = dw_plat_pcie->pci;
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret) {
dev_err(dev, "Failed to initialize endpoint\n");
return ret;
}
return 0;
}
static int dw_plat_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct dw_plat_pcie *dw_plat_pcie;
struct dw_pcie *pci;
struct resource *res; /* Resource from DT */
int ret;
const struct of_device_id *match;
const struct dw_plat_pcie_of_data *data;
@ -202,14 +147,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
dw_plat_pcie->pci = pci;
dw_plat_pcie->mode = mode;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pci->dbi_base = devm_ioremap_resource(dev, res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
platform_set_drvdata(pdev, dw_plat_pcie);
switch (dw_plat_pcie->mode) {
@ -225,9 +162,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
return -ENODEV;
ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
if (ret < 0)
return ret;
pci->ep.ops = &pcie_ep_ops;
return dw_pcie_ep_init(&pci->ep);
break;
default:
dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);

View File

@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
int index, int type,
u64 cpu_addr, u64 pci_addr,
u32 size)
u64 size)
{
u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
type | PCIE_ATU_FUNC_NUM(func_no));
val = type | PCIE_ATU_FUNC_NUM(func_no);
val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE);
@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr,
u64 pci_addr, u32 size)
u64 pci_addr, u64 size)
{
u32 retries, val;
@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
}
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
u64 cpu_addr, u64 pci_addr, u32 size)
u64 cpu_addr, u64 pci_addr, u64 size)
{
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size);
@ -544,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
return 0;
}
static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
{
int max_region, i, ob = 0, ib = 0;
u32 val;
max_region = min((int)pci->atu_size / 512, 256);
for (i = 0; i < max_region; i++) {
dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
0x11110000);
val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
if (val == 0x11110000)
ob++;
else
break;
}
for (i = 0; i < max_region; i++) {
dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
0x11110000);
val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
if (val == 0x11110000)
ib++;
else
break;
}
pci->num_ib_windows = ib;
pci->num_ob_windows = ob;
}
static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
{
int max_region, i, ob = 0, ib = 0;
u32 val;
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
for (i = 0; i < max_region; i++) {
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
if (val == 0x11110000)
ob++;
else
break;
}
for (i = 0; i < max_region; i++) {
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
if (val == 0x11110000)
ib++;
else
break;
}
pci->num_ib_windows = ib;
pci->num_ob_windows = ob;
}
void dw_pcie_setup(struct dw_pcie *pci)
{
u32 val;
@ -554,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci)
if (pci->version >= 0x480A || (!pci->version &&
dw_pcie_iatu_unroll_enabled(pci))) {
pci->iatu_unroll_enabled = true;
if (!pci->atu_base)
pci->atu_base =
devm_platform_ioremap_resource_byname(pdev, "atu");
if (IS_ERR(pci->atu_base))
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
}
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
if (!pci->atu_base) {
struct resource *res =
platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
if (res)
pci->atu_size = resource_size(res);
pci->atu_base = devm_ioremap_resource(dev, res);
if (IS_ERR(pci->atu_base))
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
}
if (!pci->atu_size)
/* Pick a minimal default, enough for 8 in and 8 out windows */
pci->atu_size = SZ_4K;
dw_pcie_iatu_detect_regions_unroll(pci);
} else
dw_pcie_iatu_detect_regions(pci);
dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
"enabled" : "disabled");
dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound",
pci->num_ob_windows, pci->num_ib_windows);
if (pci->link_gen > 0)
dw_pcie_link_set_max_speed(pci, pci->link_gen);

View File

@ -80,10 +80,8 @@
#define PCIE_ATU_VIEWPORT 0x900
#define PCIE_ATU_REGION_INBOUND BIT(31)
#define PCIE_ATU_REGION_OUTBOUND 0
#define PCIE_ATU_REGION_INDEX2 0x2
#define PCIE_ATU_REGION_INDEX1 0x1
#define PCIE_ATU_REGION_INDEX0 0x0
#define PCIE_ATU_CR1 0x904
#define PCIE_ATU_INCREASE_REGION_SIZE BIT(13)
#define PCIE_ATU_TYPE_MEM 0x0
#define PCIE_ATU_TYPE_IO 0x2
#define PCIE_ATU_TYPE_CFG0 0x4
@ -174,11 +172,11 @@ enum dw_pcie_device_mode {
struct dw_pcie_host_ops {
int (*host_init)(struct pcie_port *pp);
void (*set_num_vectors)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp);
};
struct pcie_port {
bool has_msi_ctrl:1;
u64 cfg0_base;
void __iomem *va_cfg0_base;
u32 cfg0_size;
@ -239,8 +237,6 @@ struct dw_pcie_ep {
phys_addr_t *outbound_addr;
unsigned long *ib_window_map;
unsigned long *ob_window_map;
u32 num_ib_windows;
u32 num_ob_windows;
void __iomem *msi_mem;
phys_addr_t msi_mem_phys;
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
@ -265,8 +261,9 @@ struct dw_pcie {
void __iomem *dbi_base2;
/* Used when iatu_unroll_enabled is true */
void __iomem *atu_base;
u32 num_viewport;
u8 iatu_unroll_enabled;
size_t atu_size;
u32 num_ib_windows;
u32 num_ob_windows;
struct pcie_port pp;
struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops;
@ -274,6 +271,8 @@ struct dw_pcie {
int num_lanes;
int link_gen;
u8 n_fts[2];
bool iatu_unroll_enabled: 1;
bool io_cfg_atu_shared: 1;
};
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
@ -295,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
int dw_pcie_wait_for_link(struct dw_pcie *pci);
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
int type, u64 cpu_addr, u64 pci_addr,
u32 size);
u64 size);
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u64 pci_addr,
u32 size);
@ -365,8 +364,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
#ifdef CONFIG_PCIE_DW_HOST
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
void dw_pcie_msi_init(struct pcie_port *pp);
void dw_pcie_free_msi(struct pcie_port *pp);
void dw_pcie_setup_rc(struct pcie_port *pp);
int dw_pcie_host_init(struct pcie_port *pp);
void dw_pcie_host_deinit(struct pcie_port *pp);
@ -379,14 +376,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
return IRQ_NONE;
}
static inline void dw_pcie_msi_init(struct pcie_port *pp)
{
}
static inline void dw_pcie_free_msi(struct pcie_port *pp)
{
}
static inline void dw_pcie_setup_rc(struct pcie_port *pp)
{
}

View File

@ -100,7 +100,6 @@ static int hisi_pcie_init(struct pci_config_window *cfg)
}
const struct pci_ecam_ops hisi_pcie_ops = {
.bus_shift = 20,
.init = hisi_pcie_init,
.pci_ops = {
.map_bus = hisi_pcie_map_bus,
@ -135,7 +134,6 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg)
}
static const struct pci_ecam_ops hisi_pcie_platform_ops = {
.bus_shift = 20,
.init = hisi_pcie_platform_init,
.pci_ops = {
.map_bus = hisi_pcie_map_bus,

View File

@ -169,40 +169,32 @@ static int histb_pcie_link_up(struct dw_pcie *pci)
return 0;
}
static int histb_pcie_establish_link(struct pcie_port *pp)
static int histb_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct histb_pcie *hipcie = to_histb_pcie(pci);
u32 regval;
if (dw_pcie_link_up(pci)) {
dev_info(pci->dev, "Link already up\n");
return 0;
}
/* PCIe RC work mode */
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
regval &= ~PCIE_DEVICE_TYPE_MASK;
regval |= PCIE_WM_RC;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
/* setup root complex */
dw_pcie_setup_rc(pp);
/* assert LTSSM enable */
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7);
regval |= PCIE_APP_LTSSM_ENABLE;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval);
return dw_pcie_wait_for_link(pci);
return 0;
}
static int histb_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct histb_pcie *hipcie = to_histb_pcie(pci);
u32 regval;
pp->bridge->ops = &histb_pci_ops;
histb_pcie_establish_link(pp);
dw_pcie_msi_init(pp);
/* PCIe RC work mode */
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
regval &= ~PCIE_DEVICE_TYPE_MASK;
regval |= PCIE_WM_RC;
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
return 0;
}
@ -300,6 +292,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.read_dbi = histb_pcie_read_dbi,
.write_dbi = histb_pcie_write_dbi,
.link_up = histb_pcie_link_up,
.start_link = histb_pcie_start_link,
};
static int histb_pcie_probe(struct platform_device *pdev)
@ -400,12 +393,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
return PTR_ERR(hipcie->bus_reset);
}
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
hipcie->phy = devm_phy_get(dev, "phy");
if (IS_ERR(hipcie->phy)) {
dev_info(dev, "no pcie-phy found\n");

View File

@ -58,8 +58,6 @@
struct intel_pcie_soc {
unsigned int pcie_ver;
unsigned int pcie_atu_offset;
u32 num_viewport;
};
struct intel_pcie_port {
@ -153,15 +151,6 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci)
pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
}
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
{
intel_pcie_ltssm_disable(lpp);
intel_pcie_link_setup(lpp);
intel_pcie_init_n_fts(&lpp->pci);
dw_pcie_setup_rc(&lpp->pci.pp);
dw_pcie_upconfig_setup(&lpp->pci);
}
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
{
struct device *dev = lpp->pci.dev;
@ -213,14 +202,6 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp)
gpiod_set_value_cansleep(lpp->reset_gpio, 0);
}
static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp)
{
intel_pcie_device_rst_deassert(lpp);
intel_pcie_ltssm_enable(lpp);
return dw_pcie_wait_for_link(&lpp->pci);
}
static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp)
{
pcie_app_wr(lpp, PCIE_APP_IRNEN, 0);
@ -234,10 +215,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
struct device *dev = pci->dev;
int ret;
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
lpp->core_clk = devm_clk_get(dev, NULL);
if (IS_ERR(lpp->core_clk)) {
ret = PTR_ERR(lpp->core_clk);
@ -274,11 +251,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
return 0;
}
static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp)
{
phy_exit(lpp->phy);
}
static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
{
u32 value;
@ -315,6 +287,7 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
{
int ret;
struct dw_pcie *pci = &lpp->pci;
intel_pcie_core_rst_assert(lpp);
intel_pcie_device_rst_assert(lpp);
@ -331,8 +304,18 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
goto clk_err;
}
intel_pcie_rc_setup(lpp);
ret = intel_pcie_app_logic_setup(lpp);
pci->atu_base = pci->dbi_base + 0xC0000;
intel_pcie_ltssm_disable(lpp);
intel_pcie_link_setup(lpp);
intel_pcie_init_n_fts(pci);
dw_pcie_setup_rc(&pci->pp);
dw_pcie_upconfig_setup(pci);
intel_pcie_device_rst_deassert(lpp);
intel_pcie_ltssm_enable(lpp);
ret = dw_pcie_wait_for_link(pci);
if (ret)
goto app_init_err;
@ -346,7 +329,7 @@ app_init_err:
clk_disable_unprepare(lpp->core_clk);
clk_err:
intel_pcie_core_rst_assert(lpp);
intel_pcie_deinit_phy(lpp);
phy_exit(lpp->phy);
return ret;
}
@ -357,7 +340,7 @@ static void __intel_pcie_remove(struct intel_pcie_port *lpp)
intel_pcie_turn_off(lpp);
clk_disable_unprepare(lpp->core_clk);
intel_pcie_core_rst_assert(lpp);
intel_pcie_deinit_phy(lpp);
phy_exit(lpp->phy);
}
static int intel_pcie_remove(struct platform_device *pdev)
@ -381,7 +364,7 @@ static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev)
if (ret)
return ret;
intel_pcie_deinit_phy(lpp);
phy_exit(lpp->phy);
clk_disable_unprepare(lpp->core_clk);
return ret;
}
@ -401,14 +384,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp)
return intel_pcie_host_setup(lpp);
}
/*
* Dummy function so that DW core doesn't configure MSI
*/
static int intel_pcie_msi_init(struct pcie_port *pp)
{
return 0;
}
static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
{
return cpu_addr + BUS_IATU_OFFSET;
@ -420,13 +395,10 @@ static const struct dw_pcie_ops intel_pcie_ops = {
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
.host_init = intel_pcie_rc_init,
.msi_host_init = intel_pcie_msi_init,
};
static const struct intel_pcie_soc pcie_data = {
.pcie_ver = 0x520A,
.pcie_atu_offset = 0xC0000,
.num_viewport = 3,
};
static int intel_pcie_probe(struct platform_device *pdev)
@ -461,7 +433,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
pci->ops = &intel_pcie_ops;
pci->version = data->pcie_ver;
pci->atu_base = pci->dbi_base + data->pcie_atu_offset;
pp->ops = &intel_pcie_dw_ops;
ret = dw_pcie_host_init(pp);
@ -470,12 +441,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
return ret;
}
/*
* Intel PCIe doesn't configure IO region, so set viewport
* to not perform IO region access.
*/
pci->num_viewport = data->num_viewport;
return 0;
}

View File

@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
if (IS_ERR(kirin_pcie->phy_base))
return PTR_ERR(kirin_pcie->phy_base);
kirin_pcie->pci->dbi_base =
devm_platform_ioremap_resource_byname(pdev, "dbi");
if (IS_ERR(kirin_pcie->pci->dbi_base))
return PTR_ERR(kirin_pcie->pci->dbi_base);
kirin_pcie->crgctrl =
syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl");
if (IS_ERR(kirin_pcie->crgctrl))
@ -395,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci)
return 0;
}
static int kirin_pcie_establish_link(struct pcie_port *pp)
static int kirin_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
struct device *dev = kirin_pcie->pci->dev;
int count = 0;
if (kirin_pcie_link_up(pci))
return 0;
dw_pcie_setup_rc(pp);
/* assert LTSSM enable */
kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT,
PCIE_APP_LTSSM_ENABLE);
/* check if the link is up or not */
while (!kirin_pcie_link_up(pci)) {
usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
count++;
if (count == 1000) {
dev_err(dev, "Link Fail\n");
return -EINVAL;
}
}
return 0;
}
@ -428,9 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
{
pp->bridge->ops = &kirin_pci_ops;
kirin_pcie_establish_link(pp);
dw_pcie_msi_init(pp);
return 0;
}
@ -438,42 +412,13 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
.read_dbi = kirin_pcie_read_dbi,
.write_dbi = kirin_pcie_write_dbi,
.link_up = kirin_pcie_link_up,
.start_link = kirin_pcie_start_link,
};
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
.host_init = kirin_pcie_host_init,
};
static int kirin_pcie_add_msi(struct dw_pcie *pci,
struct platform_device *pdev)
{
int irq;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
pci->pp.msi_irq = irq;
}
return 0;
}
static int kirin_add_pcie_port(struct dw_pcie *pci,
struct platform_device *pdev)
{
int ret;
ret = kirin_pcie_add_msi(pci, pdev);
if (ret)
return ret;
pci->pp.ops = &kirin_pcie_host_ops;
return dw_pcie_host_init(&pci->pp);
}
static int kirin_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -496,6 +441,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = &kirin_dw_pcie_ops;
pci->pp.ops = &kirin_pcie_host_ops;
kirin_pcie->pci = pci;
ret = kirin_pcie_get_clk(kirin_pcie, pdev);
@ -521,7 +467,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kirin_pcie);
return kirin_add_pcie_port(pci, pdev);
return dw_pcie_host_init(&pci->pp);
}
static const struct of_device_id kirin_pcie_match[] = {

View File

@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
@ -57,6 +58,7 @@
#define PCIE20_PARF_SID_OFFSET 0x234
#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
#define PCIE20_PARF_DEVICE_TYPE 0x1000
#define PCIE20_PARF_BDF_TO_SID_TABLE_N 0x2000
#define PCIE20_ELBI_SYS_CTRL 0x04
#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0)
@ -97,6 +99,9 @@
#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5
#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
struct qcom_pcie_resources_2_1_0 {
struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
struct reset_control *pci_reset;
@ -179,6 +184,7 @@ struct qcom_pcie_ops {
void (*deinit)(struct qcom_pcie *pcie);
void (*post_deinit)(struct qcom_pcie *pcie);
void (*ltssm_enable)(struct qcom_pcie *pcie);
int (*config_sid)(struct qcom_pcie *pcie);
};
struct qcom_pcie {
@ -207,18 +213,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
}
static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
static int qcom_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = pcie->pci;
if (dw_pcie_link_up(pci))
return 0;
struct qcom_pcie *pcie = to_qcom_pcie(pci);
/* Enable Link Training state machine */
if (pcie->ops->ltssm_enable)
pcie->ops->ltssm_enable(pcie);
return dw_pcie_wait_for_link(pci);
return 0;
}
static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
@ -1261,6 +1264,77 @@ static int qcom_pcie_link_up(struct dw_pcie *pci)
return !!(val & PCI_EXP_LNKSTA_DLLLA);
}
static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
{
/* iommu map structure */
struct {
u32 bdf;
u32 phandle;
u32 smmu_sid;
u32 smmu_sid_len;
} *map;
void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
struct device *dev = pcie->pci->dev;
u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
int i, nr_map, size = 0;
u32 smmu_sid_base;
of_get_property(dev->of_node, "iommu-map", &size);
if (!size)
return 0;
map = kzalloc(size, GFP_KERNEL);
if (!map)
return -ENOMEM;
of_property_read_u32_array(dev->of_node,
"iommu-map", (u32 *)map, size / sizeof(u32));
nr_map = size / (sizeof(*map));
crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
/* Registers need to be zero out first */
memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
/* Extract the SMMU SID base from the first entry of iommu-map */
smmu_sid_base = map[0].smmu_sid;
/* Look for an available entry to hold the mapping */
for (i = 0; i < nr_map; i++) {
u16 bdf_be = cpu_to_be16(map[i].bdf);
u32 val;
u8 hash;
hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
0);
val = readl(bdf_to_sid_base + hash * sizeof(u32));
/* If the register is already populated, look for next available entry */
while (val) {
u8 current_hash = hash++;
u8 next_mask = 0xff;
/* If NEXT field is NULL then update it with next hash */
if (!(val & next_mask)) {
val |= (u32)hash;
writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
}
val = readl(bdf_to_sid_base + hash * sizeof(u32));
}
/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
writel(val, bdf_to_sid_base + hash * sizeof(u32));
}
kfree(map);
return 0;
}
static int qcom_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@ -1283,16 +1357,16 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
goto err_disable_phy;
}
dw_pcie_setup_rc(pp);
dw_pcie_msi_init(pp);
qcom_ep_reset_deassert(pcie);
ret = qcom_pcie_establish_link(pcie);
if (ret)
goto err;
if (pcie->ops->config_sid) {
ret = pcie->ops->config_sid(pcie);
if (ret)
goto err;
}
return 0;
err:
qcom_ep_reset_assert(pcie);
if (pcie->ops->post_deinit)
@ -1361,14 +1435,25 @@ static const struct qcom_pcie_ops ops_2_7_0 = {
.post_deinit = qcom_pcie_post_deinit_2_7_0,
};
/* Qcom IP rev.: 1.9.0 */
static const struct qcom_pcie_ops ops_1_9_0 = {
.get_resources = qcom_pcie_get_resources_2_7_0,
.init = qcom_pcie_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
.post_init = qcom_pcie_post_init_2_7_0,
.post_deinit = qcom_pcie_post_deinit_2_7_0,
.config_sid = qcom_pcie_config_sid_sm8250,
};
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = qcom_pcie_link_up,
.start_link = qcom_pcie_start_link,
};
static int qcom_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
struct pcie_port *pp;
struct dw_pcie *pci;
struct qcom_pcie *pcie;
@ -1407,13 +1492,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
goto err_pm_runtime_put;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(pci->dbi_base)) {
ret = PTR_ERR(pci->dbi_base);
goto err_pm_runtime_put;
}
pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
if (IS_ERR(pcie->elbi)) {
ret = PTR_ERR(pcie->elbi);
@ -1432,14 +1510,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pp->ops = &qcom_pcie_dw_ops;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0) {
ret = pp->msi_irq;
goto err_pm_runtime_put;
}
}
ret = phy_init(pcie->phy);
if (ret) {
pm_runtime_disable(&pdev->dev);
@ -1474,6 +1544,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
{ .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 },
{ .compatible = "qcom,pcie-sm8250", .data = &ops_1_9_0 },
{ }
};

View File

@ -66,32 +66,10 @@ struct pcie_app_reg {
#define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
static int spear13xx_pcie_start_link(struct dw_pcie *pci)
{
struct dw_pcie *pci = spear13xx_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
u32 val;
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
if (dw_pcie_link_up(pci)) {
dev_err(pci->dev, "link already up\n");
return 0;
}
dw_pcie_setup_rc(pp);
/*
* this controller support only 128 bytes read size, however its
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
/* enable ltssm */
writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
| ((u32)1 << REG_TRANSLATION_ENABLE),
&app_reg->app_ctrl_0);
return dw_pcie_wait_for_link(pci);
return 0;
}
static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
@ -124,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie)
{
struct dw_pcie *pci = spear13xx_pcie->pci;
struct pcie_port *pp = &pci->pp;
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
/* Enable MSI interrupt */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
dw_pcie_msi_init(pp);
if (IS_ENABLED(CONFIG_PCI_MSI))
writel(readl(&app_reg->int_mask) |
MSI_CTRL_INT, &app_reg->int_mask);
}
}
static int spear13xx_pcie_link_up(struct dw_pcie *pci)
@ -151,8 +125,23 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
u32 val;
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
/*
* this controller support only 128 bytes read size, however its
* default value in capability register is 512 bytes. So force
* it to 128 here.
*/
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
spear13xx_pcie_establish_link(spear13xx_pcie);
spear13xx_pcie_enable_interrupts(spear13xx_pcie);
return 0;
@ -183,6 +172,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
}
pp->ops = &spear13xx_pcie_host_ops;
pp->msi_irq = -ENODEV;
ret = dw_pcie_host_init(pp);
if (ret) {
@ -195,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = spear13xx_pcie_link_up,
.start_link = spear13xx_pcie_start_link,
};
static int spear13xx_pcie_probe(struct platform_device *pdev)
@ -203,7 +194,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
struct dw_pcie *pci;
struct spear13xx_pcie *spear13xx_pcie;
struct device_node *np = dev->of_node;
struct resource *dbi_base;
int ret;
spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL);
@ -242,14 +232,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
return ret;
}
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
if (IS_ERR(pci->dbi_base)) {
ret = PTR_ERR(pci->dbi_base);
goto fail_clk;
}
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
if (of_property_read_bool(np, "st,pcie-is-gen1"))
pci->link_gen = 1;

View File

@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val;
dw_pcie_msi_init(pp);
/* Enable MSI interrupt generation */
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
@ -861,6 +859,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val;
if (!pcie->pcie_cap_base)
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
PCI_CAP_ID_EXP);
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
@ -889,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
init_host_aspm(pcie);
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@ -990,11 +998,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
return !!(val & PCI_EXP_LNKSTA_DLLLA);
}
static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
{
pp->num_vectors = MAX_MSI_IRQS;
}
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
{
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
@ -1019,7 +1022,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
.host_init = tegra_pcie_dw_host_init,
.set_num_vectors = tegra_pcie_set_msi_vec_num,
};
static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
@ -1061,9 +1063,16 @@ phy_exit:
static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
{
struct platform_device *pdev = to_platform_device(pcie->dev);
struct device_node *np = pcie->dev->of_node;
int ret;
pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!pcie->dbi_res) {
dev_err(pcie->dev, "Failed to find \"dbi\" region\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
if (ret < 0) {
dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
@ -1390,15 +1399,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
reset_control_deassert(pcie->core_rst);
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
PCI_CAP_ID_EXP);
/* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
if (!pcie->supports_clkreq) {
disable_aspm_l11(pcie);
disable_aspm_l12(pcie);
}
return ret;
fail_phy:
@ -1415,43 +1415,32 @@ fail_slot_reg_en:
return ret;
}
static int __deinit_controller(struct tegra_pcie_dw *pcie)
static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
{
int ret;
ret = reset_control_assert(pcie->core_rst);
if (ret) {
dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
ret);
return ret;
}
if (ret)
dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret);
tegra_pcie_disable_phy(pcie);
ret = reset_control_assert(pcie->core_apb_rst);
if (ret) {
if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
return ret;
}
clk_disable_unprepare(pcie->core_clk);
ret = regulator_disable(pcie->pex_ctl_supply);
if (ret) {
if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
return ret;
}
tegra_pcie_disable_slot_regulators(pcie);
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
if (ret) {
if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
return ret;
}
return ret;
}
static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
return 0;
fail_host_init:
return __deinit_controller(pcie);
tegra_pcie_unconfig_controller(pcie);
return ret;
}
static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@ -1516,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX);
/*
* Some cards do not go to detect state even after de-asserting
* PERST#. So, de-assert LTSSM to bring link to detect state.
*/
data = readl(pcie->appl_base + APPL_CTRL);
data &= ~APPL_CTRL_LTSSM_EN;
writel(data, pcie->appl_base + APPL_CTRL);
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
data,
((data &
@ -1523,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
LTSSM_STATE_PRE_DETECT,
1, LTSSM_TIMEOUT);
if (err) {
if (err)
dev_info(pcie->dev, "Link didn't go to detect state\n");
} else {
/* Disable LTSSM after link is in detect state */
data = appl_readl(pcie, APPL_CTRL);
data &= ~APPL_CTRL_LTSSM_EN;
appl_writel(pcie, data, APPL_CTRL);
}
}
/*
* DBI registers may not be accessible after this as PLL-E would be
@ -1544,30 +1536,20 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
}
static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
{
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(&pcie->pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
return __deinit_controller(pcie);
tegra_pcie_unconfig_controller(pcie);
}
static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
{
struct pcie_port *pp = &pcie->pci.pp;
struct device *dev = pcie->dev;
char *name;
int ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
if (!pp->msi_irq) {
dev_err(dev, "Failed to get MSI interrupt\n");
return -ENODEV;
}
}
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
@ -1583,7 +1565,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
goto fail_pm_get_sync;
}
tegra_pcie_init_controller(pcie);
ret = tegra_pcie_init_controller(pcie);
if (ret < 0) {
dev_err(dev, "Failed to initialize controller: %d\n", ret);
goto fail_pm_get_sync;
}
pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
if (!pcie->link_state) {
@ -1907,19 +1893,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
struct dw_pcie *pci = &pcie->pci;
struct device *dev = pcie->dev;
struct dw_pcie_ep *ep;
struct resource *res;
char *name;
int ret;
ep = &pci->ep;
ep->ops = &pcie_ep_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ep->page_size = SZ_64K;
ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
@ -1982,7 +1961,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *atu_dma_res;
struct tegra_pcie_dw *pcie;
struct resource *dbi_res;
struct pcie_port *pp;
struct dw_pcie *pci;
struct phy **phys;
@ -2001,8 +1979,10 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
pci->ops = &tegra_dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
pci->version = 0x490A;
pp = &pci->pp;
pp->num_vectors = MAX_MSI_IRQS;
pcie->dev = &pdev->dev;
pcie->mode = (enum dw_pcie_device_mode)data->mode;
@ -2091,20 +2071,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
pcie->phys = phys;
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
if (!dbi_res) {
dev_err(dev, "Failed to find \"dbi\" region\n");
return -ENODEV;
}
pcie->dbi_res = dbi_res;
pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
/* Tegra HW locates DBI2 at a fixed offset from DBI */
pci->dbi_base2 = pci->dbi_base + 0x1000;
atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"atu_dma");
if (!atu_dma_res) {
@ -2113,6 +2079,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
}
pcie->atu_dma_res = atu_dma_res;
pci->atu_size = resource_size(atu_dma_res);
pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
if (IS_ERR(pci->atu_base))
return PTR_ERR(pci->atu_base);
@ -2225,8 +2192,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
tegra_pcie_unconfig_controller(pcie);
return __deinit_controller(pcie);
return 0;
}
static int tegra_pcie_dw_resume_noirq(struct device *dev)
@ -2254,7 +2222,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
fail_host_init:
return __deinit_controller(pcie);
tegra_pcie_unconfig_controller(pcie);
return ret;
}
static int tegra_pcie_dw_resume_early(struct device *dev)
@ -2292,7 +2261,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
disable_irq(pcie->pci.pp.msi_irq);
tegra_pcie_dw_pme_turnoff(pcie);
__deinit_controller(pcie);
tegra_pcie_unconfig_controller(pcie);
}
static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {

View File

@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
.get_features = uniphier_pcie_get_features,
};
static int uniphier_add_pcie_ep(struct uniphier_pcie_ep_priv *priv,
struct platform_device *pdev)
{
struct dw_pcie *pci = &priv->pci;
struct dw_pcie_ep *ep = &pci->ep;
struct device *dev = &pdev->dev;
struct resource *res;
int ret;
ep->ops = &uniphier_pcie_ep_ops;
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
if (IS_ERR(pci->dbi_base2))
return PTR_ERR(pci->dbi_base2);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
if (!res)
return -EINVAL;
ep->phys_base = res->start;
ep->addr_size = resource_size(res);
ret = dw_pcie_ep_init(ep);
if (ret)
dev_err(dev, "Failed to initialize endpoint (%d)\n", ret);
return ret;
}
static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
{
int ret;
@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_pcie_ep_priv *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
priv->pci.dev = dev;
priv->pci.ops = &dw_pcie_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
if (ret)
return ret;
return uniphier_add_pcie_ep(priv, pdev);
priv->pci.ep.ops = &uniphier_pcie_ep_ops;
return dw_pcie_ep_init(&priv->pci.ep);
}
static const struct pci_epc_features uniphier_pro5_data = {

View File

@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci)
return (val & mask) == mask;
}
static int uniphier_pcie_establish_link(struct dw_pcie *pci)
static int uniphier_pcie_start_link(struct dw_pcie *pci)
{
struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
if (dw_pcie_link_up(pci))
return 0;
uniphier_pcie_ltssm_enable(priv, true);
return dw_pcie_wait_for_link(pci);
return 0;
}
static void uniphier_pcie_stop_link(struct dw_pcie *pci)
@ -317,13 +314,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
uniphier_pcie_irq_enable(priv);
dw_pcie_setup_rc(pp);
ret = uniphier_pcie_establish_link(pci);
if (ret)
return ret;
dw_pcie_msi_init(pp);
return 0;
}
@ -331,31 +321,6 @@ static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
.host_init = uniphier_pcie_host_init,
};
static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
struct platform_device *pdev)
{
struct dw_pcie *pci = &priv->pci;
struct pcie_port *pp = &pci->pp;
struct device *dev = &pdev->dev;
int ret;
pp->ops = &uniphier_pcie_host_ops;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq < 0)
return pp->msi_irq;
}
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "Failed to initialize host (%d)\n", ret);
return ret;
}
return 0;
}
static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
{
int ret;
@ -391,7 +356,7 @@ out_clk_disable:
}
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = uniphier_pcie_establish_link,
.start_link = uniphier_pcie_start_link,
.stop_link = uniphier_pcie_stop_link,
.link_up = uniphier_pcie_link_up,
};
@ -400,7 +365,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct uniphier_pcie_priv *priv;
struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -410,11 +374,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
priv->pci.dev = dev;
priv->pci.ops = &dw_pcie_ops;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
if (IS_ERR(priv->pci.dbi_base))
return PTR_ERR(priv->pci.dbi_base);
priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
@ -437,7 +396,9 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
if (ret)
return ret;
return uniphier_add_pcie_port(priv, pdev);
priv->pci.pp.ops = &uniphier_pcie_host_ops;
return dw_pcie_host_init(&priv->pci.pp);
}
static const struct of_device_id uniphier_pcie_match[] = {

View File

@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/init.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
@ -164,14 +165,6 @@
#define PCIE_CONFIG_WR_TYPE0 0xa
#define PCIE_CONFIG_WR_TYPE1 0xb
#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
#define PCIE_CONF_ADDR(bus, devfn, where) \
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
#define PIO_RETRY_CNT 500
#define PIO_RETRY_DELAY 2 /* 2 us*/
@ -259,7 +252,14 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie)
if (!pcie->reset_gpio)
return;
/* PERST does not work for some cards when link training is enabled */
/*
* As required by PCI Express spec (PCI Express Base Specification, REV.
* 4.0 PCI Express, February 19 2014, 6.6.1 Conventional Reset) a delay
* for at least 100ms after de-asserting PERST# signal is needed before
* link training is enabled. So ensure that link training is disabled
* prior de-asserting PERST# signal to fulfill that PCI Express spec
* requirement.
*/
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~LINK_TRAINING_EN;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
@ -687,7 +687,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */
reg = PCIE_CONF_ADDR(bus->number, devfn, where);
reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS);
@ -748,7 +748,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
advk_writel(pcie, reg, PIO_CTRL);
/* Program the address registers */
reg = PCIE_CONF_ADDR(bus->number, devfn, where);
reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
advk_writel(pcie, reg, PIO_ADDR_LS);
advk_writel(pcie, 0, PIO_ADDR_MS);

View File

@ -49,7 +49,6 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
}
static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_dw_ecam_map_bus,
.read = pci_generic_config_read,

View File

@ -346,7 +346,6 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
}
const struct pci_ecam_ops pci_thunder_ecam_ops = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = thunder_ecam_config_read,

View File

@ -19,6 +19,15 @@
#define PEM_CFG_WR 0x28
#define PEM_CFG_RD 0x30
/*
* Enhanced Configuration Access Mechanism (ECAM)
*
* N.B. This is a non-standard platform-specific ECAM bus shift value. For
* standard values defined in the PCI Express Base Specification see
* include/linux/pci-ecam.h.
*/
#define THUNDER_PCIE_ECAM_BUS_SHIFT 24
struct thunder_pem_pci {
u32 ea_entry[3];
void __iomem *pem_reg_base;
@ -404,7 +413,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg)
}
const struct pci_ecam_ops thunder_pem_ecam_ops = {
.bus_shift = 24,
.bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
.init = thunder_pem_acpi_init,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
@ -441,7 +450,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg)
}
static const struct pci_ecam_ops pci_thunder_pem_ops = {
.bus_shift = 24,
.bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
.init = thunder_pem_platform_init,
.pci_ops = {
.map_bus = pci_ecam_map_bus,

View File

@ -257,7 +257,6 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
}
const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
.bus_shift = 16,
.init = xgene_v1_pcie_ecam_init,
.pci_ops = {
.map_bus = xgene_pcie_map_bus,
@ -272,7 +271,6 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
}
const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
.bus_shift = 16,
.init = xgene_v2_pcie_ecam_init,
.pci_ops = {
.map_bus = xgene_pcie_map_bus,

View File

@ -22,6 +22,7 @@
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/printk.h>
#include <linux/reset.h>
#include <linux/sizes.h>
@ -127,11 +128,7 @@
#define MSI_INT_MASK_CLR 0x14
#define PCIE_EXT_CFG_DATA 0x8000
#define PCIE_EXT_CFG_INDEX 0x9000
#define PCIE_EXT_BUSNUM_SHIFT 20
#define PCIE_EXT_SLOT_SHIFT 15
#define PCIE_EXT_FUNC_SHIFT 12
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
@ -695,15 +692,6 @@ static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
return dla && plu;
}
/* Configuration space read/write support */
static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
{
return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
| ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
| (busnr << PCIE_EXT_BUSNUM_SHIFT)
| (reg & ~3);
}
static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
int where)
{
@ -716,7 +704,7 @@ static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
return PCI_SLOT(devfn) ? NULL : base + where;
/* For devices, write to the config space index register */
idx = brcm_pcie_cfg_index(bus->number, devfn, 0);
idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0);
writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
return base + PCIE_EXT_CFG_DATA + where;
}
@ -893,6 +881,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
burst = 0x2; /* 512 bytes */
/* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
tmp = readl(base + PCIE_MISC_MISC_CTRL);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);

View File

@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/msi.h>
#include <linux/clk.h>
#include <linux/module.h>
@ -39,16 +40,8 @@
#define CFG_IND_ADDR_MASK 0x00001ffc
#define CFG_ADDR_BUS_NUM_SHIFT 20
#define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
#define CFG_ADDR_DEV_NUM_SHIFT 15
#define CFG_ADDR_DEV_NUM_MASK 0x000f8000
#define CFG_ADDR_FUNC_NUM_SHIFT 12
#define CFG_ADDR_FUNC_NUM_MASK 0x00007000
#define CFG_ADDR_REG_NUM_SHIFT 2
#define CFG_ADDR_REG_NUM_MASK 0x00000ffc
#define CFG_ADDR_CFG_TYPE_SHIFT 0
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
#define CFG_ADDR_CFG_TYPE_1 1
#define SYS_RC_INTX_MASK 0xf
@ -192,8 +185,15 @@ static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = {
.imap_window_offset = 0x4,
},
{
/* IARR1/IMAP1 (currently unused) */
.type = IPROC_PCIE_IB_MAP_INVALID,
/* IARR1/IMAP1 */
.type = IPROC_PCIE_IB_MAP_MEM,
.size_unit = SZ_1M,
.region_sizes = { 8 },
.nr_sizes = 1,
.nr_windows = 8,
.imap_addr_offset = 0x4,
.imap_window_offset = 0x8,
},
{
/* IARR2/IMAP2 */
@ -307,7 +307,7 @@ enum iproc_pcie_reg {
};
/* iProc PCIe PAXB BCMA registers */
static const u16 iproc_pcie_reg_paxb_bcma[] = {
static const u16 iproc_pcie_reg_paxb_bcma[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
@ -318,7 +318,7 @@ static const u16 iproc_pcie_reg_paxb_bcma[] = {
};
/* iProc PCIe PAXB registers */
static const u16 iproc_pcie_reg_paxb[] = {
static const u16 iproc_pcie_reg_paxb[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
@ -334,7 +334,7 @@ static const u16 iproc_pcie_reg_paxb[] = {
};
/* iProc PCIe PAXB v2 registers */
static const u16 iproc_pcie_reg_paxb_v2[] = {
static const u16 iproc_pcie_reg_paxb_v2[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
@ -351,6 +351,8 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
[IPROC_PCIE_OMAP3] = 0xdf8,
[IPROC_PCIE_IARR0] = 0xd00,
[IPROC_PCIE_IMAP0] = 0xc00,
[IPROC_PCIE_IARR1] = 0xd08,
[IPROC_PCIE_IMAP1] = 0xd70,
[IPROC_PCIE_IARR2] = 0xd10,
[IPROC_PCIE_IMAP2] = 0xcc0,
[IPROC_PCIE_IARR3] = 0xe00,
@ -363,7 +365,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
};
/* iProc PCIe PAXC v1 registers */
static const u16 iproc_pcie_reg_paxc[] = {
static const u16 iproc_pcie_reg_paxc[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_CLK_CTRL] = 0x000,
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
@ -372,7 +374,7 @@ static const u16 iproc_pcie_reg_paxc[] = {
};
/* iProc PCIe PAXC v2 registers */
static const u16 iproc_pcie_reg_paxc_v2[] = {
static const u16 iproc_pcie_reg_paxc_v2[IPROC_PCIE_MAX_NUM_REG] = {
[IPROC_PCIE_MSI_GIC_MODE] = 0x050,
[IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
[IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
@ -459,19 +461,15 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus,
static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie,
unsigned int busno,
unsigned int slot,
unsigned int fn,
unsigned int devfn,
int where)
{
u16 offset;
u32 val;
/* EP device access */
val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
(slot << CFG_ADDR_DEV_NUM_SHIFT) |
(fn << CFG_ADDR_FUNC_NUM_SHIFT) |
(where & CFG_ADDR_REG_NUM_MASK) |
(1 & CFG_ADDR_CFG_TYPE_MASK);
val = ALIGN_DOWN(PCIE_ECAM_OFFSET(busno, devfn, where), 4) |
CFG_ADDR_CFG_TYPE_1;
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val);
offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
@ -574,8 +572,6 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
struct iproc_pcie *pcie = iproc_data(bus);
unsigned int slot = PCI_SLOT(devfn);
unsigned int fn = PCI_FUNC(devfn);
unsigned int busno = bus->number;
void __iomem *cfg_data_p;
unsigned int data;
@ -590,7 +586,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
return ret;
}
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
if (!cfg_data_p)
return PCIBIOS_DEVICE_NOT_FOUND;
@ -631,13 +627,11 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
int busno, unsigned int devfn,
int where)
{
unsigned slot = PCI_SLOT(devfn);
unsigned fn = PCI_FUNC(devfn);
u16 offset;
/* root complex access */
if (busno == 0) {
if (slot > 0 || fn > 0)
if (PCIE_ECAM_DEVFN(devfn) > 0)
return NULL;
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
@ -649,7 +643,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
return (pcie->base + offset);
}
return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
return iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
}
static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus,
@ -1470,6 +1464,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
{
struct device *dev;
int ret;
struct pci_dev *pdev;
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
dev = pcie->dev;
@ -1533,6 +1528,11 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
goto err_power_off_phy;
}
for_each_pci_bridge(pdev, host->bus) {
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
pcie_print_link_status(pdev);
}
return 0;
err_power_off_phy:

View File

@ -50,9 +50,7 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
/* Structure representing the PCIe interface */
struct rcar_pcie_host {
struct rcar_pcie pcie;
struct device *dev;
struct phy *phy;
void __iomem *base;
struct clk *bus_clk;
struct rcar_msi msi;
int (*phy_init_fn)(struct rcar_pcie_host *host);

View File

@ -157,12 +157,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
struct pci_bus *bus, u32 devfn,
int where, int size, u32 *val)
{
u32 busdev;
void __iomem *addr;
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn), where);
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
if (!IS_ALIGNED(busdev, size)) {
if (!IS_ALIGNED((uintptr_t)addr, size)) {
*val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
}
@ -175,11 +174,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
AXI_WRAPPER_TYPE1_CFG);
if (size == 4) {
*val = readl(rockchip->reg_base + busdev);
*val = readl(addr);
} else if (size == 2) {
*val = readw(rockchip->reg_base + busdev);
*val = readw(addr);
} else if (size == 1) {
*val = readb(rockchip->reg_base + busdev);
*val = readb(addr);
} else {
*val = 0;
return PCIBIOS_BAD_REGISTER_NUMBER;
@ -191,11 +190,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
struct pci_bus *bus, u32 devfn,
int where, int size, u32 val)
{
u32 busdev;
void __iomem *addr;
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn), where);
if (!IS_ALIGNED(busdev, size))
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
if (!IS_ALIGNED((uintptr_t)addr, size))
return PCIBIOS_BAD_REGISTER_NUMBER;
if (pci_is_root_bus(bus->parent))
@ -206,11 +205,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
AXI_WRAPPER_TYPE1_CFG);
if (size == 4)
writel(val, rockchip->reg_base + busdev);
writel(val, addr);
else if (size == 2)
writew(val, rockchip->reg_base + busdev);
writew(val, addr);
else if (size == 1)
writeb(val, rockchip->reg_base + busdev);
writeb(val, addr);
else
return PCIBIOS_BAD_REGISTER_NUMBER;

View File

@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
/*
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
@ -178,13 +179,6 @@
#define MIN_AXI_ADDR_BITS_PASSED 8
#define PCIE_RC_SEND_PME_OFF 0x11960
#define ROCKCHIP_VENDOR_ID 0x1d87
#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20)
#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15)
#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12)
#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0)
#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
(PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
#define PCIE_LINK_IS_L2(x) \
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2)
#define PCIE_LINK_UP(x) \

View File

@ -208,7 +208,6 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn,
}
static const struct pci_ecam_ops smp8759_ecam_ops = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = smp8759_config_read,

View File

@ -18,6 +18,7 @@
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
#include <linux/irqchip/chained_irq.h>
@ -124,8 +125,6 @@
#define E_ECAM_CR_ENABLE BIT(0)
#define E_ECAM_SIZE_LOC GENMASK(20, 16)
#define E_ECAM_SIZE_SHIFT 16
#define ECAM_BUS_LOC_SHIFT 20
#define ECAM_DEV_LOC_SHIFT 12
#define NWL_ECAM_VALUE_DEFAULT 12
#define CFG_DMA_REG_BAR GENMASK(2, 0)
@ -240,15 +239,11 @@ static void __iomem *nwl_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
int where)
{
struct nwl_pcie *pcie = bus->sysdata;
int relbus;
if (!nwl_pcie_valid_device(bus, devfn))
return NULL;
relbus = (bus->number << ECAM_BUS_LOC_SHIFT) |
(devfn << ECAM_DEV_LOC_SHIFT);
return pcie->ecam_base + relbus + where;
return pcie->ecam_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
}
/* PCIe operations */

View File

@ -21,6 +21,7 @@
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
#include "../pci.h"
@ -86,10 +87,6 @@
/* Phy Status/Control Register definitions */
#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
/* ECAM definitions */
#define ECAM_BUS_NUM_SHIFT 20
#define ECAM_DEV_NUM_SHIFT 12
/* Number of MSI IRQs */
#define XILINX_NUM_MSI_IRQS 128
@ -183,15 +180,11 @@ static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
unsigned int devfn, int where)
{
struct xilinx_pcie_port *port = bus->sysdata;
int relbus;
if (!xilinx_pcie_valid_device(bus, devfn))
return NULL;
relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
(devfn << ECAM_DEV_NUM_SHIFT);
return port->reg_base + relbus + where;
return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
}
/* PCIe operations */

View File

@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/pci-ecam.h>
#include <linux/srcu.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
@ -52,6 +53,12 @@ enum vmd_features {
* vendor-specific capability space
*/
VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2),
/*
* Device may use MSI-X vector 0 for software triggering and will not
* be used for MSI remapping
*/
VMD_FEAT_OFFSET_FIRST_VECTOR = (1 << 3),
};
/*
@ -93,7 +100,7 @@ struct vmd_dev {
struct pci_dev *dev;
spinlock_t cfg_lock;
char __iomem *cfgbar;
void __iomem *cfgbar;
int msix_count;
struct vmd_irq_list *irqs;
@ -103,6 +110,7 @@ struct vmd_dev {
struct irq_domain *irq_domain;
struct pci_bus *bus;
u8 busn_start;
u8 first_vec;
};
static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
@ -198,11 +206,11 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
*/
static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
{
int i, best = 1;
unsigned long flags;
int i, best;
if (vmd->msix_count == 1)
return &vmd->irqs[0];
if (vmd->msix_count == 1 + vmd->first_vec)
return &vmd->irqs[vmd->first_vec];
/*
* White list for fast-interrupt handlers. All others will share the
@ -212,11 +220,12 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
case PCI_CLASS_STORAGE_EXPRESS:
break;
default:
return &vmd->irqs[0];
return &vmd->irqs[vmd->first_vec];
}
raw_spin_lock_irqsave(&list_lock, flags);
for (i = 1; i < vmd->msix_count; i++)
best = vmd->first_vec + 1;
for (i = best; i < vmd->msix_count; i++)
if (vmd->irqs[i].count < vmd->irqs[best].count)
best = i;
vmd->irqs[best].count++;
@ -324,18 +333,16 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd)
}
}
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
unsigned int devfn, int reg, int len)
{
char __iomem *addr = vmd->cfgbar +
((bus->number - vmd->busn_start) << 20) +
(devfn << 12) + reg;
unsigned int busnr_ecam = bus->number - vmd->busn_start;
u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
if ((addr - vmd->cfgbar) + len >=
resource_size(&vmd->dev->resource[VMD_CFGBAR]))
if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))
return NULL;
return addr;
return vmd->cfgbar + offset;
}
/*
@ -346,7 +353,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
int len, u32 *value)
{
struct vmd_dev *vmd = vmd_from_bus(bus);
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
unsigned long flags;
int ret = 0;
@ -381,7 +388,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
int len, u32 value)
{
struct vmd_dev *vmd = vmd_from_bus(bus);
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
unsigned long flags;
int ret = 0;
@ -549,8 +556,8 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
if (vmd->msix_count < 0)
return -ENODEV;
vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
PCI_IRQ_MSIX);
vmd->msix_count = pci_alloc_irq_vectors(dev, vmd->first_vec + 1,
vmd->msix_count, PCI_IRQ_MSIX);
if (vmd->msix_count < 0)
return vmd->msix_count;
@ -718,6 +725,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned long features = (unsigned long) id->driver_data;
struct vmd_dev *vmd;
int err;
@ -742,13 +750,16 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)))
return -ENODEV;
if (features & VMD_FEAT_OFFSET_FIRST_VECTOR)
vmd->first_vec = 1;
err = vmd_alloc_irqs(vmd);
if (err)
return err;
spin_lock_init(&vmd->cfg_lock);
pci_set_drvdata(dev, vmd);
err = vmd_enable_domain(vmd, (unsigned long) id->driver_data);
err = vmd_enable_domain(vmd, features);
if (err)
return err;
@ -817,13 +828,16 @@ static const struct pci_device_id vmd_ids[] = {
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
VMD_FEAT_HAS_BUS_RESTRICTIONS |
VMD_FEAT_OFFSET_FIRST_VECTOR,},
{0,}
};
MODULE_DEVICE_TABLE(pci, vmd_ids);

View File

@ -28,6 +28,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
struct resource *cfgres, struct resource *busr,
const struct pci_ecam_ops *ops)
{
unsigned int bus_shift = ops->bus_shift;
struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz;
struct resource *conflict;
@ -40,20 +41,24 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
if (!cfg)
return ERR_PTR(-ENOMEM);
/* ECAM-compliant platforms need not supply ops->bus_shift */
if (!bus_shift)
bus_shift = PCIE_ECAM_BUS_SHIFT;
cfg->parent = dev;
cfg->ops = ops;
cfg->busr.start = busr->start;
cfg->busr.end = busr->end;
cfg->busr.flags = IORESOURCE_BUS;
bus_range = resource_size(&cfg->busr);
bus_range_max = resource_size(cfgres) >> ops->bus_shift;
bus_range_max = resource_size(cfgres) >> bus_shift;
if (bus_range > bus_range_max) {
bus_range = bus_range_max;
cfg->busr.end = busr->start + bus_range - 1;
dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
cfgres, &cfg->busr, busr);
}
bsz = 1 << ops->bus_shift;
bsz = 1 << bus_shift;
cfg->res.start = cfgres->start;
cfg->res.end = cfgres->end;
@ -131,25 +136,36 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
int where)
{
struct pci_config_window *cfg = bus->sysdata;
unsigned int bus_shift = cfg->ops->bus_shift;
unsigned int devfn_shift = cfg->ops->bus_shift - 8;
unsigned int busn = bus->number;
void __iomem *base;
u32 bus_offset, devfn_offset;
if (busn < cfg->busr.start || busn > cfg->busr.end)
return NULL;
busn -= cfg->busr.start;
if (per_bus_mapping)
if (per_bus_mapping) {
base = cfg->winp[busn];
else
base = cfg->win + (busn << cfg->ops->bus_shift);
return base + (devfn << devfn_shift) + where;
busn = 0;
} else
base = cfg->win;
if (cfg->ops->bus_shift) {
bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift;
devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift;
where &= PCIE_ECAM_REG_MASK;
return base + (bus_offset | devfn_offset | where);
}
return base + PCIE_ECAM_OFFSET(busn, devfn, where);
}
EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */
const struct pci_ecam_ops pci_generic_ecam_ops = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read,
@ -161,7 +177,6 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
/* ECAM ops for 32-bit access only (non-compliant) */
const struct pci_ecam_ops pci_32b_ops = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,
@ -171,7 +186,6 @@ 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 = {
.bus_shift = 20,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read32,

View File

@ -294,7 +294,6 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
default:
err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
return -ENXIO;
break;
} /* end of switch */
} /* end of valid device */
} /* end of for */
@ -1509,7 +1508,6 @@ static int unconfigure_boot_card(struct slot *slot_cur)
default:
err("MAJOR PROBLEM!!!! Cannot read device's header\n");
return -1;
break;
} /* end of switch */
} /* end of valid device */
} /* end of for */

View File

@ -26,6 +26,8 @@
#include "pci.h"
#ifdef CONFIG_PCI_MSI
static int pci_msi_enable = 1;
int pci_msi_ignore_mask;
@ -410,6 +412,17 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
pci_intx(dev, enable);
}
static void pci_msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static void __pci_restore_msi_state(struct pci_dev *dev)
{
u16 control;
@ -432,6 +445,16 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 ctrl;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}
static void __pci_restore_msix_state(struct pci_dev *dev)
{
struct msi_desc *entry;
@ -600,11 +623,11 @@ static int msi_verify_entries(struct pci_dev *dev)
struct msi_desc *entry;
for_each_pci_msi_entry(entry, dev) {
if (!dev->no_64bit_msi || !entry->msg.address_hi)
continue;
pci_err(dev, "Device has broken 64-bit MSI but arch"
" tried to assign one above 4G\n");
return -EIO;
if (entry->msg.address_hi && dev->no_64bit_msi) {
pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n",
entry->msg.address_hi, entry->msg.address_lo);
return -EIO;
}
}
return 0;
}
@ -1577,3 +1600,40 @@ bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
}
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
#endif /* CONFIG_PCI_MSI */
void pci_msi_init(struct pci_dev *dev)
{
u16 ctrl;
/*
* Disable the MSI hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!dev->msi_cap)
return;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
if (ctrl & PCI_MSI_FLAGS_ENABLE)
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
ctrl & ~PCI_MSI_FLAGS_ENABLE);
if (!(ctrl & PCI_MSI_FLAGS_64BIT))
dev->no_64bit_msi = 1;
}
void pci_msix_init(struct pci_dev *dev)
{
u16 ctrl;
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!dev->msix_cap)
return;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
if (ctrl & PCI_MSIX_FLAGS_ENABLE)
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
ctrl & ~PCI_MSIX_FLAGS_ENABLE);
}

View File

@ -556,6 +556,11 @@ static int pci_parse_request_of_pci_ranges(struct device *dev,
break;
case IORESOURCE_MEM:
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
if (!(res->flags & IORESOURCE_PREFETCH))
if (upper_32_bits(resource_size(res)))
dev_warn(dev, "Memory resource size exceeds max for 32 bits\n");
break;
}
}

View File

@ -609,7 +609,7 @@ bool pci_has_p2pmem(struct pci_dev *pdev)
EXPORT_SYMBOL_GPL(pci_has_p2pmem);
/**
* pci_p2pmem_find - find a peer-to-peer DMA memory device compatible with
* pci_p2pmem_find_many - find a peer-to-peer DMA memory device compatible with
* the specified list of clients and shortest distance (as determined
* by pci_p2pmem_dma())
* @clients: array of devices to check (NULL-terminated)
@ -674,7 +674,7 @@ struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients)
EXPORT_SYMBOL_GPL(pci_p2pmem_find_many);
/**
* pci_alloc_p2p_mem - allocate peer-to-peer DMA memory
* pci_alloc_p2pmem - allocate peer-to-peer DMA memory
* @pdev: the device to allocate memory from
* @size: number of bytes to allocate
*
@ -727,7 +727,7 @@ void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
EXPORT_SYMBOL_GPL(pci_free_p2pmem);
/**
* pci_virt_to_bus - return the PCI bus address for a given virtual
* pci_p2pmem_virt_to_bus - return the PCI bus address for a given virtual
* address obtained with pci_alloc_p2pmem()
* @pdev: the device the memory was allocated from
* @addr: address of the memory that was allocated
@ -859,7 +859,7 @@ static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
}
/**
* pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
* pci_p2pdma_map_sg_attrs - map a PCI peer-to-peer scatterlist for DMA
* @dev: device doing the DMA request
* @sg: scatter list to map
* @nents: elements in the scatterlist
@ -896,7 +896,7 @@ int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs);
/**
* pci_p2pdma_unmap_sg - unmap a PCI peer-to-peer scatterlist that was
* pci_p2pdma_unmap_sg_attrs - unmap a PCI peer-to-peer scatterlist that was
* mapped with pci_p2pdma_map_sg()
* @dev: device doing the DMA request
* @sg: scatter list to map

View File

@ -1162,14 +1162,34 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
static struct acpi_device *acpi_pci_find_companion(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct acpi_device *adev;
bool check_children;
u64 addr;
check_children = pci_is_bridge(pci_dev);
/* Please ref to ACPI spec for the syntax of _ADR */
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
check_children);
/*
* There may be ACPI device objects in the ACPI namespace that are
* children of the device object representing the host bridge, but don't
* represent PCI devices. Both _HID and _ADR may be present for them,
* even though that is against the specification (for example, see
* Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which
* appears to indicate that they should not be taken into consideration
* as potential companions of PCI devices on the root bus.
*
* To catch this special case, disregard the returned device object if
* it has a valid _HID, addr is 0 and the PCI device at hand is on the
* root bus.
*/
if (adev && adev->pnp.type.platform_id && !addr &&
pci_is_root_bus(pci_dev->bus))
return NULL;
return adev;
}
/**

View File

@ -90,7 +90,80 @@ static void pci_free_dynids(struct pci_driver *drv)
}
/**
* store_new_id - sysfs frontend to pci_add_dynid()
* pci_match_id - See if a PCI device matches a given pci_id table
* @ids: array of PCI device ID structures to search in
* @dev: the PCI device structure to match against.
*
* Used by a driver to check whether a PCI device is in its list of
* supported devices. Returns the matching pci_device_id structure or
* %NULL if there is no match.
*
* Deprecated; don't use this as it will not catch any dynamic IDs
* that a driver might want to check for.
*/
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{
if (ids) {
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
}
}
return NULL;
}
EXPORT_SYMBOL(pci_match_id);
static const struct pci_device_id pci_device_id_any = {
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
};
/**
* pci_match_device - See if a device matches a driver's list of IDs
* @drv: the PCI driver to match against
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device is in its list of
* supported devices or in the dynids list, which may have been augmented
* via the sysfs "new_id" file. Returns the matching pci_device_id
* structure or %NULL if there is no match.
*/
static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
struct pci_dynid *dynid;
const struct pci_device_id *found_id = NULL;
/* When driver_override is set, only bind to the matching driver */
if (dev->driver_override && strcmp(dev->driver_override, drv->name))
return NULL;
/* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
found_id = &dynid->id;
break;
}
}
spin_unlock(&drv->dynids.lock);
if (!found_id)
found_id = pci_match_id(drv->id_table, dev);
/* driver_override will always match, send a dummy id */
if (!found_id && dev->driver_override)
found_id = &pci_device_id_any;
return found_id;
}
/**
* new_id_store - sysfs frontend to pci_add_dynid()
* @driver: target device driver
* @buf: buffer for scanning device ID data
* @count: input size
@ -125,7 +198,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
pdev->subsystem_device = subdevice;
pdev->class = class;
if (pci_match_id(pdrv->id_table, pdev))
if (pci_match_device(pdrv, pdev))
retval = -EEXIST;
kfree(pdev);
@ -158,7 +231,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
static DRIVER_ATTR_WO(new_id);
/**
* store_remove_id - remove a PCI device ID from this driver
* remove_id_store - remove a PCI device ID from this driver
* @driver: target device driver
* @buf: buffer for scanning device ID data
* @count: input size
@ -208,78 +281,6 @@ static struct attribute *pci_drv_attrs[] = {
};
ATTRIBUTE_GROUPS(pci_drv);
/**
* pci_match_id - See if a pci device matches a given pci_id table
* @ids: array of PCI device id structures to search in
* @dev: the PCI device structure to match against.
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*
* Deprecated, don't use this as it will not catch any dynamic ids
* that a driver might want to check for.
*/
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{
if (ids) {
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
}
}
return NULL;
}
EXPORT_SYMBOL(pci_match_id);
static const struct pci_device_id pci_device_id_any = {
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
};
/**
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
* @drv: the PCI driver to match against
* @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
struct pci_dynid *dynid;
const struct pci_device_id *found_id = NULL;
/* When driver_override is set, only bind to the matching driver */
if (dev->driver_override && strcmp(dev->driver_override, drv->name))
return NULL;
/* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
found_id = &dynid->id;
break;
}
}
spin_unlock(&drv->dynids.lock);
if (!found_id)
found_id = pci_match_id(drv->id_table, dev);
/* driver_override will always match, send a dummy id */
if (!found_id && dev->driver_override)
found_id = &pci_device_id_any;
return found_id;
}
struct drv_dev_and_id {
struct pci_driver *drv;
struct pci_dev *dev;

View File

@ -124,6 +124,15 @@ static ssize_t cpulistaffinity_show(struct device *dev,
}
static DEVICE_ATTR_RO(cpulistaffinity);
static ssize_t power_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf(buf, "%s\n", pci_power_name(pdev->current_state));
}
static DEVICE_ATTR_RO(power_state);
/* show resources */
static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
char *buf)
@ -581,6 +590,7 @@ static ssize_t driver_override_show(struct device *dev,
static DEVICE_ATTR_RW(driver_override);
static struct attribute *pci_dev_attrs[] = {
&dev_attr_power_state.attr,
&dev_attr_resource.attr,
&dev_attr_vendor.attr,
&dev_attr_device.attr,

View File

@ -399,8 +399,8 @@ found:
return 1;
}
static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
u8 pos, int cap, int *ttl)
static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
u8 pos, int cap, int *ttl)
{
u8 id;
u16 ent;
@ -423,22 +423,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
return 0;
}
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
u8 pos, int cap)
static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
u8 pos, int cap)
{
int ttl = PCI_FIND_CAP_TTL;
return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
}
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
{
return __pci_find_next_cap(dev->bus, dev->devfn,
pos + PCI_CAP_LIST_NEXT, cap);
}
EXPORT_SYMBOL_GPL(pci_find_next_capability);
static int __pci_bus_find_cap_start(struct pci_bus *bus,
static u8 __pci_bus_find_cap_start(struct pci_bus *bus,
unsigned int devfn, u8 hdr_type)
{
u16 status;
@ -477,9 +477,9 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus,
* %PCI_CAP_ID_PCIX PCI-X
* %PCI_CAP_ID_EXP PCI Express
*/
int pci_find_capability(struct pci_dev *dev, int cap)
u8 pci_find_capability(struct pci_dev *dev, int cap)
{
int pos;
u8 pos;
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
if (pos)
@ -502,10 +502,9 @@ EXPORT_SYMBOL(pci_find_capability);
* device's PCI configuration space or 0 in case the device does not
* support it.
*/
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
int pos;
u8 hdr_type;
u8 hdr_type, pos;
pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
@ -528,11 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability);
* not support it. Some capabilities can occur several times, e.g., the
* vendor-specific capability, and this provides a way to find them all.
*/
int pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap)
u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
{
u32 header;
int ttl;
int pos = PCI_CFG_SPACE_SIZE;
u16 pos = PCI_CFG_SPACE_SIZE;
/* minimum 8 bytes per capability */
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
@ -583,7 +582,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
* %PCI_EXT_CAP_ID_DSN Device Serial Number
* %PCI_EXT_CAP_ID_PWR Power Budgeting
*/
int pci_find_ext_capability(struct pci_dev *dev, int cap)
u16 pci_find_ext_capability(struct pci_dev *dev, int cap)
{
return pci_find_next_ext_capability(dev, 0, cap);
}
@ -623,7 +622,7 @@ u64 pci_get_dsn(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_get_dsn);
static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
{
int rc, ttl = PCI_FIND_CAP_TTL;
u8 cap, mask;
@ -650,11 +649,12 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
return 0;
}
/**
* pci_find_next_ht_capability - query a device's Hypertransport capabilities
* pci_find_next_ht_capability - query a device's HyperTransport capabilities
* @dev: PCI device to query
* @pos: Position from which to continue searching
* @ht_cap: Hypertransport capability code
* @ht_cap: HyperTransport capability code
*
* To be used in conjunction with pci_find_ht_capability() to search for
* all capabilities matching @ht_cap. @pos should always be a value returned
@ -663,26 +663,26 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
* NB. To be 100% safe against broken PCI devices, the caller should take
* steps to avoid an infinite loop.
*/
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap)
{
return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
}
EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
/**
* pci_find_ht_capability - query a device's Hypertransport capabilities
* pci_find_ht_capability - query a device's HyperTransport capabilities
* @dev: PCI device to query
* @ht_cap: Hypertransport capability code
* @ht_cap: HyperTransport capability code
*
* Tell if a device supports a given Hypertransport capability.
* Tell if a device supports a given HyperTransport capability.
* Returns an address within the device's PCI configuration space
* or 0 in case the device does not support the request capability.
* The address points to the PCI capability, of type PCI_CAP_ID_HT,
* which has a Hypertransport capability matching @ht_cap.
* which has a HyperTransport capability matching @ht_cap.
*/
int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
{
int pos;
u8 pos;
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
if (pos)
@ -1174,26 +1174,20 @@ int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
}
EXPORT_SYMBOL_GPL(pci_platform_power_transition);
/**
* pci_wakeup - Wake up a PCI device
* @pci_dev: Device to handle.
* @ign: ignored parameter
*/
static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
static int pci_resume_one(struct pci_dev *pci_dev, void *ign)
{
pci_wakeup_event(pci_dev);
pm_request_resume(&pci_dev->dev);
return 0;
}
/**
* pci_wakeup_bus - Walk given bus and wake up devices on it
* pci_resume_bus - Walk given bus and runtime resume devices on it
* @bus: Top bus of the subtree to walk.
*/
void pci_wakeup_bus(struct pci_bus *bus)
void pci_resume_bus(struct pci_bus *bus)
{
if (bus)
pci_walk_bus(bus, pci_wakeup, NULL);
pci_walk_bus(bus, pci_resume_one, NULL);
}
static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
@ -1256,7 +1250,7 @@ int pci_power_up(struct pci_dev *dev)
* may be powered on into D0uninitialized state, resume them to
* give them a chance to suspend again
*/
pci_wakeup_bus(dev->subordinate);
pci_resume_bus(dev->subordinate);
}
return pci_raw_set_power_state(dev, PCI_D0);
@ -1564,8 +1558,10 @@ int pci_save_state(struct pci_dev *dev)
return i;
pci_save_ltr_state(dev);
pci_save_aspm_l1ss_state(dev);
pci_save_dpc_state(dev);
pci_save_aer_state(dev);
pci_save_ptm_state(dev);
return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
@ -1669,6 +1665,7 @@ void pci_restore_state(struct pci_dev *dev)
* LTR itself (in the PCIe capability).
*/
pci_restore_ltr_state(dev);
pci_restore_aspm_l1ss_state(dev);
pci_restore_pcie_state(dev);
pci_restore_pasid_state(dev);
@ -1677,6 +1674,7 @@ void pci_restore_state(struct pci_dev *dev)
pci_restore_vc_state(dev);
pci_restore_rebar_state(dev);
pci_restore_dpc_state(dev);
pci_restore_ptm_state(dev);
pci_aer_clear_status(dev);
pci_restore_aer_state(dev);
@ -2606,12 +2604,24 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
if (target_state == PCI_POWER_ERROR)
return -EIO;
/*
* There are systems (for example, Intel mobile chips since Coffee
* Lake) where the power drawn while suspended can be significantly
* reduced by disabling PTM on PCIe root ports as this allows the
* port to enter a lower-power PM state and the SoC to reach a
* lower-power idle state as a whole.
*/
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
pci_disable_ptm(dev);
pci_enable_wake(dev, target_state, wakeup);
error = pci_set_power_state(dev, target_state);
if (error)
if (error) {
pci_enable_wake(dev, target_state, false);
pci_restore_ptm_state(dev);
}
return error;
}
@ -2649,12 +2659,23 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
dev->runtime_d3cold = target_state == PCI_D3cold;
/*
* There are systems (for example, Intel mobile chips since Coffee
* Lake) where the power drawn while suspended can be significantly
* reduced by disabling PTM on PCIe root ports as this allows the
* port to enter a lower-power PM state and the SoC to reach a
* lower-power idle state as a whole.
*/
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
pci_disable_ptm(dev);
__pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
error = pci_set_power_state(dev, target_state);
if (error) {
pci_enable_wake(dev, target_state, false);
pci_restore_ptm_state(dev);
dev->runtime_d3cold = false;
}
@ -3332,6 +3353,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error)
pci_err(dev, "unable to allocate suspend buffer for LTR\n");
error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
2 * sizeof(u32));
if (error)
pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n");
pci_allocate_vc_save_buffers(dev);
}
@ -3480,7 +3506,7 @@ bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
}
/**
* pci_acs_path_enable - test ACS flags from start to end in a hierarchy
* pci_acs_path_enabled - test ACS flags from start to end in a hierarchy
* @start: starting downstream device
* @end: ending upstream device or NULL to search to the root bus
* @acs_flags: required flags
@ -4188,7 +4214,14 @@ void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
}
size = resource_size(res);
name = res->name ?: dev_name(dev);
if (res->name)
name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
res->name);
else
name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
if (!name)
return IOMEM_ERR_PTR(-ENOMEM);
if (!devm_request_mem_region(dev, res->start, size, name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
@ -4317,7 +4350,7 @@ int pci_set_cacheline_size(struct pci_dev *dev)
if (cacheline_size == pci_cache_line_size)
return 0;
pci_info(dev, "cache line size of %d is not supported\n",
pci_dbg(dev, "cache line size of %d is not supported\n",
pci_cache_line_size << 2);
return -EINVAL;
@ -6202,19 +6235,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
while (*p) {
count = 0;
if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
p[count] == '@') {
p[count] == '@') {
p += count + 1;
if (align_order > 63) {
pr_err("PCI: Invalid requested alignment (order %d)\n",
align_order);
align_order = PAGE_SHIFT;
}
} else {
align_order = -1;
align_order = PAGE_SHIFT;
}
ret = pci_dev_str_match(dev, p, &p);
if (ret == 1) {
*resize = true;
if (align_order == -1)
align = PAGE_SIZE;
else
align = 1 << align_order;
align = 1ULL << align_order;
break;
} else if (ret < 0) {
pr_err("PCI: Can't parse resource_alignment parameter: %s\n",

View File

@ -104,6 +104,8 @@ void pci_config_pm_runtime_get(struct pci_dev *dev);
void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
void pci_ea_init(struct pci_dev *dev);
void pci_msi_init(struct pci_dev *dev);
void pci_msix_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
bool pci_bridge_d3_possible(struct pci_dev *dev);
@ -185,27 +187,6 @@ void pci_no_msi(void);
static inline void pci_no_msi(void) { }
#endif
static inline void pci_msi_set_enable(struct pci_dev *dev, int enable)
{
u16 control;
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_ENABLE;
if (enable)
control |= PCI_MSI_FLAGS_ENABLE;
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
}
static inline void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
{
u16 ctrl;
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
ctrl &= ~clear;
ctrl |= set;
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
}
void pci_realloc_get_opt(char *);
static inline int pci_no_d1d2(struct pci_dev *dev)
@ -294,7 +275,8 @@ void pci_bus_put(struct pci_bus *bus);
/* PCIe link information from Link Capabilities 2 */
#define PCIE_LNKCAP2_SLS2SPEED(lnkcap2) \
((lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \
((lnkcap2) & PCI_EXP_LNKCAP2_SLS_64_0GB ? PCIE_SPEED_64_0GT : \
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_16_0GB ? PCIE_SPEED_16_0GT : \
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_8_0GB ? PCIE_SPEED_8_0GT : \
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_5_0GB ? PCIE_SPEED_5_0GT : \
@ -303,7 +285,8 @@ void pci_bus_put(struct pci_bus *bus);
/* PCIe speed to Mb/s reduced by encoding overhead */
#define PCIE_SPEED2MBS_ENC(speed) \
((speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
((speed) == PCIE_SPEED_64_0GT ? 64000*128/130 : \
(speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
(speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
(speed) == PCIE_SPEED_8_0GT ? 8000*128/130 : \
(speed) == PCIE_SPEED_5_0GT ? 5000*8/10 : \
@ -448,6 +431,15 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
#endif /* CONFIG_PCIEAER */
#ifdef CONFIG_PCIEPORTBUS
/* Cached RCEC Endpoint Association */
struct rcec_ea {
u8 nextbusn;
u8 lastbusn;
u32 bitmap;
};
#endif
#ifdef CONFIG_PCIE_DPC
void pci_save_dpc_state(struct pci_dev *dev);
void pci_restore_dpc_state(struct pci_dev *dev);
@ -460,6 +452,22 @@ static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
static inline void pci_dpc_init(struct pci_dev *pdev) {}
#endif
#ifdef CONFIG_PCIEPORTBUS
void pci_rcec_init(struct pci_dev *dev);
void pci_rcec_exit(struct pci_dev *dev);
void pcie_link_rcec(struct pci_dev *rcec);
void pcie_walk_rcec(struct pci_dev *rcec,
int (*cb)(struct pci_dev *, void *),
void *userdata);
#else
static inline void pci_rcec_init(struct pci_dev *dev) {}
static inline void pci_rcec_exit(struct pci_dev *dev) {}
static inline void pcie_link_rcec(struct pci_dev *rcec) {}
static inline void pcie_walk_rcec(struct pci_dev *rcec,
int (*cb)(struct pci_dev *, void *),
void *userdata) {}
#endif
#ifdef CONFIG_PCI_ATS
/* Address Translation Service */
void pci_ats_init(struct pci_dev *dev);
@ -516,6 +524,16 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
#endif /* CONFIG_PCI_IOV */
#ifdef CONFIG_PCIE_PTM
void pci_save_ptm_state(struct pci_dev *dev);
void pci_restore_ptm_state(struct pci_dev *dev);
void pci_disable_ptm(struct pci_dev *dev);
#else
static inline void pci_save_ptm_state(struct pci_dev *dev) { }
static inline void pci_restore_ptm_state(struct pci_dev *dev) { }
static inline void pci_disable_ptm(struct pci_dev *dev) { }
#endif
unsigned long pci_cardbus_resource_alignment(struct resource *);
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
@ -555,8 +573,8 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
/* PCI error reporting and recovery */
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pci_channel_state_t state,
pci_ers_result_t (*reset_link)(struct pci_dev *pdev));
pci_channel_state_t state,
pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev));
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
#ifdef CONFIG_PCIEASPM
@ -564,11 +582,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
void pci_save_aspm_l1ss_state(struct pci_dev *dev);
void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
#else
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
#endif
#ifdef CONFIG_PCIE_ECRC

View File

@ -2,7 +2,7 @@
#
# Makefile for PCI Express features and port driver
pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o
pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o rcec.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o

View File

@ -300,7 +300,8 @@ int pci_aer_raw_clear_status(struct pci_dev *dev)
return -EIO;
port_type = pci_pcie_type(dev);
if (port_type == PCI_EXP_TYPE_ROOT_PORT) {
if (port_type == PCI_EXP_TYPE_ROOT_PORT ||
port_type == PCI_EXP_TYPE_RC_EC) {
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &status);
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, status);
}
@ -595,7 +596,8 @@ static umode_t aer_stats_attrs_are_visible(struct kobject *kobj,
if ((a == &dev_attr_aer_rootport_total_err_cor.attr ||
a == &dev_attr_aer_rootport_total_err_fatal.attr ||
a == &dev_attr_aer_rootport_total_err_nonfatal.attr) &&
pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT)
((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
(pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC)))
return 0;
return a->mode;
@ -916,7 +918,10 @@ static bool find_source_device(struct pci_dev *parent,
if (result)
return true;
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
if (pci_pcie_type(parent) == PCI_EXP_TYPE_RC_EC)
pcie_walk_rcec(parent, find_device_iter, e_info);
else
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
if (!e_info->error_dev_num) {
pci_info(parent, "can't find device of ID%04x\n", e_info->id);
@ -1034,6 +1039,7 @@ EXPORT_SYMBOL_GPL(aer_recover_queue);
*/
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
{
int type = pci_pcie_type(dev);
int aer = dev->aer_cap;
int temp;
@ -1052,8 +1058,9 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
&info->mask);
if (!(info->status & ~info->mask))
return 0;
} else if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
} else if (type == PCI_EXP_TYPE_ROOT_PORT ||
type == PCI_EXP_TYPE_RC_EC ||
type == PCI_EXP_TYPE_DOWNSTREAM ||
info->severity == AER_NONFATAL) {
/* Link is still healthy for IO reads */
@ -1205,6 +1212,7 @@ static int set_device_error_reporting(struct pci_dev *dev, void *data)
int type = pci_pcie_type(dev);
if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
(type == PCI_EXP_TYPE_RC_EC) ||
(type == PCI_EXP_TYPE_UPSTREAM) ||
(type == PCI_EXP_TYPE_DOWNSTREAM)) {
if (enable)
@ -1229,9 +1237,12 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
{
set_device_error_reporting(dev, &enable);
if (!dev->subordinate)
return;
pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
pcie_walk_rcec(dev, set_device_error_reporting, &enable);
else if (dev->subordinate)
pci_walk_bus(dev->subordinate, set_device_error_reporting,
&enable);
}
/**
@ -1329,6 +1340,11 @@ static int aer_probe(struct pcie_device *dev)
struct device *device = &dev->device;
struct pci_dev *port = dev->port;
/* Limit to Root Ports or Root Complex Event Collectors */
if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
(pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
return -ENODEV;
rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL);
if (!rpc)
return -ENOMEM;
@ -1350,41 +1366,74 @@ static int aer_probe(struct pcie_device *dev)
}
/**
* aer_root_reset - reset link on Root Port
* @dev: pointer to Root Port's pci_dev data structure
* aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
* @dev: pointer to Root Port, RCEC, or RCiEP
*
* Invoked by Port Bus driver when performing link reset at Root Port.
* Invoked by Port Bus driver when performing reset.
*/
static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
{
int aer = dev->aer_cap;
int type = pci_pcie_type(dev);
struct pci_dev *root;
int aer;
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
u32 reg32;
int rc;
/*
* Only Root Ports and RCECs have AER Root Command and Root Status
* registers. If "dev" is an RCiEP, the relevant registers are in
* the RCEC.
*/
if (type == PCI_EXP_TYPE_RC_END)
root = dev->rcec;
else
root = dev;
/* Disable Root's interrupt in response to error messages */
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);
/*
* If the platform retained control of AER, an RCiEP may not have
* an RCEC visible to us, so dev->rcec ("root") may be NULL. In
* that case, firmware is responsible for these registers.
*/
aer = root ? root->aer_cap : 0;
rc = pci_bus_error_reset(dev);
pci_info(dev, "Root Port link has been reset\n");
if ((host->native_aer || pcie_ports_native) && aer) {
/* Disable Root's interrupt in response to error messages */
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
}
/* Clear Root Error Status */
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &reg32);
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, reg32);
if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {
if (pcie_has_flr(dev)) {
rc = pcie_flr(dev);
pci_info(dev, "has been reset (%d)\n", rc);
} else {
pci_info(dev, "not reset (no FLR support)\n");
rc = -ENOTTY;
}
} else {
rc = pci_bus_error_reset(dev);
pci_info(dev, "Root Port link has been reset (%d)\n", rc);
}
/* Enable Root Port's interrupt in response to error messages */
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);
if ((host->native_aer || pcie_ports_native) && aer) {
/* Clear Root Error Status */
pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, &reg32);
pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32);
/* Enable Root Port's interrupt in response to error messages */
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, &reg32);
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
}
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
static struct pcie_port_service_driver aerdriver = {
.name = "aer",
.port_type = PCI_EXP_TYPE_ROOT_PORT,
.port_type = PCIE_ANY_PORT,
.service = PCIE_PORT_SERVICE_AER,
.probe = aer_probe,

View File

@ -333,8 +333,11 @@ static int aer_inject(struct aer_error_inj *einj)
if (!dev)
return -ENODEV;
rpdev = pcie_find_root_port(dev);
/* If Root Port not found, try to find an RCEC */
if (!rpdev)
rpdev = dev->rcec;
if (!rpdev) {
pci_err(dev, "Root port not found\n");
pci_err(dev, "Neither Root Port nor RCEC found\n");
ret = -ENODEV;
goto out_put;
}

View File

@ -734,6 +734,50 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
PCI_L1SS_CTL1_L1SS_MASK, val);
}
void pci_save_aspm_l1ss_state(struct pci_dev *dev)
{
int aspm_l1ss;
struct pci_cap_saved_state *save_state;
u32 *cap;
if (!pci_is_pcie(dev))
return;
aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
if (!aspm_l1ss)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
if (!save_state)
return;
cap = (u32 *)&save_state->cap.data[0];
pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, cap++);
pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, cap++);
}
void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
{
int aspm_l1ss;
struct pci_cap_saved_state *save_state;
u32 *cap;
if (!pci_is_pcie(dev))
return;
aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
if (!aspm_l1ss)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
if (!save_state)
return;
cap = (u32 *)&save_state->cap.data[0];
pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, *cap++);
pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, *cap++);
}
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,

View File

@ -146,38 +146,71 @@ out:
return 0;
}
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pci_channel_state_t state,
pci_ers_result_t (*reset_link)(struct pci_dev *pdev))
/**
* pci_walk_bridge - walk bridges potentially AER affected
* @bridge: bridge which may be a Port, an RCEC, or an RCiEP
* @cb: callback to be called for each device found
* @userdata: arbitrary pointer to be passed to callback
*
* If the device provided is a bridge, walk the subordinate bus, including
* any bridged devices on buses under this bus. Call the provided callback
* on each device found.
*
* If the device provided has no subordinate bus, e.g., an RCEC or RCiEP,
* call the callback on the device itself.
*/
static void pci_walk_bridge(struct pci_dev *bridge,
int (*cb)(struct pci_dev *, void *),
void *userdata)
{
if (bridge->subordinate)
pci_walk_bus(bridge->subordinate, cb, userdata);
else
cb(bridge, userdata);
}
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pci_channel_state_t state,
pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev))
{
int type = pci_pcie_type(dev);
struct pci_dev *bridge;
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
struct pci_bus *bus;
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
/*
* Error recovery runs on all subordinates of the first downstream port.
* If the downstream port detected the error, it is cleared at the end.
* If the error was detected by a Root Port, Downstream Port, RCEC,
* or RCiEP, recovery runs on the device itself. For Ports, that
* also includes any subordinate devices.
*
* If it was detected by another device (Endpoint, etc), recovery
* runs on the device and anything else under the same Port, i.e.,
* everything under "bridge".
*/
if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
dev = dev->bus->self;
bus = dev->subordinate;
if (type == PCI_EXP_TYPE_ROOT_PORT ||
type == PCI_EXP_TYPE_DOWNSTREAM ||
type == PCI_EXP_TYPE_RC_EC ||
type == PCI_EXP_TYPE_RC_END)
bridge = dev;
else
bridge = pci_upstream_bridge(dev);
pci_dbg(dev, "broadcast error_detected message\n");
pci_dbg(bridge, "broadcast error_detected message\n");
if (state == pci_channel_io_frozen) {
pci_walk_bus(bus, report_frozen_detected, &status);
status = reset_link(dev);
pci_walk_bridge(bridge, report_frozen_detected, &status);
status = reset_subordinates(bridge);
if (status != PCI_ERS_RESULT_RECOVERED) {
pci_warn(dev, "link reset failed\n");
pci_warn(bridge, "subordinate device reset failed\n");
goto failed;
}
} else {
pci_walk_bus(bus, report_normal_detected, &status);
pci_walk_bridge(bridge, report_normal_detected, &status);
}
if (status == PCI_ERS_RESULT_CAN_RECOVER) {
status = PCI_ERS_RESULT_RECOVERED;
pci_dbg(dev, "broadcast mmio_enabled message\n");
pci_walk_bus(bus, report_mmio_enabled, &status);
pci_dbg(bridge, "broadcast mmio_enabled message\n");
pci_walk_bridge(bridge, report_mmio_enabled, &status);
}
if (status == PCI_ERS_RESULT_NEED_RESET) {
@ -187,27 +220,35 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
* drivers' slot_reset callbacks?
*/
status = PCI_ERS_RESULT_RECOVERED;
pci_dbg(dev, "broadcast slot_reset message\n");
pci_walk_bus(bus, report_slot_reset, &status);
pci_dbg(bridge, "broadcast slot_reset message\n");
pci_walk_bridge(bridge, report_slot_reset, &status);
}
if (status != PCI_ERS_RESULT_RECOVERED)
goto failed;
pci_dbg(dev, "broadcast resume message\n");
pci_walk_bus(bus, report_resume, &status);
pci_dbg(bridge, "broadcast resume message\n");
pci_walk_bridge(bridge, report_resume, &status);
if (pcie_aer_is_native(dev))
pcie_clear_device_status(dev);
pci_aer_clear_nonfatal_status(dev);
pci_info(dev, "device recovery successful\n");
/*
* If we have native control of AER, clear error status in the Root
* Port or Downstream Port that signaled the error. If the
* platform retained control of AER, it is responsible for clearing
* this status. In that case, the signaling device may not even be
* visible to the OS.
*/
if (host->native_aer || pcie_ports_native) {
pcie_clear_device_status(bridge);
pci_aer_clear_nonfatal_status(bridge);
}
pci_info(bridge, "device recovery successful\n");
return status;
failed:
pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
/* TODO: Should kernel panic here? */
pci_info(dev, "device recovery failed\n");
pci_info(bridge, "device recovery failed\n");
return status;
}

View File

@ -310,7 +310,10 @@ static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
static void pcie_pme_mark_devices(struct pci_dev *port)
{
pcie_pme_can_wakeup(port, NULL);
if (port->subordinate)
if (pci_pcie_type(port) == PCI_EXP_TYPE_RC_EC)
pcie_walk_rcec(port, pcie_pme_can_wakeup, NULL);
else if (port->subordinate)
pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
}
@ -320,10 +323,16 @@ static void pcie_pme_mark_devices(struct pci_dev *port)
*/
static int pcie_pme_probe(struct pcie_device *srv)
{
struct pci_dev *port;
struct pci_dev *port = srv->port;
struct pcie_pme_service_data *data;
int type = pci_pcie_type(port);
int ret;
/* Limit to Root Ports or Root Complex Event Collectors */
if (type != PCI_EXP_TYPE_RC_EC &&
type != PCI_EXP_TYPE_ROOT_PORT)
return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@ -333,7 +342,6 @@ static int pcie_pme_probe(struct pcie_device *srv)
data->srv = srv;
set_service_data(srv, data);
port = srv->port;
pcie_pme_interrupt_enable(port, false);
pcie_clear_root_pme_status(port);
@ -445,7 +453,7 @@ static void pcie_pme_remove(struct pcie_device *srv)
static struct pcie_port_service_driver pcie_pme_driver = {
.name = "pcie_pme",
.port_type = PCI_EXP_TYPE_ROOT_PORT,
.port_type = PCIE_ANY_PORT,
.service = PCIE_PORT_SERVICE_PME,
.probe = pcie_pme_probe,

View File

@ -233,12 +233,9 @@ static int get_port_device_capability(struct pci_dev *dev)
}
#endif
/*
* Root ports are capable of generating PME too. Root Complex
* Event Collectors can also generate PMEs, but we don't handle
* those yet.
*/
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT &&
/* Root Ports and Root Complex Event Collectors may generate PMEs */
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC) &&
(pcie_ports_native || host->native_pme)) {
services |= PCIE_PORT_SERVICE_PME;

View File

@ -101,14 +101,19 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
static int pcie_portdrv_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
int type = pci_pcie_type(dev);
int status;
if (!pci_is_pcie(dev) ||
((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
(pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
(pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
((type != PCI_EXP_TYPE_ROOT_PORT) &&
(type != PCI_EXP_TYPE_UPSTREAM) &&
(type != PCI_EXP_TYPE_DOWNSTREAM) &&
(type != PCI_EXP_TYPE_RC_EC)))
return -ENODEV;
if (type == PCI_EXP_TYPE_RC_EC)
pcie_link_rcec(dev);
status = pcie_port_device_register(dev);
if (status)
return status;
@ -195,6 +200,8 @@ static const struct pci_device_id port_pci_ids[] = {
{ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0) },
/* subtractive decode PCI-to-PCI bridge, class type is 060401h */
{ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x01), ~0) },
/* handle any Root Complex Event Collector */
{ PCI_DEVICE_CLASS(((PCI_CLASS_SYSTEM_RCEC << 8) | 0x00), ~0) },
{ },
};

View File

@ -29,6 +29,64 @@ static void pci_ptm_info(struct pci_dev *dev)
dev->ptm_root ? " (root)" : "", clock_desc);
}
void pci_disable_ptm(struct pci_dev *dev)
{
int ptm;
u16 ctrl;
if (!pci_is_pcie(dev))
return;
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
if (!ptm)
return;
pci_read_config_word(dev, ptm + PCI_PTM_CTRL, &ctrl);
ctrl &= ~(PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT);
pci_write_config_word(dev, ptm + PCI_PTM_CTRL, ctrl);
}
void pci_save_ptm_state(struct pci_dev *dev)
{
int ptm;
struct pci_cap_saved_state *save_state;
u16 *cap;
if (!pci_is_pcie(dev))
return;
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
if (!ptm)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
if (!save_state) {
pci_err(dev, "no suspend buffer for PTM\n");
return;
}
cap = (u16 *)&save_state->cap.data[0];
pci_read_config_word(dev, ptm + PCI_PTM_CTRL, cap);
}
void pci_restore_ptm_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
int ptm;
u16 *cap;
if (!pci_is_pcie(dev))
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
if (!save_state || !ptm)
return;
cap = (u16 *)&save_state->cap.data[0];
pci_write_config_word(dev, ptm + PCI_PTM_CTRL, *cap);
}
void pci_ptm_init(struct pci_dev *dev)
{
int pos;
@ -65,6 +123,8 @@ void pci_ptm_init(struct pci_dev *dev)
if (!pos)
return;
pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u16));
pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;

190
drivers/pci/pcie/rcec.c Normal file
View File

@ -0,0 +1,190 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Root Complex Event Collector Support
*
* Authors:
* Sean V Kelley <sean.v.kelley@intel.com>
* Qiuxu Zhuo <qiuxu.zhuo@intel.com>
*
* Copyright (C) 2020 Intel Corp.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include "../pci.h"
struct walk_rcec_data {
struct pci_dev *rcec;
int (*user_callback)(struct pci_dev *dev, void *data);
void *user_data;
};
static bool rcec_assoc_rciep(struct pci_dev *rcec, struct pci_dev *rciep)
{
unsigned long bitmap = rcec->rcec_ea->bitmap;
unsigned int devn;
/* An RCiEP found on a different bus in range */
if (rcec->bus->number != rciep->bus->number)
return true;
/* Same bus, so check bitmap */
for_each_set_bit(devn, &bitmap, 32)
if (devn == rciep->devfn)
return true;
return false;
}
static int link_rcec_helper(struct pci_dev *dev, void *data)
{
struct walk_rcec_data *rcec_data = data;
struct pci_dev *rcec = rcec_data->rcec;
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) &&
rcec_assoc_rciep(rcec, dev)) {
dev->rcec = rcec;
pci_dbg(dev, "PME & error events signaled via %s\n",
pci_name(rcec));
}
return 0;
}
static int walk_rcec_helper(struct pci_dev *dev, void *data)
{
struct walk_rcec_data *rcec_data = data;
struct pci_dev *rcec = rcec_data->rcec;
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) &&
rcec_assoc_rciep(rcec, dev))
rcec_data->user_callback(dev, rcec_data->user_data);
return 0;
}
static void walk_rcec(int (*cb)(struct pci_dev *dev, void *data),
void *userdata)
{
struct walk_rcec_data *rcec_data = userdata;
struct pci_dev *rcec = rcec_data->rcec;
u8 nextbusn, lastbusn;
struct pci_bus *bus;
unsigned int bnr;
if (!rcec->rcec_ea)
return;
/* Walk own bus for bitmap based association */
pci_walk_bus(rcec->bus, cb, rcec_data);
nextbusn = rcec->rcec_ea->nextbusn;
lastbusn = rcec->rcec_ea->lastbusn;
/* All RCiEP devices are on the same bus as the RCEC */
if (nextbusn == 0xff && lastbusn == 0x00)
return;
for (bnr = nextbusn; bnr <= lastbusn; bnr++) {
/* No association indicated (PCIe 5.0-1, 7.9.10.3) */
if (bnr == rcec->bus->number)
continue;
bus = pci_find_bus(pci_domain_nr(rcec->bus), bnr);
if (!bus)
continue;
/* Find RCiEP devices on the given bus ranges */
pci_walk_bus(bus, cb, rcec_data);
}
}
/**
* pcie_link_rcec - Link RCiEP devices associated with RCEC.
* @rcec: RCEC whose RCiEP devices should be linked.
*
* Link the given RCEC to each RCiEP device found.
*/
void pcie_link_rcec(struct pci_dev *rcec)
{
struct walk_rcec_data rcec_data;
if (!rcec->rcec_ea)
return;
rcec_data.rcec = rcec;
rcec_data.user_callback = NULL;
rcec_data.user_data = NULL;
walk_rcec(link_rcec_helper, &rcec_data);
}
/**
* pcie_walk_rcec - Walk RCiEP devices associating with RCEC and call callback.
* @rcec: RCEC whose RCiEP devices should be walked
* @cb: Callback to be called for each RCiEP device found
* @userdata: Arbitrary pointer to be passed to callback
*
* Walk the given RCEC. Call the callback on each RCiEP found.
*
* If @cb returns anything other than 0, break out.
*/
void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
void *userdata)
{
struct walk_rcec_data rcec_data;
if (!rcec->rcec_ea)
return;
rcec_data.rcec = rcec;
rcec_data.user_callback = cb;
rcec_data.user_data = userdata;
walk_rcec(walk_rcec_helper, &rcec_data);
}
void pci_rcec_init(struct pci_dev *dev)
{
struct rcec_ea *rcec_ea;
u32 rcec, hdr, busn;
u8 ver;
/* Only for Root Complex Event Collectors */
if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_EC)
return;
rcec = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_RCEC);
if (!rcec)
return;
rcec_ea = kzalloc(sizeof(*rcec_ea), GFP_KERNEL);
if (!rcec_ea)
return;
pci_read_config_dword(dev, rcec + PCI_RCEC_RCIEP_BITMAP,
&rcec_ea->bitmap);
/* Check whether RCEC BUSN register is present */
pci_read_config_dword(dev, rcec, &hdr);
ver = PCI_EXT_CAP_VER(hdr);
if (ver >= PCI_RCEC_BUSN_REG_VER) {
pci_read_config_dword(dev, rcec + PCI_RCEC_BUSN, &busn);
rcec_ea->nextbusn = PCI_RCEC_BUSN_NEXT(busn);
rcec_ea->lastbusn = PCI_RCEC_BUSN_LAST(busn);
} else {
/* Avoid later ver check by setting nextbusn */
rcec_ea->nextbusn = 0xff;
rcec_ea->lastbusn = 0x00;
}
dev->rcec_ea = rcec_ea;
}
void pci_rcec_exit(struct pci_dev *dev)
{
kfree(dev->rcec_ea);
dev->rcec_ea = NULL;
}

View File

@ -165,7 +165,7 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
#define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
/**
* pci_read_base - Read a PCI BAR
* __pci_read_base - Read a PCI BAR
* @dev: the PCI device
* @type: type of the BAR
* @res: resource buffer to be filled in
@ -677,7 +677,7 @@ const unsigned char pcie_link_speed[] = {
PCIE_SPEED_8_0GT, /* 3 */
PCIE_SPEED_16_0GT, /* 4 */
PCIE_SPEED_32_0GT, /* 5 */
PCI_SPEED_UNKNOWN, /* 6 */
PCIE_SPEED_64_0GT, /* 6 */
PCI_SPEED_UNKNOWN, /* 7 */
PCI_SPEED_UNKNOWN, /* 8 */
PCI_SPEED_UNKNOWN, /* 9 */
@ -719,6 +719,7 @@ const char *pci_speed_string(enum pci_bus_speed speed)
"8.0 GT/s PCIe", /* 0x16 */
"16.0 GT/s PCIe", /* 0x17 */
"32.0 GT/s PCIe", /* 0x18 */
"64.0 GT/s PCIe", /* 0x19 */
};
if (speed < ARRAY_SIZE(speed_strings))
@ -1612,7 +1613,7 @@ static bool pci_ext_cfg_is_aliased(struct pci_dev *dev)
}
/**
* pci_cfg_space_size - Get the configuration space size of the PCI device
* pci_cfg_space_size_ext - Get the configuration space size of the PCI device
* @dev: PCI device
*
* Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
@ -1716,22 +1717,6 @@ static u8 pci_hdr_type(struct pci_dev *dev)
#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
static void pci_msi_setup_pci_dev(struct pci_dev *dev)
{
/*
* Disable the MSI hardware to avoid screaming interrupts
* during boot. This is the power on reset default so
* usually this should be a noop.
*/
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (dev->msi_cap)
pci_msi_set_enable(dev, 0);
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (dev->msix_cap)
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
}
/**
* pci_intx_mask_broken - Test PCI_COMMAND_INTX_DISABLE writability
* @dev: PCI device
@ -2216,6 +2201,7 @@ static void pci_configure_device(struct pci_dev *dev)
static void pci_release_capabilities(struct pci_dev *dev)
{
pci_aer_exit(dev);
pci_rcec_exit(dev);
pci_vpd_release(dev);
pci_iov_release(dev);
pci_free_cap_save_buffers(dev);
@ -2397,9 +2383,8 @@ void pcie_report_downtraining(struct pci_dev *dev)
static void pci_init_capabilities(struct pci_dev *dev)
{
pci_ea_init(dev); /* Enhanced Allocation */
/* Setup MSI caps & disable MSI/MSI-X interrupts */
pci_msi_setup_pci_dev(dev);
pci_msi_init(dev); /* Disable MSI */
pci_msix_init(dev); /* Disable MSI-X */
/* Buffers for saving PCIe and PCI-X capabilities */
pci_allocate_cap_save_buffers(dev);
@ -2415,6 +2400,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_ptm_init(dev); /* Precision Time Measurement */
pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */
pci_rcec_init(dev); /* Root Complex Event Collector */
pcie_report_downtraining(dev);

View File

@ -2356,9 +2356,9 @@ static void quirk_enable_clear_retrain_link(struct pci_dev *dev)
dev->clear_retrain_link = 1;
pci_info(dev, "Enable PCIe Retrain Link quirk\n");
}
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe110, quirk_enable_clear_retrain_link);
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe111, quirk_enable_clear_retrain_link);
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe130, quirk_enable_clear_retrain_link);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe110, quirk_enable_clear_retrain_link);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe111, quirk_enable_clear_retrain_link);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe130, quirk_enable_clear_retrain_link);
static void fixup_rev1_53c810(struct pci_dev *dev)
{
@ -2522,6 +2522,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SAMSUNG, 0xa5e3, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
static void quirk_disable_msi(struct pci_dev *dev)
@ -3998,6 +3999,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9183,
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
quirk_dma_func1_alias);
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c135 */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9215,
quirk_dma_func1_alias);
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220,
quirk_dma_func1_alias);
@ -5164,6 +5168,18 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
(pdev->device == 0x7340 && pdev->revision != 0xc5))
return;
if (pdev->device == 0x15d8) {
if (pdev->revision == 0xcf &&
pdev->subsystem_vendor == 0xea50 &&
(pdev->subsystem_device == 0xce19 ||
pdev->subsystem_device == 0xcc10 ||
pdev->subsystem_device == 0xcc08))
goto no_ats;
else
return;
}
no_ats:
pci_info(pdev, "disabling ATS\n");
pdev->ats_cap = 0;
}
@ -5176,6 +5192,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
/* AMD Navi14 dGPU */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
/* AMD Raven platform iGPU */
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
#endif /* CONFIG_PCI_ATS */
/* Freescale PCIe doesn't support MSI in RC mode */
@ -5567,17 +5585,26 @@ static void pci_fixup_no_d0_pme(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASMEDIA, 0x2142, pci_fixup_no_d0_pme);
/*
* Device [12d8:0x400e] and [12d8:0x400f]
* Device 12d8:0x400e [OHCI] and 12d8:0x400f [EHCI]
*
* These devices advertise PME# support in all power states but don't
* reliably assert it.
*
* These devices also advertise MSI, but documentation (PI7C9X440SL.pdf)
* says "The MSI Function is not implemented on this device" in chapters
* 7.3.27, 7.3.29-7.3.31.
*/
static void pci_fixup_no_pme(struct pci_dev *dev)
static void pci_fixup_no_msi_no_pme(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_MSI
pci_info(dev, "MSI is not implemented on this device, disabling it\n");
dev->no_msi = 1;
#endif
pci_info(dev, "PME# is unreliable, disabling it\n");
dev->pme_support = 0;
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400e, pci_fixup_no_pme);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400f, pci_fixup_no_pme);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400e, pci_fixup_no_msi_no_pme);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400f, pci_fixup_no_msi_no_pme);
static void apex_pci_fixup_class(struct pci_dev *pdev)
{

View File

@ -272,6 +272,9 @@ placeholder:
goto err;
}
INIT_LIST_HEAD(&slot->list);
list_add(&slot->list, &parent->slots);
err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
"%s", slot_name);
if (err) {
@ -279,9 +282,6 @@ placeholder:
goto err;
}
INIT_LIST_HEAD(&slot->list);
list_add(&slot->list, &parent->slots);
down_read(&pci_bus_sem);
list_for_each_entry(dev, &parent->devices, bus_list)
if (PCI_SLOT(dev->devfn) == slot_nr)
@ -323,7 +323,7 @@ EXPORT_SYMBOL_GPL(pci_destroy_slot);
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
#include <linux/pci_hotplug.h>
/**
* pci_hp_create_link - create symbolic link to the hotplug driver module.
* pci_hp_create_module_link - create symbolic link to hotplug driver module
* @pci_slot: struct pci_slot
*
* Helper function for pci_hotplug_core.c to create symbolic link to
@ -349,7 +349,8 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
/**
* pci_hp_remove_link - remove symbolic link to the hotplug driver module.
* pci_hp_remove_module_link - remove symbolic link to the hotplug driver
* module.
* @pci_slot: struct pci_slot
*
* Helper function for pci_hotplug_core.c to remove symbolic link to

View File

@ -9,6 +9,33 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
/*
* Memory address shift values for the byte-level address that
* can be used when accessing the PCI Express Configuration Space.
*/
/*
* Enhanced Configuration Access Mechanism (ECAM)
*
* See PCI Express Base Specification, Revision 5.0, Version 1.0,
* Section 7.2.2, Table 7-1, p. 677.
*/
#define PCIE_ECAM_BUS_SHIFT 20 /* Bus number */
#define PCIE_ECAM_DEVFN_SHIFT 12 /* Device and Function number */
#define PCIE_ECAM_BUS_MASK 0xff
#define PCIE_ECAM_DEVFN_MASK 0xff
#define PCIE_ECAM_REG_MASK 0xfff /* Limit offset to a maximum of 4K */
#define PCIE_ECAM_BUS(x) (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT)
#define PCIE_ECAM_DEVFN(x) (((x) & PCIE_ECAM_DEVFN_MASK) << PCIE_ECAM_DEVFN_SHIFT)
#define PCIE_ECAM_REG(x) ((x) & PCIE_ECAM_REG_MASK)
#define PCIE_ECAM_OFFSET(bus, devfn, where) \
(PCIE_ECAM_BUS(bus) | \
PCIE_ECAM_DEVFN(devfn) | \
PCIE_ECAM_REG(where))
/*
* struct to hold pci ops and bus shift of the config window
* for a PCI controller.

View File

@ -281,6 +281,7 @@ enum pci_bus_speed {
PCIE_SPEED_8_0GT = 0x16,
PCIE_SPEED_16_0GT = 0x17,
PCIE_SPEED_32_0GT = 0x18,
PCIE_SPEED_64_0GT = 0x19,
PCI_SPEED_UNKNOWN = 0xff,
};
@ -304,6 +305,7 @@ struct pcie_link_state;
struct pci_vpd;
struct pci_sriov;
struct pci_p2pdma;
struct rcec_ea;
/* The pci_dev structure describes PCI devices */
struct pci_dev {
@ -326,6 +328,10 @@ struct pci_dev {
#ifdef CONFIG_PCIEAER
u16 aer_cap; /* AER capability offset */
struct aer_stats *aer_stats; /* AER stats for this device */
#endif
#ifdef CONFIG_PCIEPORTBUS
struct rcec_ea *rcec_ea; /* RCEC cached endpoint association */
struct pci_dev *rcec; /* Associated RCEC device */
#endif
u8 pcie_cap; /* PCIe capability offset */
u8 msi_cap; /* MSI capability offset */
@ -380,7 +386,7 @@ struct pci_dev {
struct pcie_link_state *link_state; /* ASPM link state */
unsigned int ltr_path:1; /* Latency Tolerance Reporting
supported from root to here */
int l1ss; /* L1SS Capability pointer */
u16 l1ss; /* L1SS Capability pointer */
#endif
unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */
@ -1063,12 +1069,13 @@ void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
int pci_find_capability(struct pci_dev *dev, int cap);
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability(struct pci_dev *dev, int cap);
int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap);
int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
u8 pci_find_capability(struct pci_dev *dev, int cap);
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap);
u16 pci_find_ext_capability(struct pci_dev *dev, int cap);
u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 pos, int cap);
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
u64 pci_get_dsn(struct pci_dev *dev);
@ -1190,7 +1197,6 @@ void pci_clear_master(struct pci_dev *dev);
int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
int pci_set_cacheline_size(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI
int __must_check pci_set_mwi(struct pci_dev *dev);
int __must_check pcim_set_mwi(struct pci_dev *dev);
int pci_try_set_mwi(struct pci_dev *dev);
@ -1271,7 +1277,7 @@ bool pci_dev_run_wake(struct pci_dev *dev);
void pci_d3cold_enable(struct pci_dev *dev);
void pci_d3cold_disable(struct pci_dev *dev);
bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
void pci_wakeup_bus(struct pci_bus *bus);
void pci_resume_bus(struct pci_bus *bus);
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
/* For use by arch with custom probe code */
@ -1279,7 +1285,6 @@ void set_pcie_port_type(struct pci_dev *pdev);
void set_pcie_hotplug_bridge(struct pci_dev *pdev);
/* Functions for PCI Hotplug drivers to use */
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
unsigned int pci_rescan_bus(struct pci_bus *bus);
void pci_lock_rescan_remove(void);
@ -1719,7 +1724,7 @@ static inline int __pci_register_driver(struct pci_driver *drv,
static inline int pci_register_driver(struct pci_driver *drv)
{ return 0; }
static inline void pci_unregister_driver(struct pci_driver *drv) { }
static inline int pci_find_capability(struct pci_dev *dev, int cap)
static inline u8 pci_find_capability(struct pci_dev *dev, int cap)
{ return 0; }
static inline int pci_find_next_capability(struct pci_dev *dev, u8 post,
int cap)

View File

@ -81,6 +81,7 @@
#define PCI_CLASS_SYSTEM_RTC 0x0803
#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
#define PCI_CLASS_SYSTEM_SDHCI 0x0805
#define PCI_CLASS_SYSTEM_RCEC 0x0807
#define PCI_CLASS_SYSTEM_OTHER 0x0880
#define PCI_BASE_CLASS_INPUT 0x09

View File

@ -531,6 +531,7 @@
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
#define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
#define PCI_EXP_LNKCAP_SLS_64_0GB 0x00000006 /* LNKCAP2 SLS Vector bit 5 */
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
#define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */
@ -562,6 +563,7 @@
#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
#define PCI_EXP_LNKSTA_CLS_32_0GB 0x0005 /* Current Link Speed 32.0GT/s */
#define PCI_EXP_LNKSTA_CLS_64_0GB 0x0006 /* Current Link Speed 64.0GT/s */
#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */
#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */
#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */
@ -670,6 +672,7 @@
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
#define PCI_EXP_LNKCAP2_SLS_32_0GB 0x00000020 /* Supported Speed 32GT/s */
#define PCI_EXP_LNKCAP2_SLS_64_0GB 0x00000040 /* Supported Speed 64GT/s */
#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */
#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
#define PCI_EXP_LNKCTL2_TLS 0x000f
@ -678,6 +681,7 @@
#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */
#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */
#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
#define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */
#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */
#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
#define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */
@ -832,6 +836,13 @@
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
#define PCI_EXT_CAP_PWR_SIZEOF 16
/* Root Complex Event Collector Endpoint Association */
#define PCI_RCEC_RCIEP_BITMAP 4 /* Associated Bitmap for RCiEPs */
#define PCI_RCEC_BUSN 8 /* RCEC Associated Bus Numbers */
#define PCI_RCEC_BUSN_REG_VER 0x02 /* Least version with BUSN present */
#define PCI_RCEC_BUSN_NEXT(x) (((x) >> 8) & 0xff)
#define PCI_RCEC_BUSN_LAST(x) (((x) >> 16) & 0xff)
/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */
#define PCI_VNDR_HEADER 4 /* Vendor-Specific Header */
#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff)