pci-v6.9-changes

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmXw04sUHGJoZWxnYWFz
 QGdvb2dsZS5jb20ACgkQWYigwDrT+vyT3xAAsp5+c2IcbrXpZZM7figwx4y9PPRp
 jcQ4AYSGP41xqTUGXUTcVZYvRorSIAFEOz33U0SL1UNxoOZz8j/M6SD58k8a6XRr
 9SSPuKja1OKJjONhS1bzrcbVtuzr71ISrECXfLkvW5hY5hvq+3+anMtu3/UIEHu6
 M1vVc+basRjjPJNTixMWvVqS3R+4gDAFeBtdZl/D+U6v0v2xOK+81YZqjfZZCw9v
 xmdHHK2dKNEdysNoRJ5cafY3b1NnSsrxlHbIhBnKt+7uRSWKD1dHcBQj7wDc/HrX
 yBGca+BZBKitXEJM3p5KcWWs4ijaywGw0GSffUIKrN9i6RIfwnxBH9jUbwDngifU
 2IR/kLEqdjYi/WnENxIHpQATLyXhXZ8uEnLS0xMlRIA96u3M5B0mrYOZxaN3bo12
 A3aE+aPOTw0u1wf7G8dBX6IdYnjZ/ZuR9Q+fVoKpZBvsYUVaKyiKCtKMCNaVirn5
 z7nxR1W71ee+35+37KthPXhiw+YtURGz1wBWt+wWUMjBcpIj2bpzU9wQDE9ZMdYt
 XJoJcatrRhJzefO3uzd0egft+vwk0xrj5LQEDhMQyDrnBLC4EgI5niKPWqbay5Nx
 Cnll01CI82xAnIF6eu7OOuI1nYGtoFcY8rP3hTC85cWN7Xi8SAOLTZZcVTpfBMUr
 l2uEll8p+8dZ6IY=
 =AP3I
 -----END PGP SIGNATURE-----

Merge tag 'pci-v6.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci

Pull PCI updates from Bjorn Helgaas:
 "Enumeration:

   - Consolidate interrupt related code in irq.c (Ilpo Järvinen)

   - Reduce kernel size by replacing sysfs resource macros with
     functions (Ilpo Järvinen)

   - Reduce kernel size by compiling sysfs support only when
     CONFIG_SYSFS=y (Lukas Wunner)

   - Avoid using Extended Tags on 3ware-9650SE Root Port to work around
     an apparent hardware defect (Jörg Wedekind)

  Resource management:

   - Fix an MMIO mapping leak in pci_iounmap() (Philipp Stanner)

   - Move pci_iomap.c and other PCI-specific devres code to drivers/pci
     (Philipp Stanner)

   - Consolidate PCI devres code in devres.c (Philipp Stanner)

  Power management:

   - Avoid D3cold on Asus B1400 PCI-NVMe bridge, where firmware doesn't
     know how to return correctly to D0, and remove previous quirk that
     wasn't as specific (Daniel Drake)

   - Allow runtime PM when the driver enables it but doesn't need any
     runtime PM callbacks (Raag Jadav)

   - Drain runtime-idle callbacks before driver removal to avoid races
     between .remove() and .runtime_idle(), which caused intermittent
     page faults when the rtsx .runtime_idle() accessed registers that
     its .remove() had already unmapped (Rafael J. Wysocki)

  Virtualization:

   - Avoid Secondary Bus Reset on LSI FW643 so it can be assigned to VMs
     with VFIO, e.g., for professional audio software on many Apple
     machines, at the cost of leaking state between VMs (Edmund Raile)

  Error handling:

   - Print all logged TLP Prefixes, not just the first, after AER or DPC
     errors (Ilpo Järvinen)

   - Quirk the DPC PIO log size for Intel Raptor Lake Root Ports, which
     still don't advertise a legal size (Paul Menzel)

   - Ignore expected DPC Surprise Down errors on hot removal (Smita
     Koralahalli)

   - Block runtime suspend while handling AER errors to avoid races that
     prevent the device form being resumed from D3hot (Stanislaw
     Gruszka)

  Peer-to-peer DMA:

   - Use atomic XA allocation in RCU read section (Christophe JAILLET)

  ASPM:

   - Collect bits of ASPM-related code that we need even without
     CONFIG_PCIEASPM into aspm.c (David E. Box)

   - Save/restore L1 PM Substates config for suspend/resume (David E.
     Box)

   - Update save_save when ASPM config is changed, so a .slot_reset()
     during error recovery restores the changed config, not the
     .probe()-time config (Vidya Sagar)

  Endpoint framework:

   - Refactor and improve pci_epf_alloc_space() API (Niklas Cassel)

   - Clean up endpoint BAR descriptions (Niklas Cassel)

   - Fix ntb_register_device() name leak in error path (Yang Yingliang)

   - Return actual error code for pci_vntb_probe() failure (Yang
     Yingliang)

  Broadcom STB PCIe controller driver:

   - Fix MDIO write polling, which previously never waited for
     completion (Jonathan Bell)

  Cadence PCIe endpoint driver:

   - Clear the ARI "Next Function Number" of last function (Jasko-EXT
     Wojciech)

  Freescale i.MX6 PCIe controller driver:

   - Simplify by replacing switch statements with function pointers for
     different hardware variants (Frank Li)

   - Simplify by using clk_bulk*() API (Frank Li)

   - Remove redundant DT clock and reg/reg-name details (Frank Li)

   - Add i.MX95 DT and driver support for both Root Complex and Endpoint
     mode (Frank Li)

  Microsoft Hyper-V host bridge driver:

   - Reduce memory usage by limiting ring buffer size to 16KB instead of
     4 pages (Michael Kelley)

  Qualcomm PCIe controller driver:

   - Add X1E80100 DT and driver support (Abel Vesa)

   - Add DT 'required-opps' for SoCs that require a minimum performance
     level (Johan Hovold)

   - Make DT 'msi-map-mask' optional, depending on how MSI interrupts
     are mapped (Johan Hovold)

   - Disable ASPM L0s for sc8280xp, sa8540p and sa8295p because the PHY
     configuration isn't tuned correctly for L0s (Johan Hovold)

   - Split dt-binding qcom,pcie.yaml into qcom,pcie-common.yaml and
     separate files for SA8775p, SC7280, SC8180X, SC8280XP, SM8150,
     SM8250, SM8350, SM8450, SM8550 for easier reviewing (Krzysztof
     Kozlowski)

   - Enable BDF to SID translation by disabling bypass mode (Manivannan
     Sadhasivam)

   - Add endpoint MHI support for Snapdragon SA8775P SoC (Mrinmay
     Sarkar)

  Synopsys DesignWare PCIe controller driver:

   - Allocate 64-bit MSI address if no 32-bit address is available (Ajay
     Agarwal)

   - Fix endpoint Resizable BAR to actually advertise the required 1MB
     size (Niklas Cassel)

  MicroSemi Switchtec management driver:

   - Release resources if the .probe() fails (Christophe JAILLET)

  Miscellaneous:

   - Make pcie_port_bus_type const (Ricardo B. Marliere)"

* tag 'pci-v6.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (77 commits)
  PCI/ASPM: Update save_state when configuration changes
  PCI/ASPM: Disable L1 before configuring L1 Substates
  PCI/ASPM: Call pci_save_ltr_state() from pci_save_pcie_state()
  PCI/ASPM: Save L1 PM Substates Capability for suspend/resume
  PCI: hv: Fix ring buffer size calculation
  PCI: dwc: endpoint: Fix advertised resizable BAR size
  PCI: cadence: Clear the ARI Capability Next Function Number of the last function
  PCI: dwc: Strengthen the MSI address allocation logic
  PCI: brcmstb: Fix broken brcm_pcie_mdio_write() polling
  PCI: qcom: Add X1E80100 PCIe support
  dt-bindings: PCI: qcom: Document the X1E80100 PCIe Controller
  PCI: qcom: Enable BDF to SID translation properly
  PCI/AER: Generalize TLP Header Log reading
  PCI/AER: Use explicit register size for PCI_ERR_CAP
  PCI: qcom: Disable ASPM L0s for sc8280xp, sa8540p and sa8295p
  dt-bindings: PCI: qcom: Do not require 'msi-map-mask'
  dt-bindings: PCI: qcom: Allow 'required-opps'
  PCI/AER: Block runtime suspend when handling errors
  PCI/ASPM: Move pci_save_ltr_state() to aspm.c
  PCI/ASPM: Always build aspm.c
  ...
This commit is contained in:
Linus Torvalds 2024-03-14 10:58:27 -07:00
commit 705c1da8fa
73 changed files with 3796 additions and 1774 deletions

View File

@ -11,7 +11,7 @@ saw any problems).
What: /sys/bus/pci/devices/<dev>/aer_dev_correctable
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of correctable errors seen and reported by this
PCI device using ERR_COR. Note that since multiple errors may
@ -32,7 +32,7 @@ Description: List of correctable errors seen and reported by this
What: /sys/bus/pci/devices/<dev>/aer_dev_fatal
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of uncorrectable fatal errors seen and reported by this
PCI device using ERR_FATAL. Note that since multiple errors may
@ -62,7 +62,7 @@ Description: List of uncorrectable fatal errors seen and reported by this
What: /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of uncorrectable nonfatal errors seen and reported by this
PCI device using ERR_NONFATAL. Note that since multiple errors
@ -100,20 +100,20 @@ collectors) that are AER capable. These indicate the number of error messages as
device, so these counters include them and are thus cumulative of all the error
messages on the PCI hierarchy originating at that root port.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
What: /sys/bus/pci/devices/<dev>/aer_rootport_total_err_cor
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_COR messages reported to rootport.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
What: /sys/bus/pci/devices/<dev>/aer_rootport_total_err_fatal
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_FATAL messages reported to rootport.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
What: /sys/bus/pci/devices/<dev>/aer_rootport_total_err_nonfatal
Date: July 2018
KernelVersion: 4.19.0
KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_NONFATAL messages reported to rootport.

View File

@ -150,22 +150,6 @@ allOf:
- {}
- const: pcie_phy
- const: pcie_aux
- if:
properties:
compatible:
not:
contains:
enum:
- fsl,imx6sx-pcie
- fsl,imx8mq-pcie
- fsl,imx6sx-pcie-ep
- fsl,imx8mq-pcie-ep
then:
properties:
clocks:
maxItems: 3
clock-names:
maxItems: 3
- if:
properties:
@ -223,6 +207,7 @@ allOf:
- fsl,imx6sx-pcie
- fsl,imx6q-pcie
- fsl,imx6qp-pcie
- fsl,imx95-pcie
- fsl,imx6sx-pcie-ep
- fsl,imx6q-pcie-ep
- fsl,imx6qp-pcie-ep

View File

@ -22,14 +22,7 @@ properties:
- fsl,imx8mm-pcie-ep
- fsl,imx8mq-pcie-ep
- fsl,imx8mp-pcie-ep
reg:
minItems: 2
reg-names:
items:
- const: dbi
- const: addr_space
- fsl,imx95-pcie-ep
clocks:
minItems: 3
@ -66,7 +59,44 @@ allOf:
properties:
compatible:
enum:
- fsl,imx8mm-pcie-ep
- fsl,imx8mq-pcie-ep
- fsl,imx8mp-pcie-ep
then:
properties:
reg:
minItems: 2
maxItems: 2
reg-names:
items:
- const: dbi
- const: addr_space
- if:
properties:
compatible:
enum:
- fsl,imx95-pcie-ep
then:
properties:
reg:
minItems: 6
maxItems: 6
reg-names:
items:
- const: dbi
- const: atu
- const: dbi2
- const: app
- const: dma
- const: addr_space
- if:
properties:
compatible:
enum:
- fsl,imx8mq-pcie-ep
- fsl,imx95-pcie-ep
then:
properties:
clocks:

View File

@ -29,16 +29,7 @@ properties:
- fsl,imx8mq-pcie
- fsl,imx8mm-pcie
- fsl,imx8mp-pcie
reg:
items:
- description: Data Bus Interface (DBI) registers.
- description: PCIe configuration space region.
reg-names:
items:
- const: dbi
- const: config
- fsl,imx95-pcie
clocks:
minItems: 3
@ -90,6 +81,43 @@ required:
allOf:
- $ref: /schemas/pci/snps,dw-pcie.yaml#
- $ref: /schemas/pci/fsl,imx6q-pcie-common.yaml#
- if:
properties:
compatible:
enum:
- fsl,imx6q-pcie
- fsl,imx6sx-pcie
- fsl,imx6qp-pcie
- fsl,imx7d-pcie
- fsl,imx8mq-pcie
- fsl,imx8mm-pcie
- fsl,imx8mp-pcie
then:
properties:
reg:
maxItems: 2
reg-names:
items:
- const: dbi
- const: config
- if:
properties:
compatible:
enum:
- fsl,imx95-pcie
then:
properties:
reg:
minItems: 4
maxItems: 4
reg-names:
items:
- const: dbi
- const: config
- const: atu
- const: app
- if:
properties:
compatible:
@ -111,6 +139,7 @@ allOf:
compatible:
enum:
- fsl,imx8mq-pcie
- fsl,imx95-pcie
then:
properties:
clocks:

View File

@ -0,0 +1,100 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-common.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm PCI Express Root Complex Common Properties
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
properties:
reg:
minItems: 4
maxItems: 6
reg-names:
minItems: 4
maxItems: 6
interrupts:
minItems: 1
maxItems: 8
interrupt-names:
minItems: 1
maxItems: 8
iommu-map:
minItems: 1
maxItems: 16
clocks:
minItems: 3
maxItems: 13
clock-names:
minItems: 3
maxItems: 13
dma-coherent: true
interconnects:
maxItems: 2
interconnect-names:
items:
- const: pcie-mem
- const: cpu-pcie
phys:
maxItems: 1
phy-names:
items:
- const: pciephy
power-domains:
maxItems: 1
required-opps:
maxItems: 1
resets:
minItems: 1
maxItems: 12
reset-names:
minItems: 1
maxItems: 12
perst-gpios:
description: GPIO controlled connection to PERST# signal
maxItems: 1
wake-gpios:
description: GPIO controlled connection to WAKE# signal
maxItems: 1
required:
- reg
- reg-names
- interrupt-map-mask
- interrupt-map
- clocks
- clock-names
anyOf:
- required:
- interrupts
- interrupt-names
- "#interrupt-cells"
- required:
- msi-map
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
additionalProperties: true

View File

@ -0,0 +1,166 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sa8775p.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SA8775p PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SA8775p SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sa8775p
reg:
minItems: 6
maxItems: 6
reg-names:
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 5
maxItems: 5
clock-names:
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
required:
- interconnects
- interconnect-names
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,sa8775p-gcc.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interconnect/qcom,sa8775p-rpmh.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sa8775p";
reg = <0x0 0x01c00000 0x0 0x3000>,
<0x0 0x40000000 0x0 0xf20>,
<0x0 0x40000f20 0x0 0xa8>,
<0x0 0x40001000 0x0 0x4000>,
<0x0 0x40100000 0x0 0x100000>,
<0x0 0x01c03000 0x0 0x1000>;
reg-names = "parf", "dbi", "elbi", "atu", "config", "mhi";
ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
<0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>;
assigned-clock-rates = <19200000>;
clocks = <&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>;
clock-names = "aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a";
dma-coherent;
interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 312 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 313 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 314 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
"msi3",
"msi4",
"msi5",
"msi6",
"msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 2 &intc GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 3 &intc GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 4 &intc GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>;
interconnects = <&pcie_anoc MASTER_PCIE_0 0 &mc_virt SLAVE_EBI1 0>,
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_0 0>;
interconnect-names = "pcie-mem", "cpu-pcie";
iommu-map = <0x0 &pcie_smmu 0x0000 0x1>,
<0x100 &pcie_smmu 0x0001 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 0 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,166 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sc7280.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SC7280 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SC7280 SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sc7280
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 13
maxItems: 13
clock-names:
items:
- const: pipe # PIPE clock
- const: pipe_mux # PIPE MUX
- const: phy_pipe # PIPE output clock
- const: ref # REFERENCE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre0 # Aggre NoC PCIe CENTER SF AXI clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
interrupts:
maxItems: 1
interrupt-names:
items:
- const: msi
resets:
maxItems: 1
reset-names:
items:
- const: pci
vddpe-3v3-supply:
description: PCIe endpoint power supply
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc7280.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c08000 {
compatible = "qcom,pcie-sc7280";
reg = <0 0x01c08000 0 0x3000>,
<0 0x40000000 0 0xf1d>,
<0 0x40000f20 0 0xa8>,
<0 0x40001000 0 0x1000>,
<0 0x40100000 0 0x100000>;
reg-names = "parf", "dbi", "elbi", "atu", "config";
ranges = <0x01000000 0x0 0x00000000 0x0 0x40200000 0x0 0x100000>,
<0x02000000 0x0 0x40300000 0x0 0x40300000 0x0 0x1fd00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <1>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>;
assigned-clock-rates = <19200000>;
clocks = <&gcc GCC_PCIE_1_PIPE_CLK>,
<&gcc GCC_PCIE_1_PIPE_CLK_SRC>,
<&pcie1_phy>,
<&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_PCIE_1_AUX_CLK>,
<&gcc GCC_PCIE_1_CFG_AHB_CLK>,
<&gcc GCC_PCIE_1_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_1_SLV_AXI_CLK>,
<&gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_CENTER_SF_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_1_AXI_CLK>;
clock-names = "pipe",
"pipe_mux",
"phy_pipe",
"ref",
"aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"tbu",
"ddrss_sf_tbu",
"aggre0",
"aggre1";
dma-coherent;
interrupts = <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 2 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 3 &intc 0 0 0 438 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 4 &intc 0 0 0 439 IRQ_TYPE_LEVEL_HIGH>;
iommu-map = <0x0 &apps_smmu 0x1c80 0x1>,
<0x100 &apps_smmu 0x1c81 0x1>;
phys = <&pcie1_phy>;
phy-names = "pciephy";
pinctrl-names = "default";
pinctrl-0 = <&pcie1_clkreq_n>;
power-domains = <&gcc GCC_PCIE_1_GDSC>;
resets = <&gcc GCC_PCIE_1_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 2 GPIO_ACTIVE_LOW>;
vddpe-3v3-supply = <&pp3300_ssd>;
};
};

View File

@ -0,0 +1,170 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sc8180x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SC8180x PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SC8180x SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sc8180x
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ref # REFERENCE clock
- const: tbu # PCIe TBU clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc8180x.h>
#include <dt-bindings/interconnect/qcom,sc8180x.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sc8180x";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>;
reg-names = "parf",
"dbi",
"elbi",
"atu",
"config";
ranges = <0x01000000 0x0 0x60200000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>;
assigned-clock-rates = <19200000>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
<&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_PCIE_0_CLKREF_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>;
clock-names = "pipe",
"aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"ref",
"tbu";
dma-coherent;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0",
"msi1",
"msi2",
"msi3",
"msi4",
"msi5",
"msi6",
"msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
interconnects = <&aggre2_noc MASTER_PCIE 0 &mc_virt SLAVE_EBI_CH0 0>,
<&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_PCIE_0 0>;
interconnect-names = "pcie-mem", "cpu-pcie";
iommu-map = <0x0 &apps_smmu 0x1d80 0x1>,
<0x100 &apps_smmu 0x1d81 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
};
};

View File

@ -0,0 +1,180 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sc8280xp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SC8280XP PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SC8280XP SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
enum:
- qcom,pcie-sa8540p
- qcom,pcie-sc8280xp
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 8
maxItems: 9
clock-names:
minItems: 8
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: noc_aggr_4 # NoC aggregate 4 clock
- const: noc_aggr_south_sf # NoC aggregate South SF clock
- const: cnoc_qx # Configuration NoC QX clock
resets:
maxItems: 1
reset-names:
items:
- const: pci
vddpe-3v3-supply:
description: A phandle to the PCIe endpoint power supply
required:
- interconnects
- interconnect-names
allOf:
- $ref: qcom,pcie-common.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sc8280xp
then:
properties:
interrupts:
minItems: 4
maxItems: 4
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
else:
properties:
interrupts:
maxItems: 1
interrupt-names:
items:
- const: msi
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc8280xp.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sc8280xp.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c20000 {
compatible = "qcom,pcie-sc8280xp";
reg = <0x0 0x01c20000 0x0 0x3000>,
<0x0 0x3c000000 0x0 0xf1d>,
<0x0 0x3c000f20 0x0 0xa8>,
<0x0 0x3c001000 0x0 0x1000>,
<0x0 0x3c100000 0x0 0x100000>,
<0x0 0x01c23000 0x0 0x1000>;
reg-names = "parf", "dbi", "elbi", "atu", "config", "mhi";
ranges = <0x01000000 0x0 0x00000000 0x0 0x3c200000 0x0 0x100000>,
<0x02000000 0x0 0x3c300000 0x0 0x3c300000 0x0 0x1d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <2>;
num-lanes = <4>;
#address-cells = <3>;
#size-cells = <2>;
assigned-clocks = <&gcc GCC_PCIE_2A_AUX_CLK>;
assigned-clock-rates = <19200000>;
clocks = <&gcc GCC_PCIE_2A_AUX_CLK>,
<&gcc GCC_PCIE_2A_CFG_AHB_CLK>,
<&gcc GCC_PCIE_2A_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_2A_SLV_AXI_CLK>,
<&gcc GCC_PCIE_2A_SLV_Q2A_AXI_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_4_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_SOUTH_SF_AXI_CLK>;
clock-names = "aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"ddrss_sf_tbu",
"noc_aggr_4",
"noc_aggr_south_sf";
dma-coherent;
interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 523 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 524 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 525 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 530 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 2 &intc 0 0 GIC_SPI 531 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 3 &intc 0 0 GIC_SPI 532 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 4 &intc 0 0 GIC_SPI 533 IRQ_TYPE_LEVEL_HIGH>;
interconnects = <&aggre2_noc MASTER_PCIE_2A 0 &mc_virt SLAVE_EBI1 0>,
<&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_PCIE_2A 0>;
interconnect-names = "pcie-mem", "cpu-pcie";
phys = <&pcie2a_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie2a_default>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_2A_GDSC>;
resets = <&gcc GCC_PCIE_2A_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 143 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 145 GPIO_ACTIVE_LOW>;
vddpe-3v3-supply = <&vreg_nvme>;
};
};

View File

@ -0,0 +1,158 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sm8150.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM8150 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM8150 SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sm8150
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ref # REFERENCE clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sm8150.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sm8150.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sm8150";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>;
reg-names = "parf", "dbi", "elbi", "atu", "config";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <1>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
<&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
<&rpmhcc RPMH_CXO_CLK>;
clock-names = "pipe",
"aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"tbu",
"ref";
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
iommu-map = <0x0 &apps_smmu 0x1d80 0x1>,
<0x100 &apps_smmu 0x1d81 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;
wake-gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,173 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sm8250.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM8250 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM8250 SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sm8250
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 8
maxItems: 9
clock-names:
# Unfortunately the "optional" ref clock is used in the middle of the list
oneOf:
- items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ref # REFERENCE clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sm8250.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sm8250.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sm8250";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>,
<0 0x01c03000 0 0x1000>;
reg-names = "parf", "dbi", "elbi", "atu", "config", "mhi";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <1>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
<&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>;
clock-names = "pipe",
"aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"tbu",
"ddrss_sf_tbu";
dma-coherent;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
iommu-map = <0x0 &apps_smmu 0x1c00 0x1>,
<0x100 &apps_smmu 0x1c01 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 79 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,184 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sm8350.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM8350 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM8350 SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-sm8350
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 8
maxItems: 9
clock-names:
minItems: 8
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
- const: aggre0 # Aggre NoC PCIe0 AXI clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
oneOf:
- properties:
interrupts:
maxItems: 1
interrupt-names:
items:
- const: msi
- properties:
interrupts:
minItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sm8350.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sm8350.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sm8350";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>;
reg-names = "parf", "dbi", "elbi", "atu", "config";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <1>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_1_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_0_AXI_CLK>;
clock-names = "aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"tbu",
"ddrss_sf_tbu",
"aggre1",
"aggre0";
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
iommu-map = <0x0 &apps_smmu 0x1c00 0x1>,
<0x100 &apps_smmu 0x1c01 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,178 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sm8450.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM8450 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM8450 SoC PCIe root complex controller is based on the Synopsys
DesignWare PCIe IP.
properties:
compatible:
enum:
- qcom,pcie-sm8450-pcie0
- qcom,pcie-sm8450-pcie1
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 11
maxItems: 12
clock-names:
minItems: 11
items:
- const: pipe # PIPE clock
- const: pipe_mux # PIPE MUX
- const: phy_pipe # PIPE output clock
- const: ref # REFERENCE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- enum: [aggre0, aggre1] # Aggre NoC PCIe0/1 AXI clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
maxItems: 1
reset-names:
items:
- const: pci
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sm8450.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sm8450.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sm8450-pcie0";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>;
reg-names = "parf", "dbi", "elbi", "atu", "config";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
max-link-speed = <2>;
num-lanes = <1>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
<&gcc GCC_PCIE_0_PIPE_CLK_SRC>,
<&pcie0_phy>,
<&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_TBU_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_0_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_1_AXI_CLK>;
clock-names = "pipe",
"pipe_mux",
"phy_pipe",
"ref",
"aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"ddrss_sf_tbu",
"aggre0",
"aggre1";
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
msi-map = <0x0 &gic_its 0x5981 0x1>,
<0x100 &gic_its 0x5980 0x1>;
msi-map-mask = <0xff00>;
iommu-map = <0x0 &apps_smmu 0x1c00 0x1>,
<0x100 &apps_smmu 0x1c01 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,171 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-sm8550.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM8550 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm SM8550 SoC (and compatible) PCIe root complex controller is based on
the Synopsys DesignWare PCIe IP.
properties:
compatible:
oneOf:
- const: qcom,pcie-sm8550
- items:
- enum:
- qcom,pcie-sm8650
- const: qcom,pcie-sm8550
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 7
maxItems: 8
clock-names:
minItems: 7
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: noc_aggr # Aggre NoC PCIe AXI clock
- const: cnoc_sf_axi # Config NoC PCIe1 AXI clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
items:
- const: pci # PCIe core reset
- const: link_down # PCIe link down reset
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,sm8550-rpmh.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c00000 {
compatible = "qcom,pcie-sm8550";
reg = <0 0x01c00000 0 0x3000>,
<0 0x60000000 0 0xf1d>,
<0 0x60000f20 0 0xa8>,
<0 0x60001000 0 0x1000>,
<0 0x60100000 0 0x100000>;
reg-names = "parf", "dbi", "elbi", "atu", "config";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_0_AUX_CLK>,
<&gcc GCC_PCIE_0_CFG_AHB_CLK>,
<&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_AXI_CLK>,
<&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>,
<&gcc GCC_DDRSS_PCIE_SF_QTB_CLK>,
<&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>;
clock-names = "aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"ddrss_sf_tbu",
"noc_aggr";
dma-coherent;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
interconnects = <&pcie_noc MASTER_PCIE_0 0 &mc_virt SLAVE_EBI1 0>,
<&gem_noc MASTER_APPSS_PROC 0 &cnoc_main SLAVE_PCIE_0 0>;
interconnect-names = "pcie-mem", "cpu-pcie";
iommu-map = <0x0 &apps_smmu 0x1400 0x1>,
<0x100 &apps_smmu 0x1401 0x1>;
phys = <&pcie0_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc PCIE_0_GDSC>;
resets = <&gcc GCC_PCIE_0_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -0,0 +1,165 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/qcom,pcie-x1e80100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm X1E80100 PCI Express Root Complex
maintainers:
- Bjorn Andersson <andersson@kernel.org>
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
description:
Qualcomm X1E80100 SoC (and compatible) PCIe root complex controller is based on
the Synopsys DesignWare PCIe IP.
properties:
compatible:
const: qcom,pcie-x1e80100
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
items:
- const: parf # Qualcomm specific registers
- const: dbi # DesignWare PCIe registers
- const: elbi # External local bus interface registers
- const: atu # ATU address space
- const: config # PCIe configuration space
- const: mhi # MHI registers
clocks:
minItems: 7
maxItems: 7
clock-names:
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: noc_aggr # Aggre NoC PCIe AXI clock
- const: cnoc_sf_axi # Config NoC PCIe1 AXI clock
interrupts:
minItems: 8
maxItems: 8
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- const: msi4
- const: msi5
- const: msi6
- const: msi7
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
items:
- const: pci # PCIe core reset
- const: link_down # PCIe link down reset
allOf:
- $ref: qcom,pcie-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,x1e80100-gcc.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interconnect/qcom,x1e80100-rpmh.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
pcie@1c08000 {
compatible = "qcom,pcie-x1e80100";
reg = <0 0x01c08000 0 0x3000>,
<0 0x7c000000 0 0xf1d>,
<0 0x7c000f40 0 0xa8>,
<0 0x7c001000 0 0x1000>,
<0 0x7c100000 0 0x100000>,
<0 0x01c0b000 0 0x1000>;
reg-names = "parf", "dbi", "elbi", "atu", "config", "mhi";
ranges = <0x01000000 0x0 0x00000000 0x0 0x60200000 0x0 0x100000>,
<0x02000000 0x0 0x60300000 0x0 0x60300000 0x0 0x3d00000>;
bus-range = <0x00 0xff>;
device_type = "pci";
linux,pci-domain = <0>;
num-lanes = <2>;
#address-cells = <3>;
#size-cells = <2>;
clocks = <&gcc GCC_PCIE_4_AUX_CLK>,
<&gcc GCC_PCIE_4_CFG_AHB_CLK>,
<&gcc GCC_PCIE_4_MSTR_AXI_CLK>,
<&gcc GCC_PCIE_4_SLV_AXI_CLK>,
<&gcc GCC_PCIE_4_SLV_Q2A_AXI_CLK>,
<&gcc GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK>,
<&gcc GCC_CNOC_PCIE_NORTH_SF_AXI_CLK>;
clock-names = "aux",
"cfg",
"bus_master",
"bus_slave",
"slave_q2a",
"noc_aggr",
"cnoc_sf_axi";
dma-coherent;
interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi0", "msi1", "msi2", "msi3",
"msi4", "msi5", "msi6", "msi7";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
<0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
<0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
<0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
interconnects = <&pcie_noc MASTER_PCIE_4 0 &mc_virt SLAVE_EBI1 0>,
<&gem_noc MASTER_APPSS_PROC 0 &cnoc_main SLAVE_PCIE_4 0>;
interconnect-names = "pcie-mem", "cpu-pcie";
iommu-map = <0x0 &apps_smmu 0x1400 0x1>,
<0x100 &apps_smmu 0x1401 0x1>;
phys = <&pcie4_phy>;
phy-names = "pciephy";
pinctrl-0 = <&pcie0_default_state>;
pinctrl-names = "default";
power-domains = <&gcc GCC_PCIE_4_GDSC>;
resets = <&gcc GCC_PCIE_4_BCR>;
reset-names = "pci";
perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -28,23 +28,8 @@ properties:
- qcom,pcie-ipq8074-gen3
- qcom,pcie-msm8996
- qcom,pcie-qcs404
- qcom,pcie-sa8540p
- qcom,pcie-sa8775p
- qcom,pcie-sc7280
- qcom,pcie-sc8180x
- qcom,pcie-sc8280xp
- qcom,pcie-sdm845
- qcom,pcie-sdx55
- qcom,pcie-sm8150
- qcom,pcie-sm8250
- qcom,pcie-sm8350
- qcom,pcie-sm8450-pcie0
- qcom,pcie-sm8450-pcie1
- qcom,pcie-sm8550
- items:
- enum:
- qcom,pcie-sm8650
- const: qcom,pcie-sm8550
- items:
- const: qcom,pcie-msm8998
- const: qcom,pcie-msm8996
@ -106,9 +91,6 @@ properties:
vdda_refclk-supply:
description: A phandle to the core analog power supply for IC which generates reference clock
vddpe-3v3-supply:
description: A phandle to the PCIe endpoint power supply
phys:
maxItems: 1
@ -123,6 +105,9 @@ properties:
description: GPIO controlled connection to PERST# signal
maxItems: 1
required-opps:
maxItems: 1
wake-gpios:
description: GPIO controlled connection to WAKE# signal
maxItems: 1
@ -143,7 +128,6 @@ anyOf:
- "#interrupt-cells"
- required:
- msi-map
- msi-map-mask
allOf:
- $ref: /schemas/pci/pci-bus.yaml#
@ -217,16 +201,7 @@ allOf:
compatible:
contains:
enum:
- qcom,pcie-sa8775p
- qcom,pcie-sc7280
- qcom,pcie-sc8180x
- qcom,pcie-sc8280xp
- qcom,pcie-sdx55
- qcom,pcie-sm8250
- qcom,pcie-sm8350
- qcom,pcie-sm8450-pcie0
- qcom,pcie-sm8450-pcie1
- qcom,pcie-sm8550
then:
properties:
reg:
@ -451,65 +426,6 @@ allOf:
- const: pwr # PWR reset
- const: ahb # AHB reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sc7280
then:
properties:
clocks:
minItems: 13
maxItems: 13
clock-names:
items:
- const: pipe # PIPE clock
- const: pipe_mux # PIPE MUX
- const: phy_pipe # PIPE output clock
- const: ref # REFERENCE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre0 # Aggre NoC PCIe CENTER SF AXI clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sc8180x
then:
properties:
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ref # REFERENCE clock
- const: tbu # PCIe TBU clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
@ -553,229 +469,6 @@ allOf:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8150
then:
properties:
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ref # REFERENCE clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8250
then:
oneOf:
# Unfortunately the "optional" ref clock is used in the middle of the list
- properties:
clocks:
minItems: 9
maxItems: 9
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ref # REFERENCE clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- properties:
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
properties:
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8350
then:
properties:
clocks:
minItems: 8
maxItems: 9
clock-names:
minItems: 8
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
- const: aggre0 # Aggre NoC PCIe0 AXI clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8450-pcie0
then:
properties:
clocks:
minItems: 12
maxItems: 12
clock-names:
items:
- const: pipe # PIPE clock
- const: pipe_mux # PIPE MUX
- const: phy_pipe # PIPE output clock
- const: ref # REFERENCE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre0 # Aggre NoC PCIe0 AXI clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8450-pcie1
then:
properties:
clocks:
minItems: 11
maxItems: 11
clock-names:
items:
- const: pipe # PIPE clock
- const: pipe_mux # PIPE MUX
- const: phy_pipe # PIPE output clock
- const: ref # REFERENCE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: aggre1 # Aggre NoC PCIe1 AXI clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8550
then:
properties:
clocks:
minItems: 7
maxItems: 8
clock-names:
minItems: 7
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: noc_aggr # Aggre NoC PCIe AXI clock
- const: cnoc_sf_axi # Config NoC PCIe1 AXI clock
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
items:
- const: pci # PCIe core reset
- const: link_down # PCIe link down reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sa8540p
- qcom,pcie-sc8280xp
then:
properties:
clocks:
minItems: 8
maxItems: 9
clock-names:
minItems: 8
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ddrss_sf_tbu # PCIe SF TBU clock
- const: noc_aggr_4 # NoC aggregate 4 clock
- const: noc_aggr_south_sf # NoC aggregate South SF clock
- const: cnoc_qx # Configuration NoC QX clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
@ -802,43 +495,6 @@ allOf:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sa8775p
then:
properties:
clocks:
minItems: 5
maxItems: 5
clock-names:
items:
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sa8540p
- qcom,pcie-sa8775p
- qcom,pcie-sc8280xp
then:
required:
- interconnects
- interconnect-names
- if:
not:
properties:
@ -874,16 +530,7 @@ allOf:
contains:
enum:
- qcom,pcie-msm8996
- qcom,pcie-sa8775p
- qcom,pcie-sc7280
- qcom,pcie-sc8180x
- qcom,pcie-sdm845
- qcom,pcie-sm8150
- qcom,pcie-sm8250
- qcom,pcie-sm8350
- qcom,pcie-sm8450-pcie0
- qcom,pcie-sm8450-pcie1
- qcom,pcie-sm8550
then:
oneOf:
- properties:
@ -906,24 +553,6 @@ allOf:
- const: msi6
- const: msi7
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sc8280xp
then:
properties:
interrupts:
minItems: 4
maxItems: 4
interrupt-names:
items:
- const: msi0
- const: msi1
- const: msi2
- const: msi3
- if:
properties:
compatible:
@ -938,7 +567,6 @@ allOf:
- qcom,pcie-ipq8074
- qcom,pcie-ipq8074-gen3
- qcom,pcie-qcs404
- qcom,pcie-sa8540p
then:
properties:
interrupts:

View File

@ -517,6 +517,3 @@ Public Functions Provided
.. kernel-doc:: arch/x86/include/asm/io.h
:internal:
.. kernel-doc:: lib/pci_iomap.c
:export:

View File

@ -4,6 +4,12 @@ PCI Support Library
.. kernel-doc:: drivers/pci/pci.c
:export:
.. kernel-doc:: drivers/pci/iomap.c
:export:
.. kernel-doc:: drivers/pci/devres.c
:export:
.. kernel-doc:: drivers/pci/pci-driver.c
:export:

View File

@ -17018,7 +17018,6 @@ F: include/asm-generic/pci*
F: include/linux/of_pci.h
F: include/linux/pci*
F: include/uapi/linux/pci*
F: lib/pci*
PCIE DRIVER FOR AMAZON ANNAPURNA LABS
M: Jonathan Chocron <jonnyc@amazon.com>

View File

@ -907,6 +907,54 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
/*
* Disable D3cold on Asus B1400 PCI-NVMe bridge
*
* On this platform with VMD off, the NVMe device cannot successfully power
* back on from D3cold. This appears to be an untested transition by the
* vendor: Windows leaves the NVMe and parent bridge in D0 during suspend.
*
* We disable D3cold on the parent bridge for simplicity, and the fact that
* both parent bridge and NVMe device share the same power resource.
*
* This is only needed on BIOS versions before 308; the newer versions flip
* StorageD3Enable from 1 to 0.
*/
static const struct dmi_system_id asus_nvme_broken_d3cold_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.304"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.305"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.306"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_BIOS_VERSION, "B1400CEAE.307"),
},
},
{}
};
static void asus_disable_nvme_d3cold(struct pci_dev *pdev)
{
if (dmi_check_system(asus_nvme_broken_d3cold_table) > 0)
pci_d3cold_disable(pdev);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x9a09, asus_disable_nvme_d3cold);
#ifdef CONFIG_SUSPEND
/*
* Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but

View File

@ -385,18 +385,6 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "20GGA00L00"),
},
},
/*
* ASUS B1400CEAE hangs on resume from suspend (see
* https://bugzilla.kernel.org/show_bug.cgi?id=215742).
*/
{
.callback = init_default_s3,
.ident = "ASUS B1400CEAE",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK B1400CEAE"),
},
},
{},
};

View File

@ -445,8 +445,8 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
printk("%saer_uncor_severity: 0x%08x\n",
pfx, aer->uncor_severity);
printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
aer->header_log.dw0, aer->header_log.dw1,
aer->header_log.dw2, aer->header_log.dw3);
aer->header_log.dw[0], aer->header_log.dw[1],
aer->header_log.dw[2], aer->header_log.dw[3]);
}
}

View File

@ -100,6 +100,8 @@ EXPORT_SYMBOL(ntb_unregister_client);
int ntb_register_device(struct ntb_dev *ntb)
{
int ret;
if (!ntb)
return -EINVAL;
if (!ntb->pdev)
@ -120,7 +122,11 @@ int ntb_register_device(struct ntb_dev *ntb)
ntb->ctx_ops = NULL;
spin_lock_init(&ntb->ctx_lock);
return device_register(&ntb->dev);
ret = device_register(&ntb->dev);
if (ret)
put_device(&ntb->dev);
return ret;
}
EXPORT_SYMBOL(ntb_register_device);

View File

@ -13,6 +13,11 @@ config FORCE_PCI
select HAVE_PCI
select PCI
# select this to provide a generic PCI iomap,
# without PCI itself having to be defined
config GENERIC_PCI_IOMAP
bool
menuconfig PCI
bool "PCI support"
depends on HAVE_PCI

View File

@ -4,16 +4,17 @@
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
rom.o setup-res.o irq.o vpd.o \
setup-bus.o vc.o mmap.o devres.o
obj-$(CONFIG_PCI) += msi/
obj-$(CONFIG_PCI) += pcie/
ifdef CONFIG_PCI
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o
obj-$(CONFIG_ACPI) += pci-acpi.o
obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o
endif
obj-$(CONFIG_OF) += of.o

View File

@ -565,7 +565,8 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
struct cdns_pcie *pcie = &ep->pcie;
struct device *dev = pcie->dev;
int max_epfs = sizeof(epc->function_num_map) * 8;
int ret, value, epf;
int ret, epf, last_fn;
u32 reg, value;
/*
* BIT(0) is hardwired to 1, hence function 0 is always enabled
@ -573,6 +574,17 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
*/
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, epc->function_num_map);
/*
* Next function field in ARI_CAP_AND_CTR register for last function
* should be 0.
* Clearing Next Function Number field for the last function used.
*/
last_fn = find_last_bit(&epc->function_num_map, BITS_PER_LONG);
reg = CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(last_fn);
value = cdns_pcie_readl(pcie, reg);
value &= ~CDNS_PCIE_ARI_CAP_NFN_MASK;
cdns_pcie_writel(pcie, reg, value);
if (ep->quirk_disable_flr) {
for (epf = 0; epf < max_epfs; epf++) {
if (!(epc->function_num_map & BIT(epf)))

View File

@ -130,6 +130,12 @@
#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xc0
#define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200
/*
* Endpoint PF Registers
*/
#define CDNS_PCIE_CORE_PF_I_ARI_CAP_AND_CTRL(fn) (0x144 + (fn) * 0x1000)
#define CDNS_PCIE_ARI_CAP_NFN_MASK GENMASK(15, 8)
/*
* Root Port Registers (PCI configuration space for the root port function)
*/

View File

@ -42,6 +42,19 @@
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
#define IMX95_PCIE_PHY_GEN_CTRL 0x0
#define IMX95_PCIE_REF_USE_PAD BIT(17)
#define IMX95_PCIE_SS_RW_REG_0 0xf0
#define IMX95_PCIE_REF_CLKEN BIT(23)
#define IMX95_PCIE_PHY_CR_PARA_SEL BIT(9)
#define IMX95_PE0_GEN_CTRL_1 0x1050
#define IMX95_PCIE_DEVICE_TYPE GENMASK(3, 0)
#define IMX95_PE0_GEN_CTRL_3 0x1058
#define IMX95_PCIE_LTSSM_EN BIT(0)
#define to_imx6_pcie(x) dev_get_drvdata((x)->dev)
enum imx6_pcie_variants {
@ -52,14 +65,29 @@ enum imx6_pcie_variants {
IMX8MQ,
IMX8MM,
IMX8MP,
IMX95,
IMX8MQ_EP,
IMX8MM_EP,
IMX8MP_EP,
IMX95_EP,
};
#define IMX6_PCIE_FLAG_IMX6_PHY BIT(0)
#define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE BIT(1)
#define IMX6_PCIE_FLAG_SUPPORTS_SUSPEND BIT(2)
#define IMX6_PCIE_FLAG_HAS_PHYDRV BIT(3)
#define IMX6_PCIE_FLAG_HAS_APP_RESET BIT(4)
#define IMX6_PCIE_FLAG_HAS_PHY_RESET BIT(5)
#define IMX6_PCIE_FLAG_HAS_SERDES BIT(6)
#define IMX6_PCIE_FLAG_SUPPORT_64BIT BIT(7)
#define imx6_check_flag(pci, val) (pci->drvdata->flags & val)
#define IMX6_PCIE_MAX_CLKS 6
#define IMX6_PCIE_MAX_INSTANCES 2
struct imx6_pcie;
struct imx6_pcie_drvdata {
enum imx6_pcie_variants variant;
@ -67,6 +95,14 @@ struct imx6_pcie_drvdata {
u32 flags;
int dbi_length;
const char *gpr;
const char * const *clk_names;
const u32 clks_cnt;
const u32 ltssm_off;
const u32 ltssm_mask;
const u32 mode_off[IMX6_PCIE_MAX_INSTANCES];
const u32 mode_mask[IMX6_PCIE_MAX_INSTANCES];
const struct pci_epc_features *epc_features;
int (*init_phy)(struct imx6_pcie *pcie);
};
struct imx6_pcie {
@ -74,11 +110,7 @@ struct imx6_pcie {
int reset_gpio;
bool gpio_active_high;
bool link_is_up;
struct clk *pcie_bus;
struct clk *pcie_phy;
struct clk *pcie_inbound_axi;
struct clk *pcie;
struct clk *pcie_aux;
struct clk_bulk_data clks[IMX6_PCIE_MAX_CLKS];
struct regmap *iomuxc_gpr;
u16 msi_ctrl;
u32 controller_id;
@ -165,34 +197,44 @@ static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
}
static int imx95_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
regmap_update_bits(imx6_pcie->iomuxc_gpr,
IMX95_PCIE_SS_RW_REG_0,
IMX95_PCIE_PHY_CR_PARA_SEL,
IMX95_PCIE_PHY_CR_PARA_SEL);
regmap_update_bits(imx6_pcie->iomuxc_gpr,
IMX95_PCIE_PHY_GEN_CTRL,
IMX95_PCIE_REF_USE_PAD, 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr,
IMX95_PCIE_SS_RW_REG_0,
IMX95_PCIE_REF_CLKEN,
IMX95_PCIE_REF_CLKEN);
return 0;
}
static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
{
unsigned int mask, val, mode;
const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata;
unsigned int mask, val, mode, id;
if (imx6_pcie->drvdata->mode == DW_PCIE_EP_TYPE)
if (drvdata->mode == DW_PCIE_EP_TYPE)
mode = PCI_EXP_TYPE_ENDPOINT;
else
mode = PCI_EXP_TYPE_ROOT_PORT;
switch (imx6_pcie->drvdata->variant) {
case IMX8MQ:
case IMX8MQ_EP:
if (imx6_pcie->controller_id == 1) {
mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE;
val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
mode);
} else {
mask = IMX6Q_GPR12_DEVICE_TYPE;
val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode);
}
break;
default:
mask = IMX6Q_GPR12_DEVICE_TYPE;
val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE, mode);
break;
}
id = imx6_pcie->controller_id;
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val);
/* If mode_mask[id] is zero, means each controller have its individual gpr */
if (!drvdata->mode_mask[id])
id = 0;
mask = drvdata->mode_mask[id];
val = mode << (ffs(mask) - 1);
regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->mode_off[id], mask, val);
}
static int pcie_phy_poll_ack(struct imx6_pcie *imx6_pcie, bool exp_val)
@ -320,76 +362,66 @@ static int pcie_phy_write(struct imx6_pcie *imx6_pcie, int addr, u16 data)
return 0;
}
static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
static int imx8mq_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
switch (imx6_pcie->drvdata->variant) {
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
/*
* The PHY initialization had been done in the PHY
* driver, break here directly.
*/
break;
case IMX8MQ:
case IMX8MQ_EP:
/*
* TODO: Currently this code assumes external
* oscillator is being used
*/
/* TODO: Currently this code assumes external oscillator is being used */
regmap_update_bits(imx6_pcie->iomuxc_gpr,
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_REF_USE_PAD,
IMX8MQ_GPR_PCIE_REF_USE_PAD);
/*
* Regarding the datasheet, the PCIE_VPH is suggested to be 1.8V. If the PCIE_VPH is
* supplied by 3.3V, the VREG_BYPASS should be cleared to zero.
*/
if (imx6_pcie->vph && regulator_get_voltage(imx6_pcie->vph) > 3000000)
regmap_update_bits(imx6_pcie->iomuxc_gpr,
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_REF_USE_PAD,
IMX8MQ_GPR_PCIE_REF_USE_PAD);
/*
* Regarding the datasheet, the PCIE_VPH is suggested
* to be 1.8V. If the PCIE_VPH is supplied by 3.3V, the
* VREG_BYPASS should be cleared to zero.
*/
if (imx6_pcie->vph &&
regulator_get_voltage(imx6_pcie->vph) > 3000000)
regmap_update_bits(imx6_pcie->iomuxc_gpr,
imx6_pcie_grp_offset(imx6_pcie),
IMX8MQ_GPR_PCIE_VREG_BYPASS,
0);
break;
case IMX7D:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0);
break;
case IMX6SX:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_RX_EQ_MASK,
IMX6SX_GPR12_PCIE_RX_EQ_2);
fallthrough;
default:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX8MQ_GPR_PCIE_VREG_BYPASS,
0);
return 0;
}
static int imx7d_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0);
return 0;
}
static int imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
/* configure constant input signal to the pcie ctrl and phy */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
/* configure constant input signal to the pcie ctrl and phy */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN1,
imx6_pcie->tx_deemph_gen1 << 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB,
imx6_pcie->tx_deemph_gen2_3p5db << 6);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB,
imx6_pcie->tx_deemph_gen2_6db << 12);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_SWING_FULL,
imx6_pcie->tx_swing_full << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_SWING_LOW,
imx6_pcie->tx_swing_low << 25);
break;
}
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN1,
imx6_pcie->tx_deemph_gen1 << 0);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB,
imx6_pcie->tx_deemph_gen2_3p5db << 6);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB,
imx6_pcie->tx_deemph_gen2_6db << 12);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_SWING_FULL,
imx6_pcie->tx_swing_full << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
IMX6Q_GPR8_TX_SWING_LOW,
imx6_pcie->tx_swing_low << 25);
return 0;
}
imx6_pcie_configure_type(imx6_pcie);
static int imx6sx_pcie_init_phy(struct imx6_pcie *imx6_pcie)
{
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_RX_EQ_MASK, IMX6SX_GPR12_PCIE_RX_EQ_2);
return imx6_pcie_init_phy(imx6_pcie);
}
static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
@ -407,13 +439,18 @@ static void imx7d_pcie_wait_for_phy_pll_lock(struct imx6_pcie *imx6_pcie)
static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
{
unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy);
unsigned long phy_rate = 0;
int mult, div;
u16 val;
int i;
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
return 0;
for (i = 0; i < imx6_pcie->drvdata->clks_cnt; i++)
if (strncmp(imx6_pcie->clks[i].id, "pcie_phy", 8) == 0)
phy_rate = clk_get_rate(imx6_pcie->clks[i].clk);
switch (phy_rate) {
case 125000000:
/*
@ -550,19 +587,11 @@ static int imx6_pcie_attach_pd(struct device *dev)
static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
struct device *dev = pci->dev;
unsigned int offset;
int ret = 0;
switch (imx6_pcie->drvdata->variant) {
case IMX6SX:
ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
if (ret) {
dev_err(dev, "unable to enable pcie_axi clock\n");
break;
}
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN, 0);
break;
@ -582,6 +611,8 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
break;
case IMX7D:
case IMX95:
case IMX95_EP:
break;
case IMX8MM:
case IMX8MM_EP:
@ -589,12 +620,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
case IMX8MQ_EP:
case IMX8MP:
case IMX8MP_EP:
ret = clk_prepare_enable(imx6_pcie->pcie_aux);
if (ret) {
dev_err(dev, "unable to enable pcie_aux clock\n");
break;
}
offset = imx6_pcie_grp_offset(imx6_pcie);
/*
* Set the over ride low and enabled
@ -615,9 +640,6 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie)
{
switch (imx6_pcie->drvdata->variant) {
case IMX6SX:
clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
break;
case IMX6QP:
case IMX6Q:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
@ -631,14 +653,6 @@ static void imx6_pcie_disable_ref_clk(struct imx6_pcie *imx6_pcie)
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
break;
case IMX8MM:
case IMX8MM_EP:
case IMX8MQ:
case IMX8MQ_EP:
case IMX8MP:
case IMX8MP_EP:
clk_disable_unprepare(imx6_pcie->pcie_aux);
break;
default:
break;
}
@ -650,23 +664,9 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)
struct device *dev = pci->dev;
int ret;
ret = clk_prepare_enable(imx6_pcie->pcie_phy);
if (ret) {
dev_err(dev, "unable to enable pcie_phy clock\n");
ret = clk_bulk_prepare_enable(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);
if (ret)
return ret;
}
ret = clk_prepare_enable(imx6_pcie->pcie_bus);
if (ret) {
dev_err(dev, "unable to enable pcie_bus clock\n");
goto err_pcie_bus;
}
ret = clk_prepare_enable(imx6_pcie->pcie);
if (ret) {
dev_err(dev, "unable to enable pcie clock\n");
goto err_pcie;
}
ret = imx6_pcie_enable_ref_clk(imx6_pcie);
if (ret) {
@ -679,11 +679,7 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)
return 0;
err_ref_clk:
clk_disable_unprepare(imx6_pcie->pcie);
err_pcie:
clk_disable_unprepare(imx6_pcie->pcie_bus);
err_pcie_bus:
clk_disable_unprepare(imx6_pcie->pcie_phy);
clk_bulk_disable_unprepare(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);
return ret;
}
@ -691,25 +687,15 @@ static int imx6_pcie_clk_enable(struct imx6_pcie *imx6_pcie)
static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
{
imx6_pcie_disable_ref_clk(imx6_pcie);
clk_disable_unprepare(imx6_pcie->pcie);
clk_disable_unprepare(imx6_pcie->pcie_bus);
clk_disable_unprepare(imx6_pcie->pcie_phy);
clk_bulk_disable_unprepare(imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);
}
static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
{
reset_control_assert(imx6_pcie->pciephy_reset);
reset_control_assert(imx6_pcie->apps_reset);
switch (imx6_pcie->drvdata->variant) {
case IMX7D:
case IMX8MQ:
case IMX8MQ_EP:
reset_control_assert(imx6_pcie->pciephy_reset);
fallthrough;
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
reset_control_assert(imx6_pcie->apps_reset);
break;
case IMX6SX:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6SX_GPR12_PCIE_TEST_POWERDOWN,
@ -730,6 +716,8 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
break;
default:
break;
}
/* Some boards don't have PCIe reset GPIO. */
@ -743,14 +731,10 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
struct dw_pcie *pci = imx6_pcie->pci;
struct device *dev = pci->dev;
switch (imx6_pcie->drvdata->variant) {
case IMX8MQ:
case IMX8MQ_EP:
reset_control_deassert(imx6_pcie->pciephy_reset);
break;
case IMX7D:
reset_control_deassert(imx6_pcie->pciephy_reset);
reset_control_deassert(imx6_pcie->pciephy_reset);
switch (imx6_pcie->drvdata->variant) {
case IMX7D:
/* Workaround for ERR010728, failure of PCI-e PLL VCO to
* oscillate, especially when cold. This turns off "Duty-cycle
* Corrector" and other mysterious undocumented things.
@ -782,11 +766,7 @@ static int imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
usleep_range(200, 500);
break;
case IMX6Q: /* Nothing to do */
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
default:
break;
}
@ -824,48 +804,25 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
static void imx6_pcie_ltssm_enable(struct device *dev)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata;
switch (imx6_pcie->drvdata->variant) {
case IMX6Q:
case IMX6SX:
case IMX6QP:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2,
IMX6Q_GPR12_PCIE_CTL_2);
break;
case IMX7D:
case IMX8MQ:
case IMX8MQ_EP:
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
reset_control_deassert(imx6_pcie->apps_reset);
break;
}
if (drvdata->ltssm_mask)
regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->ltssm_off, drvdata->ltssm_mask,
drvdata->ltssm_mask);
reset_control_deassert(imx6_pcie->apps_reset);
}
static void imx6_pcie_ltssm_disable(struct device *dev)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
const struct imx6_pcie_drvdata *drvdata = imx6_pcie->drvdata;
switch (imx6_pcie->drvdata->variant) {
case IMX6Q:
case IMX6SX:
case IMX6QP:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0);
break;
case IMX7D:
case IMX8MQ:
case IMX8MQ_EP:
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
reset_control_assert(imx6_pcie->apps_reset);
break;
}
if (drvdata->ltssm_mask)
regmap_update_bits(imx6_pcie->iomuxc_gpr, drvdata->ltssm_off,
drvdata->ltssm_mask, 0);
reset_control_assert(imx6_pcie->apps_reset);
}
static int imx6_pcie_start_link(struct dw_pcie *pci)
@ -977,7 +934,11 @@ static int imx6_pcie_host_init(struct dw_pcie_rp *pp)
}
imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
if (imx6_pcie->drvdata->init_phy)
imx6_pcie->drvdata->init_phy(imx6_pcie);
imx6_pcie_configure_type(imx6_pcie);
ret = imx6_pcie_clk_enable(imx6_pcie);
if (ret) {
@ -1081,14 +1042,35 @@ static const struct pci_epc_features imx8m_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = false,
.reserved_bar = 1 << BAR_1 | 1 << BAR_3,
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.align = SZ_64K,
};
/*
* BAR# | Default BAR enable | Default BAR Type | Default BAR Size | BAR Sizing Scheme
* ================================================================================================
* BAR0 | Enable | 64-bit | 1 MB | Programmable Size
* BAR1 | Disable | 32-bit | 64 KB | Fixed Size
* BAR1 should be disabled if BAR0 is 64bit.
* BAR2 | Enable | 32-bit | 1 MB | Programmable Size
* BAR3 | Enable | 32-bit | 64 KB | Programmable Size
* BAR4 | Enable | 32-bit | 1M | Programmable Size
* BAR5 | Enable | 32-bit | 64 KB | Programmable Size
*/
static const struct pci_epc_features imx95_pcie_epc_features = {
.msi_capable = true,
.bar[BAR_1] = { .type = BAR_FIXED, .fixed_size = SZ_64K, },
.align = SZ_4K,
};
static const struct pci_epc_features*
imx6_pcie_ep_get_features(struct dw_pcie_ep *ep)
{
return &imx8m_pcie_epc_features;
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
return imx6_pcie->drvdata->epc_features;
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
@ -1103,7 +1085,6 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,
int ret;
unsigned int pcie_dbi2_offset;
struct dw_pcie_ep *ep;
struct resource *res;
struct dw_pcie *pci = imx6_pcie->pci;
struct dw_pcie_rp *pp = &pci->pp;
struct device *dev = pci->dev;
@ -1122,14 +1103,20 @@ static int imx6_add_pcie_ep(struct imx6_pcie *imx6_pcie,
pcie_dbi2_offset = SZ_4K;
break;
}
pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset;
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;
pci->dbi_base2 = pci->dbi_base + pcie_dbi2_offset;
/*
* FIXME: Ideally, dbi2 base address should come from DT. But since only IMX95 is defining
* "dbi2" in DT, "dbi_base2" is set to NULL here for that platform alone so that the DWC
* core code can fetch that from DT. But once all platform DTs were fixed, this and the
* above "dbi_base2" setting should be removed.
*/
if (device_property_match_string(dev, "reg-names", "dbi2") >= 0)
pci->dbi_base2 = NULL;
if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_SUPPORT_64BIT))
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
ret = dw_pcie_ep_init(ep);
if (ret) {
@ -1251,6 +1238,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
int ret;
u16 val;
int i;
imx6_pcie = devm_kzalloc(dev, sizeof(*imx6_pcie), GFP_KERNEL);
if (!imx6_pcie)
@ -1304,81 +1292,48 @@ static int imx6_pcie_probe(struct platform_device *pdev)
return imx6_pcie->reset_gpio;
}
if (imx6_pcie->drvdata->clks_cnt >= IMX6_PCIE_MAX_CLKS)
return dev_err_probe(dev, -ENOMEM, "clks_cnt is too big\n");
for (i = 0; i < imx6_pcie->drvdata->clks_cnt; i++)
imx6_pcie->clks[i].id = imx6_pcie->drvdata->clk_names[i];
/* Fetch clocks */
imx6_pcie->pcie_bus = devm_clk_get(dev, "pcie_bus");
if (IS_ERR(imx6_pcie->pcie_bus))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_bus),
"pcie_bus clock source missing or invalid\n");
imx6_pcie->pcie = devm_clk_get(dev, "pcie");
if (IS_ERR(imx6_pcie->pcie))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie),
"pcie clock source missing or invalid\n");
switch (imx6_pcie->drvdata->variant) {
case IMX6SX:
imx6_pcie->pcie_inbound_axi = devm_clk_get(dev,
"pcie_inbound_axi");
if (IS_ERR(imx6_pcie->pcie_inbound_axi))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_inbound_axi),
"pcie_inbound_axi clock missing or invalid\n");
break;
case IMX8MQ:
case IMX8MQ_EP:
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
if (IS_ERR(imx6_pcie->pcie_aux))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
"pcie_aux clock source missing or invalid\n");
fallthrough;
case IMX7D:
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
imx6_pcie->controller_id = 1;
imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev,
"pciephy");
if (IS_ERR(imx6_pcie->pciephy_reset)) {
dev_err(dev, "Failed to get PCIEPHY reset control\n");
return PTR_ERR(imx6_pcie->pciephy_reset);
}
imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev,
"apps");
if (IS_ERR(imx6_pcie->apps_reset)) {
dev_err(dev, "Failed to get PCIE APPS reset control\n");
return PTR_ERR(imx6_pcie->apps_reset);
}
break;
case IMX8MM:
case IMX8MM_EP:
case IMX8MP:
case IMX8MP_EP:
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
if (IS_ERR(imx6_pcie->pcie_aux))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_aux),
"pcie_aux clock source missing or invalid\n");
imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev,
"apps");
if (IS_ERR(imx6_pcie->apps_reset))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->apps_reset),
"failed to get pcie apps reset control\n");
ret = devm_clk_bulk_get(dev, imx6_pcie->drvdata->clks_cnt, imx6_pcie->clks);
if (ret)
return ret;
if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_PHYDRV)) {
imx6_pcie->phy = devm_phy_get(dev, "pcie-phy");
if (IS_ERR(imx6_pcie->phy))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->phy),
"failed to get pcie phy\n");
}
if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_APP_RESET)) {
imx6_pcie->apps_reset = devm_reset_control_get_exclusive(dev, "apps");
if (IS_ERR(imx6_pcie->apps_reset))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->apps_reset),
"failed to get pcie apps reset control\n");
}
if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_PHY_RESET)) {
imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev, "pciephy");
if (IS_ERR(imx6_pcie->pciephy_reset))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pciephy_reset),
"Failed to get PCIEPHY reset control\n");
}
switch (imx6_pcie->drvdata->variant) {
case IMX8MQ:
case IMX8MQ_EP:
case IMX7D:
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
imx6_pcie->controller_id = 1;
break;
default:
break;
}
/* Don't fetch the pcie_phy clock, if it has abstract PHY driver */
if (imx6_pcie->phy == NULL) {
imx6_pcie->pcie_phy = devm_clk_get(dev, "pcie_phy");
if (IS_ERR(imx6_pcie->pcie_phy))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->pcie_phy),
"pcie_phy clock source missing or invalid\n");
}
/* Grab turnoff reset */
imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
@ -1387,12 +1342,32 @@ static int imx6_pcie_probe(struct platform_device *pdev)
return PTR_ERR(imx6_pcie->turnoff_reset);
}
if (imx6_pcie->drvdata->gpr) {
/* Grab GPR config register range */
imx6_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible(imx6_pcie->drvdata->gpr);
if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
dev_err(dev, "unable to find iomuxc registers\n");
return PTR_ERR(imx6_pcie->iomuxc_gpr);
imx6_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible(imx6_pcie->drvdata->gpr);
if (IS_ERR(imx6_pcie->iomuxc_gpr))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->iomuxc_gpr),
"unable to find iomuxc registers\n");
}
if (imx6_check_flag(imx6_pcie, IMX6_PCIE_FLAG_HAS_SERDES)) {
void __iomem *off = devm_platform_ioremap_resource_byname(pdev, "app");
if (IS_ERR(off))
return dev_err_probe(dev, PTR_ERR(off),
"unable to find serdes registers\n");
static const struct regmap_config regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
imx6_pcie->iomuxc_gpr = devm_regmap_init_mmio(dev, off, &regmap_config);
if (IS_ERR(imx6_pcie->iomuxc_gpr))
return dev_err_probe(dev, PTR_ERR(imx6_pcie->iomuxc_gpr),
"unable to find iomuxc registers\n");
}
/* Grab PCIe PHY Tx Settings */
@ -1469,6 +1444,11 @@ static void imx6_pcie_shutdown(struct platform_device *pdev)
imx6_pcie_assert_core_reset(imx6_pcie);
}
static const char * const imx6q_clks[] = {"pcie_bus", "pcie", "pcie_phy"};
static const char * const imx8mm_clks[] = {"pcie_bus", "pcie", "pcie_aux"};
static const char * const imx8mq_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_aux"};
static const char * const imx6sx_clks[] = {"pcie_bus", "pcie", "pcie_phy", "pcie_inbound_axi"};
static const struct imx6_pcie_drvdata drvdata[] = {
[IMX6Q] = {
.variant = IMX6Q,
@ -1476,6 +1456,13 @@ static const struct imx6_pcie_drvdata drvdata[] = {
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
.dbi_length = 0x200,
.gpr = "fsl,imx6q-iomuxc-gpr",
.clk_names = imx6q_clks,
.clks_cnt = ARRAY_SIZE(imx6q_clks),
.ltssm_off = IOMUXC_GPR12,
.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2,
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.init_phy = imx6_pcie_init_phy,
},
[IMX6SX] = {
.variant = IMX6SX,
@ -1483,6 +1470,13 @@ static const struct imx6_pcie_drvdata drvdata[] = {
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE |
IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.gpr = "fsl,imx6q-iomuxc-gpr",
.clk_names = imx6sx_clks,
.clks_cnt = ARRAY_SIZE(imx6sx_clks),
.ltssm_off = IOMUXC_GPR12,
.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2,
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.init_phy = imx6sx_pcie_init_phy,
},
[IMX6QP] = {
.variant = IMX6QP,
@ -1491,40 +1485,122 @@ static const struct imx6_pcie_drvdata drvdata[] = {
IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.dbi_length = 0x200,
.gpr = "fsl,imx6q-iomuxc-gpr",
.clk_names = imx6q_clks,
.clks_cnt = ARRAY_SIZE(imx6q_clks),
.ltssm_off = IOMUXC_GPR12,
.ltssm_mask = IMX6Q_GPR12_PCIE_CTL_2,
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.init_phy = imx6_pcie_init_phy,
},
[IMX7D] = {
.variant = IMX7D,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND |
IMX6_PCIE_FLAG_HAS_APP_RESET |
IMX6_PCIE_FLAG_HAS_PHY_RESET,
.gpr = "fsl,imx7d-iomuxc-gpr",
.clk_names = imx6q_clks,
.clks_cnt = ARRAY_SIZE(imx6q_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.init_phy = imx7d_pcie_init_phy,
},
[IMX8MQ] = {
.variant = IMX8MQ,
.flags = IMX6_PCIE_FLAG_HAS_APP_RESET |
IMX6_PCIE_FLAG_HAS_PHY_RESET,
.gpr = "fsl,imx8mq-iomuxc-gpr",
.clk_names = imx8mq_clks,
.clks_cnt = ARRAY_SIZE(imx8mq_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.mode_off[1] = IOMUXC_GPR12,
.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
.init_phy = imx8mq_pcie_init_phy,
},
[IMX8MM] = {
.variant = IMX8MM,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND |
IMX6_PCIE_FLAG_HAS_PHYDRV |
IMX6_PCIE_FLAG_HAS_APP_RESET,
.gpr = "fsl,imx8mm-iomuxc-gpr",
.clk_names = imx8mm_clks,
.clks_cnt = ARRAY_SIZE(imx8mm_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
},
[IMX8MP] = {
.variant = IMX8MP,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND,
.flags = IMX6_PCIE_FLAG_SUPPORTS_SUSPEND |
IMX6_PCIE_FLAG_HAS_PHYDRV |
IMX6_PCIE_FLAG_HAS_APP_RESET,
.gpr = "fsl,imx8mp-iomuxc-gpr",
.clk_names = imx8mm_clks,
.clks_cnt = ARRAY_SIZE(imx8mm_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
},
[IMX95] = {
.variant = IMX95,
.flags = IMX6_PCIE_FLAG_HAS_SERDES,
.clk_names = imx8mq_clks,
.clks_cnt = ARRAY_SIZE(imx8mq_clks),
.ltssm_off = IMX95_PE0_GEN_CTRL_3,
.ltssm_mask = IMX95_PCIE_LTSSM_EN,
.mode_off[0] = IMX95_PE0_GEN_CTRL_1,
.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
.init_phy = imx95_pcie_init_phy,
},
[IMX8MQ_EP] = {
.variant = IMX8MQ_EP,
.flags = IMX6_PCIE_FLAG_HAS_APP_RESET |
IMX6_PCIE_FLAG_HAS_PHY_RESET,
.mode = DW_PCIE_EP_TYPE,
.gpr = "fsl,imx8mq-iomuxc-gpr",
.clk_names = imx8mq_clks,
.clks_cnt = ARRAY_SIZE(imx8mq_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.mode_off[1] = IOMUXC_GPR12,
.mode_mask[1] = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
.epc_features = &imx8m_pcie_epc_features,
.init_phy = imx8mq_pcie_init_phy,
},
[IMX8MM_EP] = {
.variant = IMX8MM_EP,
.flags = IMX6_PCIE_FLAG_HAS_PHYDRV,
.mode = DW_PCIE_EP_TYPE,
.gpr = "fsl,imx8mm-iomuxc-gpr",
.clk_names = imx8mm_clks,
.clks_cnt = ARRAY_SIZE(imx8mm_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.epc_features = &imx8m_pcie_epc_features,
},
[IMX8MP_EP] = {
.variant = IMX8MP_EP,
.flags = IMX6_PCIE_FLAG_HAS_PHYDRV,
.mode = DW_PCIE_EP_TYPE,
.gpr = "fsl,imx8mp-iomuxc-gpr",
.clk_names = imx8mm_clks,
.clks_cnt = ARRAY_SIZE(imx8mm_clks),
.mode_off[0] = IOMUXC_GPR12,
.mode_mask[0] = IMX6Q_GPR12_DEVICE_TYPE,
.epc_features = &imx8m_pcie_epc_features,
},
[IMX95_EP] = {
.variant = IMX95_EP,
.flags = IMX6_PCIE_FLAG_HAS_SERDES |
IMX6_PCIE_FLAG_SUPPORT_64BIT,
.clk_names = imx8mq_clks,
.clks_cnt = ARRAY_SIZE(imx8mq_clks),
.ltssm_off = IMX95_PE0_GEN_CTRL_3,
.ltssm_mask = IMX95_PCIE_LTSSM_EN,
.mode_off[0] = IMX95_PE0_GEN_CTRL_1,
.mode_mask[0] = IMX95_PCIE_DEVICE_TYPE,
.init_phy = imx95_pcie_init_phy,
.epc_features = &imx95_pcie_epc_features,
.mode = DW_PCIE_EP_TYPE,
},
};
@ -1536,9 +1612,11 @@ static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], },
{ .compatible = "fsl,imx8mm-pcie", .data = &drvdata[IMX8MM], },
{ .compatible = "fsl,imx8mp-pcie", .data = &drvdata[IMX8MP], },
{ .compatible = "fsl,imx95-pcie", .data = &drvdata[IMX95], },
{ .compatible = "fsl,imx8mq-pcie-ep", .data = &drvdata[IMX8MQ_EP], },
{ .compatible = "fsl,imx8mm-pcie-ep", .data = &drvdata[IMX8MM_EP], },
{ .compatible = "fsl,imx8mp-pcie-ep", .data = &drvdata[IMX8MP_EP], },
{ .compatible = "fsl,imx95-pcie-ep", .data = &drvdata[IMX95_EP], },
{},
};

View File

@ -924,12 +924,12 @@ static const struct pci_epc_features ks_pcie_am654_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = true,
.reserved_bar = 1 << BAR_0 | 1 << BAR_1,
.bar_fixed_64bit = 1 << BAR_0,
.bar_fixed_size[2] = SZ_1M,
.bar_fixed_size[3] = SZ_64K,
.bar_fixed_size[4] = 256,
.bar_fixed_size[5] = SZ_1M,
.bar[BAR_0] = { .type = BAR_RESERVED, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.bar[BAR_3] = { .type = BAR_FIXED, .fixed_size = SZ_64K, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256, },
.bar[BAR_5] = { .type = BAR_FIXED, .fixed_size = SZ_1M, },
.align = SZ_1M,
};

View File

@ -250,7 +250,10 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
pci->dev = dev;
pci->ops = pcie->drvdata->dw_pcie_ops;
ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4);
ls_epc->bar[BAR_2].only_64bit = true;
ls_epc->bar[BAR_3].type = BAR_RESERVED;
ls_epc->bar[BAR_4].only_64bit = true;
ls_epc->bar[BAR_5].type = BAR_RESERVED;
ls_epc->linkup_notifier = true;
pcie->pci = pci;

View File

@ -629,8 +629,13 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
PCI_REBAR_CTRL_NBAR_SHIFT;
/*
* PCIe r6.0, sec 7.8.6.2 require us to support at least one
* size in the range from 1 MB to 512 GB. Advertise support
* for 1 MB BAR size only.
*/
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, BIT(4));
}
/*

View File

@ -328,7 +328,7 @@ static int dw_pcie_msi_host_init(struct dw_pcie_rp *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct device *dev = pci->dev;
struct platform_device *pdev = to_platform_device(dev);
u64 *msi_vaddr;
u64 *msi_vaddr = NULL;
int ret;
u32 ctrl, num_ctrls;
@ -379,15 +379,20 @@ static int dw_pcie_msi_host_init(struct dw_pcie_rp *pp)
* memory.
*/
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret)
dev_warn(dev, "Failed to set DMA mask to 32-bit. Devices with only 32-bit MSI support may not work properly\n");
if (!ret)
msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data,
GFP_KERNEL);
msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data,
GFP_KERNEL);
if (!msi_vaddr) {
dev_err(dev, "Failed to alloc and map MSI data\n");
dw_pcie_free_msi(pp);
return -ENOMEM;
dev_warn(dev, "Failed to allocate 32-bit MSI address\n");
dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
msi_vaddr = dmam_alloc_coherent(dev, sizeof(u64), &pp->msi_data,
GFP_KERNEL);
if (!msi_vaddr) {
dev_err(dev, "Failed to allocate MSI address\n");
dw_pcie_free_msi(pp);
return -ENOMEM;
}
}
return 0;

View File

@ -312,8 +312,12 @@ static const struct pci_epc_features keembay_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = true,
.reserved_bar = BIT(BAR_1) | BIT(BAR_3) | BIT(BAR_5),
.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.align = SZ_16K,
};

View File

@ -53,6 +53,7 @@
#define PARF_SLV_ADDR_SPACE_SIZE 0x358
#define PARF_DEVICE_TYPE 0x1000
#define PARF_BDF_TO_SID_TABLE_N 0x2000
#define PARF_BDF_TO_SID_CFG 0x2c00
/* ELBI registers */
#define ELBI_SYS_CTRL 0x04
@ -120,6 +121,9 @@
/* PARF_DEVICE_TYPE register fields */
#define DEVICE_TYPE_RC 0x4
/* PARF_BDF_TO_SID_CFG fields */
#define BDF_TO_SID_BYPASS BIT(0)
/* ELBI_SYS_CTRL register fields */
#define ELBI_SYS_CTRL_LT_ENABLE BIT(0)
@ -229,6 +233,7 @@ struct qcom_pcie_ops {
struct qcom_pcie_cfg {
const struct qcom_pcie_ops *ops;
bool no_l0s;
};
struct qcom_pcie {
@ -272,6 +277,26 @@ static int qcom_pcie_start_link(struct dw_pcie *pci)
return 0;
}
static void qcom_pcie_clear_aspm_l0s(struct dw_pcie *pci)
{
struct qcom_pcie *pcie = to_qcom_pcie(pci);
u16 offset;
u32 val;
if (!pcie->cfg->no_l0s)
return;
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
dw_pcie_dbi_ro_wr_en(pci);
val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
val &= ~PCI_EXP_LNKCAP_ASPM_L0S;
writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
dw_pcie_dbi_ro_wr_dis(pci);
}
static void qcom_pcie_clear_hpc(struct dw_pcie *pci)
{
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
@ -961,6 +986,7 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
{
qcom_pcie_clear_aspm_l0s(pcie->pci);
qcom_pcie_clear_hpc(pcie->pci);
return 0;
@ -1008,11 +1034,17 @@ static int qcom_pcie_config_sid_1_9_0(struct qcom_pcie *pcie)
u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
int i, nr_map, size = 0;
u32 smmu_sid_base;
u32 val;
of_get_property(dev->of_node, "iommu-map", &size);
if (!size)
return 0;
/* Enable BDF to SID translation by disabling bypass mode (default) */
val = readl(pcie->parf + PARF_BDF_TO_SID_CFG);
val &= ~BDF_TO_SID_BYPASS;
writel(val, pcie->parf + PARF_BDF_TO_SID_CFG);
map = kzalloc(size, GFP_KERNEL);
if (!map)
return -ENOMEM;
@ -1358,6 +1390,11 @@ static const struct qcom_pcie_cfg cfg_2_9_0 = {
.ops = &ops_2_9_0,
};
static const struct qcom_pcie_cfg cfg_sc8280xp = {
.ops = &ops_1_9_0,
.no_l0s = true,
};
static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = qcom_pcie_link_up,
.start_link = qcom_pcie_start_link,
@ -1629,11 +1666,11 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-ipq8074-gen3", .data = &cfg_2_9_0 },
{ .compatible = "qcom,pcie-msm8996", .data = &cfg_2_3_2 },
{ .compatible = "qcom,pcie-qcs404", .data = &cfg_2_4_0 },
{ .compatible = "qcom,pcie-sa8540p", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sa8540p", .data = &cfg_sc8280xp },
{ .compatible = "qcom,pcie-sa8775p", .data = &cfg_1_9_0},
{ .compatible = "qcom,pcie-sc7280", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sc8180x", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sc8280xp", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sc8280xp", .data = &cfg_sc8280xp },
{ .compatible = "qcom,pcie-sdm845", .data = &cfg_2_7_0 },
{ .compatible = "qcom,pcie-sdx55", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8150", .data = &cfg_1_9_0 },
@ -1642,6 +1679,7 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-sm8450-pcie0", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8450-pcie1", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-sm8550", .data = &cfg_1_9_0 },
{ .compatible = "qcom,pcie-x1e80100", .data = &cfg_1_9_0 },
{ }
};

View File

@ -383,7 +383,9 @@ static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = false,
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
.align = SZ_1M,
};

View File

@ -2007,9 +2007,13 @@ static const struct pci_epc_features tegra_pcie_epc_features = {
.core_init_notifier = true,
.msi_capable = false,
.msix_capable = false,
.reserved_bar = 1 << BAR_2 | 1 << BAR_3 | 1 << BAR_4 | 1 << BAR_5,
.bar_fixed_64bit = 1 << BAR_0,
.bar_fixed_size[0] = SZ_1M,
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = SZ_1M,
.only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_RESERVED, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
};
static const struct pci_epc_features*

View File

@ -411,8 +411,12 @@ static const struct uniphier_pcie_ep_soc_data uniphier_pro5_data = {
.msi_capable = true,
.msix_capable = false,
.align = 1 << 16,
.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
.reserved_bar = BIT(BAR_4),
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_RESERVED, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
},
};
@ -425,7 +429,12 @@ static const struct uniphier_pcie_ep_soc_data uniphier_nx1_data = {
.msi_capable = true,
.msix_capable = false,
.align = 1 << 12,
.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
.bar[BAR_0] = { .only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
},
};

View File

@ -49,6 +49,7 @@
#include <linux/refcount.h>
#include <linux/irqdomain.h>
#include <linux/acpi.h>
#include <linux/sizes.h>
#include <asm/mshyperv.h>
/*
@ -465,7 +466,7 @@ struct pci_eject_response {
u32 status;
} __packed;
static int pci_ring_size = (4 * PAGE_SIZE);
static int pci_ring_size = VMBUS_RING_SIZE(SZ_16K);
/*
* Driver specific state.

View File

@ -336,7 +336,7 @@ static int brcm_pcie_mdio_write(void __iomem *base, u8 port,
readl(base + PCIE_RC_DL_MDIO_ADDR);
writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA);
err = readw_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_WR_DATA, data,
err = readl_poll_timeout_atomic(base + PCIE_RC_DL_MDIO_WR_DATA, data,
MDIO_WT_DONE(data), 10, 100);
return err;
}

View File

@ -440,11 +440,15 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
.msi_capable = true,
.msix_capable = false,
/* use 64-bit BARs so mark BAR[1,3,5] as reserved */
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
.bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4,
.bar_fixed_size[0] = 128,
.bar_fixed_size[2] = 256,
.bar_fixed_size[4] = 256,
.bar[BAR_0] = { .type = BAR_FIXED, .fixed_size = 128,
.only_64bit = true, },
.bar[BAR_1] = { .type = BAR_RESERVED, },
.bar[BAR_2] = { .type = BAR_FIXED, .fixed_size = 256,
.only_64bit = true, },
.bar[BAR_3] = { .type = BAR_RESERVED, },
.bar[BAR_4] = { .type = BAR_FIXED, .fixed_size = 256,
.only_64bit = true, },
.bar[BAR_5] = { .type = BAR_RESERVED, },
};
static const struct pci_epc_features*

448
drivers/pci/devres.c Normal file
View File

@ -0,0 +1,448 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/device.h>
#include <linux/pci.h>
#include "pci.h"
/*
* PCI iomap devres
*/
#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
struct pcim_iomap_devres {
void __iomem *table[PCIM_IOMAP_MAX];
};
static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
{
struct resource **res = ptr;
pci_unmap_iospace(*res);
}
/**
* devm_pci_remap_iospace - Managed pci_remap_iospace()
* @dev: Generic device to remap IO address for
* @res: Resource describing the I/O space
* @phys_addr: physical address of range to be mapped
*
* Managed pci_remap_iospace(). Map is automatically unmapped on driver
* detach.
*/
int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
phys_addr_t phys_addr)
{
const struct resource **ptr;
int error;
ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
error = pci_remap_iospace(res, phys_addr);
if (error) {
devres_free(ptr);
} else {
*ptr = res;
devres_add(dev, ptr);
}
return error;
}
EXPORT_SYMBOL(devm_pci_remap_iospace);
/**
* devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
* @dev: Generic device to remap IO address for
* @offset: Resource address to map
* @size: Size of map
*
* Managed pci_remap_cfgspace(). Map is automatically unmapped on driver
* detach.
*/
void __iomem *devm_pci_remap_cfgspace(struct device *dev,
resource_size_t offset,
resource_size_t size)
{
void __iomem **ptr, *addr;
ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
addr = pci_remap_cfgspace(offset, size);
if (addr) {
*ptr = addr;
devres_add(dev, ptr);
} else
devres_free(ptr);
return addr;
}
EXPORT_SYMBOL(devm_pci_remap_cfgspace);
/**
* devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
* @dev: generic device to handle the resource for
* @res: configuration space resource to be handled
*
* Checks that a resource is a valid memory region, requests the memory
* region and ioremaps with pci_remap_cfgspace() API that ensures the
* proper PCI configuration space memory attributes are guaranteed.
*
* All operations are managed and will be undone on driver detach.
*
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure. Usage example::
*
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
* base = devm_pci_remap_cfg_resource(&pdev->dev, res);
* if (IS_ERR(base))
* return PTR_ERR(base);
*/
void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
struct resource *res)
{
resource_size_t size;
const char *name;
void __iomem *dest_ptr;
BUG_ON(!dev);
if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, "invalid resource\n");
return IOMEM_ERR_PTR(-EINVAL);
}
size = resource_size(res);
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);
return IOMEM_ERR_PTR(-EBUSY);
}
dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
if (!dest_ptr) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
devm_release_mem_region(dev, res->start, size);
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
}
return dest_ptr;
}
EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
/**
* pcim_set_mwi - a device-managed pci_set_mwi()
* @dev: the PCI device for which MWI is enabled
*
* Managed pci_set_mwi().
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
int pcim_set_mwi(struct pci_dev *dev)
{
struct pci_devres *dr;
dr = find_pci_dr(dev);
if (!dr)
return -ENOMEM;
dr->mwi = 1;
return pci_set_mwi(dev);
}
EXPORT_SYMBOL(pcim_set_mwi);
static void pcim_release(struct device *gendev, void *res)
{
struct pci_dev *dev = to_pci_dev(gendev);
struct pci_devres *this = res;
int i;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
if (this->region_mask & (1 << i))
pci_release_region(dev, i);
if (this->mwi)
pci_clear_mwi(dev);
if (this->restore_intx)
pci_intx(dev, this->orig_intx);
if (this->enabled && !this->pinned)
pci_disable_device(dev);
}
/*
* TODO: After the last four callers in pci.c are ported, find_pci_dr()
* needs to be made static again.
*/
struct pci_devres *find_pci_dr(struct pci_dev *pdev)
{
if (pci_is_managed(pdev))
return devres_find(&pdev->dev, pcim_release, NULL, NULL);
return NULL;
}
static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
{
struct pci_devres *dr, *new_dr;
dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
if (dr)
return dr;
new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
if (!new_dr)
return NULL;
return devres_get(&pdev->dev, new_dr, NULL, NULL);
}
/**
* pcim_enable_device - Managed pci_enable_device()
* @pdev: PCI device to be initialized
*
* Managed pci_enable_device().
*/
int pcim_enable_device(struct pci_dev *pdev)
{
struct pci_devres *dr;
int rc;
dr = get_pci_dr(pdev);
if (unlikely(!dr))
return -ENOMEM;
if (dr->enabled)
return 0;
rc = pci_enable_device(pdev);
if (!rc) {
pdev->is_managed = 1;
dr->enabled = 1;
}
return rc;
}
EXPORT_SYMBOL(pcim_enable_device);
/**
* pcim_pin_device - Pin managed PCI device
* @pdev: PCI device to pin
*
* Pin managed PCI device @pdev. Pinned device won't be disabled on
* driver detach. @pdev must have been enabled with
* pcim_enable_device().
*/
void pcim_pin_device(struct pci_dev *pdev)
{
struct pci_devres *dr;
dr = find_pci_dr(pdev);
WARN_ON(!dr || !dr->enabled);
if (dr)
dr->pinned = 1;
}
EXPORT_SYMBOL(pcim_pin_device);
static void pcim_iomap_release(struct device *gendev, void *res)
{
struct pci_dev *dev = to_pci_dev(gendev);
struct pcim_iomap_devres *this = res;
int i;
for (i = 0; i < PCIM_IOMAP_MAX; i++)
if (this->table[i])
pci_iounmap(dev, this->table[i]);
}
/**
* pcim_iomap_table - access iomap allocation table
* @pdev: PCI device to access iomap table for
*
* Access iomap allocation table for @dev. If iomap table doesn't
* exist and @pdev is managed, it will be allocated. All iomaps
* recorded in the iomap table are automatically unmapped on driver
* detach.
*
* This function might sleep when the table is first allocated but can
* be safely called without context and guaranteed to succeed once
* allocated.
*/
void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
{
struct pcim_iomap_devres *dr, *new_dr;
dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
if (dr)
return dr->table;
new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
dev_to_node(&pdev->dev));
if (!new_dr)
return NULL;
dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
return dr->table;
}
EXPORT_SYMBOL(pcim_iomap_table);
/**
* pcim_iomap - Managed pcim_iomap()
* @pdev: PCI device to iomap for
* @bar: BAR to iomap
* @maxlen: Maximum length of iomap
*
* Managed pci_iomap(). Map is automatically unmapped on driver
* detach.
*/
void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
{
void __iomem **tbl;
BUG_ON(bar >= PCIM_IOMAP_MAX);
tbl = (void __iomem **)pcim_iomap_table(pdev);
if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
return NULL;
tbl[bar] = pci_iomap(pdev, bar, maxlen);
return tbl[bar];
}
EXPORT_SYMBOL(pcim_iomap);
/**
* pcim_iounmap - Managed pci_iounmap()
* @pdev: PCI device to iounmap for
* @addr: Address to unmap
*
* Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
*/
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
{
void __iomem **tbl;
int i;
pci_iounmap(pdev, addr);
tbl = (void __iomem **)pcim_iomap_table(pdev);
BUG_ON(!tbl);
for (i = 0; i < PCIM_IOMAP_MAX; i++)
if (tbl[i] == addr) {
tbl[i] = NULL;
return;
}
WARN_ON(1);
}
EXPORT_SYMBOL(pcim_iounmap);
/**
* pcim_iomap_regions - Request and iomap PCI BARs
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to request and iomap
* @name: Name used when requesting regions
*
* Request and iomap regions specified by @mask.
*/
int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
{
void __iomem * const *iomap;
int i, rc;
iomap = pcim_iomap_table(pdev);
if (!iomap)
return -ENOMEM;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
unsigned long len;
if (!(mask & (1 << i)))
continue;
rc = -EINVAL;
len = pci_resource_len(pdev, i);
if (!len)
goto err_inval;
rc = pci_request_region(pdev, i, name);
if (rc)
goto err_inval;
rc = -ENOMEM;
if (!pcim_iomap(pdev, i, 0))
goto err_region;
}
return 0;
err_region:
pci_release_region(pdev, i);
err_inval:
while (--i >= 0) {
if (!(mask & (1 << i)))
continue;
pcim_iounmap(pdev, iomap[i]);
pci_release_region(pdev, i);
}
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions);
/**
* pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to iomap
* @name: Name used when requesting regions
*
* Request all PCI BARs and iomap regions specified by @mask.
*/
int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
const char *name)
{
int request_mask = ((1 << 6) - 1) & ~mask;
int rc;
rc = pci_request_selected_regions(pdev, request_mask, name);
if (rc)
return rc;
rc = pcim_iomap_regions(pdev, mask, name);
if (rc)
pci_release_selected_regions(pdev, request_mask);
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions_request_all);
/**
* pcim_iounmap_regions - Unmap and release PCI BARs
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to unmap and release
*
* Unmap and release regions specified by @mask.
*/
void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
{
void __iomem * const *iomap;
int i;
iomap = pcim_iomap_table(pdev);
if (!iomap)
return;
for (i = 0; i < PCIM_IOMAP_MAX; i++) {
if (!(mask & (1 << i)))
continue;
pcim_iounmap(pdev, iomap[i]);
pci_release_region(pdev, i);
}
}
EXPORT_SYMBOL(pcim_iounmap_regions);

View File

@ -123,6 +123,22 @@ static const struct pci_epf_mhi_ep_info sm8450_info = {
.flags = MHI_EPF_USE_DMA,
};
static struct pci_epf_header sa8775p_header = {
.vendorid = PCI_VENDOR_ID_QCOM,
.deviceid = 0x0306, /* FIXME: Update deviceid for sa8775p EP */
.baseclass_code = PCI_CLASS_OTHERS,
.interrupt_pin = PCI_INTERRUPT_INTA,
};
static const struct pci_epf_mhi_ep_info sa8775p_info = {
.config = &mhi_v1_config,
.epf_header = &sa8775p_header,
.bar_num = BAR_0,
.epf_flags = PCI_BASE_ADDRESS_MEM_TYPE_32,
.msi_count = 32,
.mru = 0x8000,
};
struct pci_epf_mhi {
const struct pci_epc_features *epc_features;
const struct pci_epf_mhi_ep_info *info;
@ -913,8 +929,9 @@ static int pci_epf_mhi_probe(struct pci_epf *epf,
}
static const struct pci_epf_device_id pci_epf_mhi_ids[] = {
{ .name = "sdx55", .driver_data = (kernel_ulong_t)&sdx55_info },
{ .name = "sm8450", .driver_data = (kernel_ulong_t)&sm8450_info },
{ .name = "pci_epf_mhi_sa8775p", .driver_data = (kernel_ulong_t)&sa8775p_info },
{ .name = "pci_epf_mhi_sdx55", .driver_data = (kernel_ulong_t)&sdx55_info },
{ .name = "pci_epf_mhi_sm8450", .driver_data = (kernel_ulong_t)&sm8450_info },
{},
};

View File

@ -1012,13 +1012,13 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb,
epc_features = ntb_epc->epc_features;
barno = ntb_epc->epf_ntb_bar[BAR_CONFIG];
size = epc_features->bar_fixed_size[barno];
size = epc_features->bar[barno].fixed_size;
align = epc_features->align;
peer_ntb_epc = ntb->epc[!type];
peer_epc_features = peer_ntb_epc->epc_features;
peer_barno = ntb_epc->epf_ntb_bar[BAR_PEER_SPAD];
peer_size = peer_epc_features->bar_fixed_size[peer_barno];
peer_size = peer_epc_features->bar[peer_barno].fixed_size;
/* Check if epc_features is populated incorrectly */
if ((!IS_ALIGNED(size, align)))
@ -1067,7 +1067,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb,
else if (size < ctrl_size + spad_size)
return -EINVAL;
base = pci_epf_alloc_space(epf, size, barno, align, type);
base = pci_epf_alloc_space(epf, size, barno, epc_features, type);
if (!base) {
dev_err(dev, "%s intf: Config/Status/SPAD alloc region fail\n",
pci_epc_interface_string(type));

View File

@ -729,7 +729,7 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
*/
add = (epf_bar->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) ? 2 : 1;
if (!!(epc_features->reserved_bar & (1 << bar)))
if (epc_features->bar[bar].type == BAR_RESERVED)
continue;
ret = pci_epc_set_bar(epc, epf->func_no, epf->vfunc_no,
@ -841,14 +841,8 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
}
test_reg_size = test_reg_bar_size + msix_table_size + pba_size;
if (epc_features->bar_fixed_size[test_reg_bar]) {
if (test_reg_size > bar_size[test_reg_bar])
return -ENOMEM;
test_reg_size = bar_size[test_reg_bar];
}
base = pci_epf_alloc_space(epf, test_reg_size, test_reg_bar,
epc_features->align, PRIMARY_INTERFACE);
epc_features, PRIMARY_INTERFACE);
if (!base) {
dev_err(dev, "Failed to allocated register space\n");
return -ENOMEM;
@ -862,12 +856,11 @@ static int pci_epf_test_alloc_space(struct pci_epf *epf)
if (bar == test_reg_bar)
continue;
if (!!(epc_features->reserved_bar & (1 << bar)))
if (epc_features->bar[bar].type == BAR_RESERVED)
continue;
base = pci_epf_alloc_space(epf, bar_size[bar], bar,
epc_features->align,
PRIMARY_INTERFACE);
epc_features, PRIMARY_INTERFACE);
if (!base)
dev_err(dev, "Failed to allocate space for BAR%d\n",
bar);
@ -881,16 +874,12 @@ static void pci_epf_configure_bar(struct pci_epf *epf,
const struct pci_epc_features *epc_features)
{
struct pci_epf_bar *epf_bar;
bool bar_fixed_64bit;
int i;
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
epf_bar = &epf->bar[i];
bar_fixed_64bit = !!(epc_features->bar_fixed_64bit & (1 << i));
if (bar_fixed_64bit)
if (epc_features->bar[i].only_64bit)
epf_bar->flags |= PCI_BASE_ADDRESS_MEM_TYPE_64;
if (epc_features->bar_fixed_size[i])
bar_size[i] = epc_features->bar_fixed_size[i];
}
}

View File

@ -422,7 +422,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
epf->func_no,
epf->vfunc_no);
barno = ntb->epf_ntb_bar[BAR_CONFIG];
size = epc_features->bar_fixed_size[barno];
size = epc_features->bar[barno].fixed_size;
align = epc_features->align;
if ((!IS_ALIGNED(size, align)))
@ -446,7 +446,7 @@ static int epf_ntb_config_spad_bar_alloc(struct epf_ntb *ntb)
else if (size < ctrl_size + spad_size)
return -EINVAL;
base = pci_epf_alloc_space(epf, size, barno, align, 0);
base = pci_epf_alloc_space(epf, size, barno, epc_features, 0);
if (!base) {
dev_err(dev, "Config/Status/SPAD alloc region fail\n");
return -ENOMEM;
@ -527,7 +527,6 @@ static int epf_ntb_configure_interrupt(struct epf_ntb *ntb)
static int epf_ntb_db_bar_init(struct epf_ntb *ntb)
{
const struct pci_epc_features *epc_features;
u32 align;
struct device *dev = &ntb->epf->dev;
int ret;
struct pci_epf_bar *epf_bar;
@ -538,19 +537,9 @@ static int epf_ntb_db_bar_init(struct epf_ntb *ntb)
epc_features = pci_epc_get_features(ntb->epf->epc,
ntb->epf->func_no,
ntb->epf->vfunc_no);
align = epc_features->align;
if (size < 128)
size = 128;
if (align)
size = ALIGN(size, align);
else
size = roundup_pow_of_two(size);
barno = ntb->epf_ntb_bar[BAR_DB];
mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, align, 0);
mw_addr = pci_epf_alloc_space(ntb->epf, size, barno, epc_features, 0);
if (!mw_addr) {
dev_err(dev, "Failed to allocate OB address\n");
return -ENOMEM;
@ -1269,21 +1258,17 @@ static int pci_vntb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(dev, "Cannot set DMA mask\n");
return -EINVAL;
return ret;
}
ret = ntb_register_device(&ndev->ntb);
if (ret) {
dev_err(dev, "Failed to register NTB device\n");
goto err_register_dev;
return ret;
}
dev_dbg(dev, "PCI Virtual NTB driver loaded\n");
return 0;
err_register_dev:
put_device(&ndev->ntb.dev);
return -EINVAL;
}
static struct pci_device_id pci_vntb_table[] = {

View File

@ -87,7 +87,7 @@ EXPORT_SYMBOL_GPL(pci_epc_get);
* @epc_features: pci_epc_features structure that holds the reserved bar bitmap
*
* Invoke to get the first unreserved BAR that can be used by the endpoint
* function. For any incorrect value in reserved_bar return '0'.
* function.
*/
enum pci_barno
pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features)
@ -102,32 +102,27 @@ EXPORT_SYMBOL_GPL(pci_epc_get_first_free_bar);
* @bar: the starting BAR number from where unreserved BAR should be searched
*
* Invoke to get the next unreserved BAR starting from @bar that can be used
* for endpoint function. For any incorrect value in reserved_bar return '0'.
* for endpoint function.
*/
enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
*epc_features, enum pci_barno bar)
{
unsigned long free_bar;
int i;
if (!epc_features)
return BAR_0;
/* If 'bar - 1' is a 64-bit BAR, move to the next BAR */
if ((epc_features->bar_fixed_64bit << 1) & 1 << bar)
if (bar > 0 && epc_features->bar[bar - 1].only_64bit)
bar++;
/* Find if the reserved BAR is also a 64-bit BAR */
free_bar = epc_features->reserved_bar & epc_features->bar_fixed_64bit;
for (i = bar; i < PCI_STD_NUM_BARS; i++) {
/* If the BAR is not reserved, return it. */
if (epc_features->bar[i].type != BAR_RESERVED)
return i;
}
/* Set the adjacent bit if the reserved BAR is also a 64-bit BAR */
free_bar <<= 1;
free_bar |= epc_features->reserved_bar;
free_bar = find_next_zero_bit(&free_bar, 6, bar);
if (free_bar > 5)
return NO_BAR;
return free_bar;
return NO_BAR;
}
EXPORT_SYMBOL_GPL(pci_epc_get_next_free_bar);

View File

@ -17,7 +17,7 @@
static DEFINE_MUTEX(pci_epf_mutex);
static struct bus_type pci_epf_bus_type;
static const struct bus_type pci_epf_bus_type;
static const struct device_type pci_epf_type;
/**
@ -251,14 +251,17 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
* @epf: the EPF device to whom allocate the memory
* @size: the size of the memory that has to be allocated
* @bar: the BAR number corresponding to the allocated register space
* @align: alignment size for the allocation region
* @epc_features: the features provided by the EPC specific to this EPF
* @type: Identifies if the allocation is for primary EPC or secondary EPC
*
* Invoke to allocate memory for the PCI EPF register space.
*/
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
size_t align, enum pci_epc_interface_type type)
const struct pci_epc_features *epc_features,
enum pci_epc_interface_type type)
{
u64 bar_fixed_size = epc_features->bar[bar].fixed_size;
size_t align = epc_features->align;
struct pci_epf_bar *epf_bar;
dma_addr_t phys_addr;
struct pci_epc *epc;
@ -268,6 +271,15 @@ void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
if (size < 128)
size = 128;
if (epc_features->bar[bar].type == BAR_FIXED && bar_fixed_size) {
if (size > bar_fixed_size) {
dev_err(&epf->dev,
"requested BAR size is larger than fixed size\n");
return NULL;
}
size = bar_fixed_size;
}
if (align)
size = ALIGN(size, align);
else
@ -507,7 +519,7 @@ static void pci_epf_device_remove(struct device *dev)
epf->driver = NULL;
}
static struct bus_type pci_epf_bus_type = {
static const struct bus_type pci_epf_bus_type = {
.name = "pci-epf",
.match = pci_epf_device_match,
.probe = pci_epf_device_probe,

View File

@ -9,7 +9,6 @@
#include <linux/export.h>
#ifdef CONFIG_PCI
/**
* pci_iomap_range - create a virtual mapping cookie for a PCI BAR
* @dev: PCI device that owns the BAR
@ -170,11 +169,9 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *p)
if (addr >= start && addr < start + IO_SPACE_LIMIT)
return;
iounmap(p);
#endif
iounmap(p);
}
EXPORT_SYMBOL(pci_iounmap);
#endif /* ARCH_WANTS_GENERIC_PCI_IOUNMAP */
#endif /* CONFIG_PCI */

View File

@ -8,9 +8,13 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include "pci.h"
/**
* pci_request_irq - allocate an interrupt line for a PCI device
* @dev: PCI device to operate on
@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id)
kfree(free_irq(pci_irq_vector(dev, nr), dev_id));
}
EXPORT_SYMBOL(pci_free_irq);
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
*
* Perform INTx swizzling for a device behind one level of bridge. This is
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
* behind bridges on add-in cards. For devices with ARI enabled, the slot
* number is always 0 (see the Implementation Note in section 2.2.8.1 of
* the PCI Express Base Specification, Revision 2.1)
*/
u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
{
int slot;
if (pci_ari_enabled(dev->bus))
slot = 0;
else
slot = PCI_SLOT(dev->devfn);
return (((pin - 1) + slot) % 4) + 1;
}
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
u8 pin;
pin = dev->pin;
if (!pin)
return -1;
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
*bridge = dev;
return pin;
}
/**
* pci_common_swizzle - swizzle INTx all the way to root bridge
* @dev: the PCI device
* @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
*
* Perform INTx swizzling for a device. This traverses through all PCI-to-PCI
* bridges all the way up to a PCI root bus.
*/
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
*pinp = pin;
return PCI_SLOT(dev->devfn);
}
EXPORT_SYMBOL_GPL(pci_common_swizzle);
void pci_assign_irq(struct pci_dev *dev)
{
u8 pin;
u8 slot = -1;
int irq = 0;
struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
if (!(hbrg->map_irq)) {
pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
return;
}
/*
* If this device is not on the primary bus, we need to figure out
* which interrupt pin it will come in on. We know which slot it
* will come in on because that slot is where the bridge is. Each
* time the interrupt line passes through a PCI-PCI bridge we must
* apply the swizzle function.
*/
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
/* Cope with illegal. */
if (pin > 4)
pin = 1;
if (pin) {
/* Follow the chain of bridges, swizzling as we go. */
if (hbrg->swizzle_irq)
slot = (*(hbrg->swizzle_irq))(dev, &pin);
/*
* If a swizzling function is not used, map_irq() must
* ignore slot.
*/
irq = (*(hbrg->map_irq))(dev, slot, pin);
if (irq == -1)
irq = 0;
}
dev->irq = irq;
pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
/*
* Always tell the device, so the driver knows what is the real IRQ
* to use; the device does not use it.
*/
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
{
struct pci_bus *bus = dev->bus;
bool mask_updated = true;
u32 cmd_status_dword;
u16 origcmd, newcmd;
unsigned long flags;
bool irq_pending;
/*
* We do a single dword read to retrieve both command and status.
* Document assumptions that make this possible.
*/
BUILD_BUG_ON(PCI_COMMAND % 4);
BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
raw_spin_lock_irqsave(&pci_lock, flags);
bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
/*
* Check interrupt status register to see whether our device
* triggered the interrupt (when masking) or the next IRQ is
* already pending (when unmasking).
*/
if (mask != irq_pending) {
mask_updated = false;
goto done;
}
origcmd = cmd_status_dword;
newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
if (mask)
newcmd |= PCI_COMMAND_INTX_DISABLE;
if (newcmd != origcmd)
bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
done:
raw_spin_unlock_irqrestore(&pci_lock, flags);
return mask_updated;
}
/**
* pci_check_and_mask_intx - mask INTx on pending interrupt
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, mask it and return
* true in that case. False is returned if no interrupt was pending.
*/
bool pci_check_and_mask_intx(struct pci_dev *dev)
{
return pci_check_and_set_intx_mask(dev, true);
}
EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
/**
* pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, unmask it if not and
* return true. False is returned and the mask remains active if there was
* still an interrupt pending.
*/
bool pci_check_and_unmask_intx(struct pci_dev *dev)
{
return pci_check_and_set_intx_mask(dev, false);
}
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
/**
* pcibios_penalize_isa_irq - penalize an ISA IRQ
* @irq: ISA IRQ to penalize
* @active: IRQ active or not
*
* Permits the platform to provide architecture-specific functionality when
* penalizing ISA IRQs. This is the default implementation. Architecture
* implementations can override this.
*/
void __weak pcibios_penalize_isa_irq(int irq, int active) {}
int __weak pcibios_alloc_irq(struct pci_dev *dev)
{
return 0;
}
void __weak pcibios_free_irq(struct pci_dev *dev)
{
}

View File

@ -11,6 +11,8 @@
#include <linux/mm.h>
#include <linux/pci.h>
#include "pci.h"
#ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
static const struct vm_operations_struct pci_phys_vm_ops = {
@ -50,3 +52,30 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
}
#endif
#if (defined(CONFIG_SYSFS) || defined(CONFIG_PROC_FS)) && \
(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE))
int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
{
resource_size_t pci_start = 0, pci_end;
unsigned long nr, start, size;
if (pci_resource_len(pdev, resno) == 0)
return 0;
nr = vma_pages(vma);
start = vma->vm_pgoff;
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
if (mmap_api == PCI_MMAP_PROCFS) {
pci_resource_to_user(pdev, resno, &pdev->resource[resno],
&pci_start, &pci_end);
pci_start >>= PAGE_SHIFT;
}
if (start >= pci_start && start < pci_start + size &&
start + nr <= pci_start + size)
return 1;
return 0;
}
#endif

View File

@ -661,7 +661,7 @@ calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
p2pdma = rcu_dereference(provider->p2pdma);
if (p2pdma)
xa_store(&p2pdma->map_types, map_types_idx(client),
xa_mk_value(map_type), GFP_KERNEL);
xa_mk_value(map_type), GFP_ATOMIC);
rcu_read_unlock();
return map_type;
}

View File

@ -419,15 +419,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
return error;
}
int __weak pcibios_alloc_irq(struct pci_dev *dev)
{
return 0;
}
void __weak pcibios_free_irq(struct pci_dev *dev)
{
}
#ifdef CONFIG_PCI_IOV
static inline bool pci_device_can_probe(struct pci_dev *pdev)
{
@ -473,6 +464,13 @@ static void pci_device_remove(struct device *dev)
if (drv->remove) {
pm_runtime_get_sync(dev);
/*
* If the driver provides a .runtime_idle() callback and it has
* started to run already, it may continue to run in parallel
* with the code below, so wait until all of the runtime PM
* activity has completed.
*/
pm_runtime_barrier(dev);
drv->remove(pci_dev);
pm_runtime_put_noidle(dev);
}
@ -1382,10 +1380,7 @@ static int pci_pm_runtime_idle(struct device *dev)
if (!pci_dev->driver)
return 0;
if (!pm)
return -ENOSYS;
if (pm->runtime_idle)
if (pm && pm->runtime_idle)
return pm->runtime_idle(dev);
return 0;
@ -1714,7 +1709,7 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
return 1;
}
struct bus_type pcie_port_bus_type = {
const struct bus_type pcie_port_bus_type = {
.name = "pci_express",
.match = pcie_port_bus_match,
};

View File

@ -1022,29 +1022,6 @@ void pci_remove_legacy_files(struct pci_bus *b)
#endif /* HAVE_PCI_LEGACY */
#if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
enum pci_mmap_api mmap_api)
{
unsigned long nr, start, size;
resource_size_t pci_start = 0, pci_end;
if (pci_resource_len(pdev, resno) == 0)
return 0;
nr = vma_pages(vma);
start = vma->vm_pgoff;
size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
if (mmap_api == PCI_MMAP_PROCFS) {
pci_resource_to_user(pdev, resno, &pdev->resource[resno],
&pci_start, &pci_end);
pci_start >>= PAGE_SHIFT;
}
if (start >= pci_start && start < pci_start + size &&
start + nr <= pci_start + size)
return 1;
return 0;
}
/**
* pci_mmap_resource - map a PCI resource into user memory space
* @kobj: kobject for mapping
@ -1410,79 +1387,89 @@ static const struct attribute_group pci_dev_reset_attr_group = {
.is_visible = pci_dev_reset_attr_is_visible,
};
static ssize_t __resource_resize_show(struct device *dev, int n, char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
ssize_t ret;
pci_config_pm_runtime_get(pdev);
ret = sysfs_emit(buf, "%016llx\n",
(u64)pci_rebar_get_possible_sizes(pdev, n));
pci_config_pm_runtime_put(pdev);
return ret;
}
static ssize_t __resource_resize_store(struct device *dev, int n,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
unsigned long size, flags;
int ret, i;
u16 cmd;
if (kstrtoul(buf, 0, &size) < 0)
return -EINVAL;
device_lock(dev);
if (dev->driver) {
ret = -EBUSY;
goto unlock;
}
pci_config_pm_runtime_get(pdev);
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
ret = aperture_remove_conflicting_pci_devices(pdev,
"resourceN_resize");
if (ret)
goto pm_put;
}
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
pci_write_config_word(pdev, PCI_COMMAND,
cmd & ~PCI_COMMAND_MEMORY);
flags = pci_resource_flags(pdev, n);
pci_remove_resource_files(pdev);
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
if (pci_resource_len(pdev, i) &&
pci_resource_flags(pdev, i) == flags)
pci_release_resource(pdev, i);
}
ret = pci_resize_resource(pdev, n, size);
pci_assign_unassigned_bus_resources(pdev->bus);
if (pci_create_resource_files(pdev))
pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");
pci_write_config_word(pdev, PCI_COMMAND, cmd);
pm_put:
pci_config_pm_runtime_put(pdev);
unlock:
device_unlock(dev);
return ret ? ret : count;
}
#define pci_dev_resource_resize_attr(n) \
static ssize_t resource##n##_resize_show(struct device *dev, \
struct device_attribute *attr, \
char * buf) \
char *buf) \
{ \
struct pci_dev *pdev = to_pci_dev(dev); \
ssize_t ret; \
\
pci_config_pm_runtime_get(pdev); \
\
ret = sysfs_emit(buf, "%016llx\n", \
(u64)pci_rebar_get_possible_sizes(pdev, n)); \
\
pci_config_pm_runtime_put(pdev); \
\
return ret; \
return __resource_resize_show(dev, n, buf); \
} \
\
static ssize_t resource##n##_resize_store(struct device *dev, \
struct device_attribute *attr,\
const char *buf, size_t count)\
{ \
struct pci_dev *pdev = to_pci_dev(dev); \
unsigned long size, flags; \
int ret, i; \
u16 cmd; \
\
if (kstrtoul(buf, 0, &size) < 0) \
return -EINVAL; \
\
device_lock(dev); \
if (dev->driver) { \
ret = -EBUSY; \
goto unlock; \
} \
\
pci_config_pm_runtime_get(pdev); \
\
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { \
ret = aperture_remove_conflicting_pci_devices(pdev, \
"resourceN_resize"); \
if (ret) \
goto pm_put; \
} \
\
pci_read_config_word(pdev, PCI_COMMAND, &cmd); \
pci_write_config_word(pdev, PCI_COMMAND, \
cmd & ~PCI_COMMAND_MEMORY); \
\
flags = pci_resource_flags(pdev, n); \
\
pci_remove_resource_files(pdev); \
\
for (i = 0; i < PCI_STD_NUM_BARS; i++) { \
if (pci_resource_len(pdev, i) && \
pci_resource_flags(pdev, i) == flags) \
pci_release_resource(pdev, i); \
} \
\
ret = pci_resize_resource(pdev, n, size); \
\
pci_assign_unassigned_bus_resources(pdev->bus); \
\
if (pci_create_resource_files(pdev)) \
pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\
\
pci_write_config_word(pdev, PCI_COMMAND, cmd); \
pm_put: \
pci_config_pm_runtime_put(pdev); \
unlock: \
device_unlock(dev); \
\
return ret ? ret : count; \
return __resource_resize_store(dev, n, buf, count); \
} \
static DEVICE_ATTR_RW(resource##n##_resize)
@ -1660,7 +1647,7 @@ static const struct attribute_group pcie_dev_attr_group = {
.is_visible = pcie_dev_attrs_are_visible,
};
static const struct attribute_group *pci_dev_attr_groups[] = {
const struct attribute_group *pci_dev_attr_groups[] = {
&pci_dev_attr_group,
&pci_dev_hp_attr_group,
#ifdef CONFIG_PCI_IOV
@ -1677,7 +1664,3 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
#endif
NULL,
};
const struct device_type pci_dev_type = {
.groups = pci_dev_attr_groups,
};

View File

@ -24,7 +24,6 @@
#include <linux/log2.h>
#include <linux/logic_pio.h>
#include <linux/pm_wakeup.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h>
@ -1067,6 +1066,34 @@ static void pci_enable_acs(struct pci_dev *dev)
pci_disable_acs_redir(dev);
}
/**
* pcie_read_tlp_log - read TLP Header Log
* @dev: PCIe device
* @where: PCI Config offset of TLP Header Log
* @tlp_log: TLP Log structure to fill
*
* Fill @tlp_log from TLP Header Log registers, e.g., AER or DPC.
*
* Return: 0 on success and filled TLP Log structure, <0 on error.
*/
int pcie_read_tlp_log(struct pci_dev *dev, int where,
struct pcie_tlp_log *tlp_log)
{
int i, ret;
memset(tlp_log, 0, sizeof(*tlp_log));
for (i = 0; i < 4; i++) {
ret = pci_read_config_dword(dev, where + i * 4,
&tlp_log->dw[i]);
if (ret)
return pcibios_err_to_errno(ret);
}
return 0;
}
EXPORT_SYMBOL_GPL(pcie_read_tlp_log);
/**
* pci_restore_bars - restore a device's BAR values (e.g. after wake-up)
* @dev: PCI device to have its BARs restored
@ -1649,33 +1676,25 @@ static int pci_save_pcie_state(struct pci_dev *dev)
pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &cap[i++]);
pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &cap[i++]);
pci_save_aspm_l1ss_state(dev);
pci_save_ltr_state(dev);
return 0;
}
void pci_bridge_reconfigure_ltr(struct pci_dev *dev)
{
#ifdef CONFIG_PCIEASPM
struct pci_dev *bridge;
u32 ctl;
bridge = pci_upstream_bridge(dev);
if (bridge && bridge->ltr_path) {
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
pci_dbg(bridge, "re-enabling LTR\n");
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
}
}
#endif
}
static void pci_restore_pcie_state(struct pci_dev *dev)
{
int i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
/*
* Restore max latencies (in the LTR capability) before enabling
* LTR itself in PCI_EXP_DEVCTL2.
*/
pci_restore_ltr_state(dev);
pci_restore_aspm_l1ss_state(dev);
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state)
return;
@ -1733,46 +1752,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
}
static void pci_save_ltr_state(struct pci_dev *dev)
{
int ltr;
struct pci_cap_saved_state *save_state;
u32 *cap;
if (!pci_is_pcie(dev))
return;
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!ltr)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
if (!save_state) {
pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
return;
}
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
}
static void pci_restore_ltr_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
int ltr;
u32 *cap;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!save_state || !ltr)
return;
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
}
/**
* pci_save_state - save the PCI configuration space of a device before
* suspending
@ -1797,7 +1776,6 @@ int pci_save_state(struct pci_dev *dev)
if (i != 0)
return i;
pci_save_ltr_state(dev);
pci_save_dpc_state(dev);
pci_save_aer_state(dev);
pci_save_ptm_state(dev);
@ -1898,12 +1876,6 @@ void pci_restore_state(struct pci_dev *dev)
if (!dev->state_saved)
return;
/*
* Restore max latencies (in the LTR capability) before enabling
* LTR itself (in the PCIe capability).
*/
pci_restore_ltr_state(dev);
pci_restore_pcie_state(dev);
pci_restore_pasid_state(dev);
pci_restore_pri_state(dev);
@ -2183,107 +2155,6 @@ int pci_enable_device(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_enable_device);
/*
* Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X
* on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so
* there's no need to track it separately. pci_devres is initialized
* when a device is enabled using managed PCI device enable interface.
*/
struct pci_devres {
unsigned int enabled:1;
unsigned int pinned:1;
unsigned int orig_intx:1;
unsigned int restore_intx:1;
unsigned int mwi:1;
u32 region_mask;
};
static void pcim_release(struct device *gendev, void *res)
{
struct pci_dev *dev = to_pci_dev(gendev);
struct pci_devres *this = res;
int i;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
if (this->region_mask & (1 << i))
pci_release_region(dev, i);
if (this->mwi)
pci_clear_mwi(dev);
if (this->restore_intx)
pci_intx(dev, this->orig_intx);
if (this->enabled && !this->pinned)
pci_disable_device(dev);
}
static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
{
struct pci_devres *dr, *new_dr;
dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
if (dr)
return dr;
new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
if (!new_dr)
return NULL;
return devres_get(&pdev->dev, new_dr, NULL, NULL);
}
static struct pci_devres *find_pci_dr(struct pci_dev *pdev)
{
if (pci_is_managed(pdev))
return devres_find(&pdev->dev, pcim_release, NULL, NULL);
return NULL;
}
/**
* pcim_enable_device - Managed pci_enable_device()
* @pdev: PCI device to be initialized
*
* Managed pci_enable_device().
*/
int pcim_enable_device(struct pci_dev *pdev)
{
struct pci_devres *dr;
int rc;
dr = get_pci_dr(pdev);
if (unlikely(!dr))
return -ENOMEM;
if (dr->enabled)
return 0;
rc = pci_enable_device(pdev);
if (!rc) {
pdev->is_managed = 1;
dr->enabled = 1;
}
return rc;
}
EXPORT_SYMBOL(pcim_enable_device);
/**
* pcim_pin_device - Pin managed PCI device
* @pdev: PCI device to pin
*
* Pin managed PCI device @pdev. Pinned device won't be disabled on
* driver detach. @pdev must have been enabled with
* pcim_enable_device().
*/
void pcim_pin_device(struct pci_dev *pdev)
{
struct pci_devres *dr;
dr = find_pci_dr(pdev);
WARN_ON(!dr || !dr->enabled);
if (dr)
dr->pinned = 1;
}
EXPORT_SYMBOL(pcim_pin_device);
/*
* pcibios_device_add - provide arch specific hooks when adding device dev
* @dev: the PCI device being added
@ -2318,17 +2189,6 @@ void __weak pcibios_release_device(struct pci_dev *dev) {}
*/
void __weak pcibios_disable_device(struct pci_dev *dev) {}
/**
* pcibios_penalize_isa_irq - penalize an ISA IRQ
* @irq: ISA IRQ to penalize
* @active: IRQ active or not
*
* Permits the platform to provide architecture-specific functionality when
* penalizing ISA IRQs. This is the default implementation. Architecture
* implementations can override this.
*/
void __weak pcibios_penalize_isa_irq(int irq, int active) {}
static void do_pci_disable_device(struct pci_dev *dev)
{
u16 pci_command;
@ -3997,66 +3857,6 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
}
EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device
* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD)
*
* Perform INTx swizzling for a device behind one level of bridge. This is
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
* behind bridges on add-in cards. For devices with ARI enabled, the slot
* number is always 0 (see the Implementation Note in section 2.2.8.1 of
* the PCI Express Base Specification, Revision 2.1)
*/
u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin)
{
int slot;
if (pci_ari_enabled(dev->bus))
slot = 0;
else
slot = PCI_SLOT(dev->devfn);
return (((pin - 1) + slot) % 4) + 1;
}
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
u8 pin;
pin = dev->pin;
if (!pin)
return -1;
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
*bridge = dev;
return pin;
}
/**
* pci_common_swizzle - swizzle INTx all the way to root bridge
* @dev: the PCI device
* @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
*
* Perform INTx swizzling for a device. This traverses through all PCI-to-PCI
* bridges all the way up to a PCI root bus.
*/
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
{
u8 pin = *pinp;
while (!pci_is_root_bus(dev->bus)) {
pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
*pinp = pin;
return PCI_SLOT(dev->devfn);
}
EXPORT_SYMBOL_GPL(pci_common_swizzle);
/**
* pci_release_region - Release a PCI bar
* @pdev: PCI device whose resources were previously reserved by
@ -4385,133 +4185,6 @@ void pci_unmap_iospace(struct resource *res)
}
EXPORT_SYMBOL(pci_unmap_iospace);
static void devm_pci_unmap_iospace(struct device *dev, void *ptr)
{
struct resource **res = ptr;
pci_unmap_iospace(*res);
}
/**
* devm_pci_remap_iospace - Managed pci_remap_iospace()
* @dev: Generic device to remap IO address for
* @res: Resource describing the I/O space
* @phys_addr: physical address of range to be mapped
*
* Managed pci_remap_iospace(). Map is automatically unmapped on driver
* detach.
*/
int devm_pci_remap_iospace(struct device *dev, const struct resource *res,
phys_addr_t phys_addr)
{
const struct resource **ptr;
int error;
ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
error = pci_remap_iospace(res, phys_addr);
if (error) {
devres_free(ptr);
} else {
*ptr = res;
devres_add(dev, ptr);
}
return error;
}
EXPORT_SYMBOL(devm_pci_remap_iospace);
/**
* devm_pci_remap_cfgspace - Managed pci_remap_cfgspace()
* @dev: Generic device to remap IO address for
* @offset: Resource address to map
* @size: Size of map
*
* Managed pci_remap_cfgspace(). Map is automatically unmapped on driver
* detach.
*/
void __iomem *devm_pci_remap_cfgspace(struct device *dev,
resource_size_t offset,
resource_size_t size)
{
void __iomem **ptr, *addr;
ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
addr = pci_remap_cfgspace(offset, size);
if (addr) {
*ptr = addr;
devres_add(dev, ptr);
} else
devres_free(ptr);
return addr;
}
EXPORT_SYMBOL(devm_pci_remap_cfgspace);
/**
* devm_pci_remap_cfg_resource - check, request region and ioremap cfg resource
* @dev: generic device to handle the resource for
* @res: configuration space resource to be handled
*
* Checks that a resource is a valid memory region, requests the memory
* region and ioremaps with pci_remap_cfgspace() API that ensures the
* proper PCI configuration space memory attributes are guaranteed.
*
* All operations are managed and will be undone on driver detach.
*
* Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
* on failure. Usage example::
*
* res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
* base = devm_pci_remap_cfg_resource(&pdev->dev, res);
* if (IS_ERR(base))
* return PTR_ERR(base);
*/
void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
struct resource *res)
{
resource_size_t size;
const char *name;
void __iomem *dest_ptr;
BUG_ON(!dev);
if (!res || resource_type(res) != IORESOURCE_MEM) {
dev_err(dev, "invalid resource\n");
return IOMEM_ERR_PTR(-EINVAL);
}
size = resource_size(res);
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);
return IOMEM_ERR_PTR(-EBUSY);
}
dest_ptr = devm_pci_remap_cfgspace(dev, res->start, size);
if (!dest_ptr) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
devm_release_mem_region(dev, res->start, size);
dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
}
return dest_ptr;
}
EXPORT_SYMBOL(devm_pci_remap_cfg_resource);
static void __pci_set_master(struct pci_dev *dev, bool enable)
{
u16 old_cmd, cmd;
@ -4661,27 +4334,6 @@ int pci_set_mwi(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_set_mwi);
/**
* pcim_set_mwi - a device-managed pci_set_mwi()
* @dev: the PCI device for which MWI is enabled
*
* Managed pci_set_mwi().
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
int pcim_set_mwi(struct pci_dev *dev)
{
struct pci_devres *dr;
dr = find_pci_dr(dev);
if (!dr)
return -ENOMEM;
dr->mwi = 1;
return pci_set_mwi(dev);
}
EXPORT_SYMBOL(pcim_set_mwi);
/**
* pci_try_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
@ -4770,78 +4422,6 @@ void pci_intx(struct pci_dev *pdev, int enable)
}
EXPORT_SYMBOL_GPL(pci_intx);
static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask)
{
struct pci_bus *bus = dev->bus;
bool mask_updated = true;
u32 cmd_status_dword;
u16 origcmd, newcmd;
unsigned long flags;
bool irq_pending;
/*
* We do a single dword read to retrieve both command and status.
* Document assumptions that make this possible.
*/
BUILD_BUG_ON(PCI_COMMAND % 4);
BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS);
raw_spin_lock_irqsave(&pci_lock, flags);
bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword);
irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT;
/*
* Check interrupt status register to see whether our device
* triggered the interrupt (when masking) or the next IRQ is
* already pending (when unmasking).
*/
if (mask != irq_pending) {
mask_updated = false;
goto done;
}
origcmd = cmd_status_dword;
newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE;
if (mask)
newcmd |= PCI_COMMAND_INTX_DISABLE;
if (newcmd != origcmd)
bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd);
done:
raw_spin_unlock_irqrestore(&pci_lock, flags);
return mask_updated;
}
/**
* pci_check_and_mask_intx - mask INTx on pending interrupt
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, mask it and return
* true in that case. False is returned if no interrupt was pending.
*/
bool pci_check_and_mask_intx(struct pci_dev *dev)
{
return pci_check_and_set_intx_mask(dev, true);
}
EXPORT_SYMBOL_GPL(pci_check_and_mask_intx);
/**
* pci_check_and_unmask_intx - unmask INTx if no interrupt is pending
* @dev: the PCI device to operate on
*
* Check if the device dev has its INTx line asserted, unmask it if not and
* return true. False is returned and the mask remains active if there was
* still an interrupt pending.
*/
bool pci_check_and_unmask_intx(struct pci_dev *dev)
{
return pci_check_and_set_intx_mask(dev, false);
}
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
/**
* pci_wait_for_pending_transaction - wait for pending transaction
* @dev: the PCI device to operate on

View File

@ -31,9 +31,6 @@ bool pcie_cap_has_rtctl(const struct pci_dev *dev);
/* Functions internal to the PCI core code */
int pci_create_sysfs_dev_files(struct pci_dev *pdev);
void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
void pci_cleanup_rom(struct pci_dev *dev);
#ifdef CONFIG_DMI
extern const struct attribute_group pci_dev_smbios_attr_group;
#endif
@ -97,7 +94,6 @@ void pci_msi_init(struct pci_dev *dev);
void pci_msix_init(struct pci_dev *dev);
bool pci_bridge_d3_possible(struct pci_dev *dev);
void pci_bridge_d3_update(struct pci_dev *dev);
void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type);
static inline void pci_wakeup_event(struct pci_dev *dev)
@ -152,7 +148,7 @@ static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; }
/* Functions for PCI Hotplug drivers to use */
int pci_hp_add_bridge(struct pci_dev *dev);
#ifdef HAVE_PCI_LEGACY
#if defined(CONFIG_SYSFS) && defined(HAVE_PCI_LEGACY)
void pci_create_legacy_files(struct pci_bus *bus);
void pci_remove_legacy_files(struct pci_bus *bus);
#else
@ -185,10 +181,22 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
return (dev->no_d1d2 || parent_dstates);
}
#ifdef CONFIG_SYSFS
int pci_create_sysfs_dev_files(struct pci_dev *pdev);
void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern const struct attribute_group *pci_dev_groups[];
extern const struct attribute_group *pci_dev_attr_groups[];
extern const struct attribute_group *pcibus_groups[];
extern const struct device_type pci_dev_type;
extern const struct attribute_group *pci_bus_groups[];
#else
static inline int pci_create_sysfs_dev_files(struct pci_dev *pdev) { return 0; }
static inline void pci_remove_sysfs_dev_files(struct pci_dev *pdev) { }
#define pci_dev_groups NULL
#define pci_dev_attr_groups NULL
#define pcibus_groups NULL
#define pci_bus_groups NULL
#endif
extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mmio_size;
@ -404,7 +412,7 @@ struct aer_err_info {
unsigned int status; /* COR/UNCOR Error Status */
unsigned int mask; /* COR/UNCOR Error Mask */
struct aer_header_log_regs tlp; /* TLP Header */
struct pcie_tlp_log tlp; /* TLP Header */
};
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
@ -563,16 +571,28 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
int pcie_retrain_link(struct pci_dev *pdev, bool use_lt);
/* ASPM-related functionality we need even without CONFIG_PCIEASPM */
void pci_save_ltr_state(struct pci_dev *dev);
void pci_restore_ltr_state(struct pci_dev *dev);
void pci_configure_aspm_l1ss(struct pci_dev *dev);
void pci_save_aspm_l1ss_state(struct pci_dev *dev);
void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
#ifdef CONFIG_PCIEASPM
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, bool locked);
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
void pci_configure_ltr(struct pci_dev *pdev);
void pci_bridge_reconfigure_ltr(struct pci_dev *pdev);
#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, bool locked) { }
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
static inline void pci_configure_ltr(struct pci_dev *pdev) { }
static inline void pci_bridge_reconfigure_ltr(struct pci_dev *pdev) { }
#endif
#ifdef CONFIG_PCIE_ECRC
@ -792,6 +812,27 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev)
}
#endif
/*
* Managed PCI resources. This manages device on/off, INTx/MSI/MSI-X
* on/off and BAR regions. pci_dev itself records MSI/MSI-X status, so
* there's no need to track it separately. pci_devres is initialized
* when a device is enabled using managed PCI device enable interface.
*
* TODO: Struct pci_devres and find_pci_dr() only need to be here because
* they're used in pci.c. Port or move these functions to devres.c and
* then remove them from here.
*/
struct pci_devres {
unsigned int enabled:1;
unsigned int pinned:1;
unsigned int orig_intx:1;
unsigned int restore_intx:1;
unsigned int mwi:1;
u32 region_mask;
};
struct pci_devres *find_pci_dr(struct pci_dev *pdev);
/*
* Config Address for PCI Configuration Mechanism #1
*

View File

@ -6,7 +6,7 @@ pcieportdrv-y := portdrv.o rcec.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
obj-$(CONFIG_PCIEASPM) += aspm.o
obj-y += aspm.o
obj-$(CONFIG_PCIEAER) += aer.o err.o
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
obj-$(CONFIG_PCIE_PME) += pme.o

View File

@ -664,11 +664,10 @@ static void pci_rootport_aer_stats_incr(struct pci_dev *pdev,
}
}
static void __print_tlp_header(struct pci_dev *dev,
struct aer_header_log_regs *t)
static void __print_tlp_header(struct pci_dev *dev, struct pcie_tlp_log *t)
{
pci_err(dev, " TLP Header: %08x %08x %08x %08x\n",
t->dw0, t->dw1, t->dw2, t->dw3);
t->dw[0], t->dw[1], t->dw[2], t->dw[3]);
}
static void __aer_print_error(struct pci_dev *dev,
@ -1210,7 +1209,7 @@ 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;
u32 aercc;
/* Must reset in this function */
info->status = 0;
@ -1241,19 +1240,12 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
return 0;
/* Get First Error Pointer */
pci_read_config_dword(dev, aer + PCI_ERR_CAP, &temp);
info->first_error = PCI_ERR_CAP_FEP(temp);
pci_read_config_dword(dev, aer + PCI_ERR_CAP, &aercc);
info->first_error = PCI_ERR_CAP_FEP(aercc);
if (info->status & AER_LOG_TLP_MASKS) {
info->tlp_header_valid = 1;
pci_read_config_dword(dev,
aer + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
pci_read_config_dword(dev,
aer + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
pci_read_config_dword(dev,
aer + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
pci_read_config_dword(dev,
aer + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
pcie_read_tlp_log(dev, aer + PCI_ERR_HEADER_LOG, &info->tlp);
}
}

View File

@ -24,6 +24,166 @@
#include "../pci.h"
void pci_save_ltr_state(struct pci_dev *dev)
{
int ltr;
struct pci_cap_saved_state *save_state;
u32 *cap;
if (!pci_is_pcie(dev))
return;
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!ltr)
return;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
if (!save_state) {
pci_err(dev, "no suspend buffer for LTR; ASPM issues possible after resume\n");
return;
}
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
}
void pci_restore_ltr_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
int ltr;
u32 *cap;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!save_state || !ltr)
return;
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
}
void pci_configure_aspm_l1ss(struct pci_dev *pdev)
{
int rc;
pdev->l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
rc = pci_add_ext_cap_save_buffer(pdev, PCI_EXT_CAP_ID_L1SS,
2 * sizeof(u32));
if (rc)
pci_err(pdev, "unable to allocate ASPM L1SS save buffer (%pe)\n",
ERR_PTR(rc));
}
void pci_save_aspm_l1ss_state(struct pci_dev *pdev)
{
struct pci_cap_saved_state *save_state;
u16 l1ss = pdev->l1ss;
u32 *cap;
/*
* Save L1 substate configuration. The ASPM L0s/L1 configuration
* in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
*/
if (!l1ss)
return;
save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
if (!save_state)
return;
cap = &save_state->cap.data[0];
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2, cap++);
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, cap++);
}
void pci_restore_aspm_l1ss_state(struct pci_dev *pdev)
{
struct pci_cap_saved_state *pl_save_state, *cl_save_state;
struct pci_dev *parent = pdev->bus->self;
u32 *cap, pl_ctl1, pl_ctl2, pl_l1_2_enable;
u32 cl_ctl1, cl_ctl2, cl_l1_2_enable;
u16 clnkctl, plnkctl;
/*
* In case BIOS enabled L1.2 when resuming, we need to disable it first
* on the downstream component before the upstream. So, don't attempt to
* restore either until we are at the downstream component.
*/
if (pcie_downstream_port(pdev) || !parent)
return;
if (!pdev->l1ss || !parent->l1ss)
return;
cl_save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
pl_save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS);
if (!cl_save_state || !pl_save_state)
return;
cap = &cl_save_state->cap.data[0];
cl_ctl2 = *cap++;
cl_ctl1 = *cap;
cap = &pl_save_state->cap.data[0];
pl_ctl2 = *cap++;
pl_ctl1 = *cap;
/* Make sure L0s/L1 are disabled before updating L1SS config */
pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &clnkctl);
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &plnkctl);
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL,
clnkctl & ~PCI_EXP_LNKCTL_ASPMC);
pcie_capability_write_word(parent, PCI_EXP_LNKCTL,
plnkctl & ~PCI_EXP_LNKCTL_ASPMC);
}
/*
* Disable L1.2 on this downstream endpoint device first, followed
* by the upstream
*/
pci_clear_and_set_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_L1_2_MASK, 0);
pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
PCI_L1SS_CTL1_L1_2_MASK, 0);
/*
* In addition, Common_Mode_Restore_Time and LTR_L1.2_THRESHOLD
* in PCI_L1SS_CTL1 must be programmed *before* setting the L1.2
* enable bits, even though they're all in PCI_L1SS_CTL1.
*/
pl_l1_2_enable = pl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
pl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
cl_l1_2_enable = cl_ctl1 & PCI_L1SS_CTL1_L1_2_MASK;
cl_ctl1 &= ~PCI_L1SS_CTL1_L1_2_MASK;
/* Write back without enables first (above we cleared them in ctl1) */
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, pl_ctl2);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, cl_ctl2);
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, pl_ctl1);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, cl_ctl1);
/* Then write back the enables */
if (pl_l1_2_enable || cl_l1_2_enable) {
pci_write_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1,
pl_ctl1 | pl_l1_2_enable);
pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1,
cl_ctl1 | cl_l1_2_enable);
}
/* Restore L0s/L1 if they were enabled */
if (FIELD_GET(PCI_EXP_LNKCTL_ASPMC, clnkctl) ||
FIELD_GET(PCI_EXP_LNKCTL_ASPMC, plnkctl)) {
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, clnkctl);
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL, plnkctl);
}
}
#ifdef CONFIG_PCIEASPM
#ifdef MODULE_PARAM_PREFIX
#undef MODULE_PARAM_PREFIX
#endif
@ -141,16 +301,42 @@ static int policy_to_clkpm_state(struct pcie_link_state *link)
return 0;
}
static void pci_update_aspm_saved_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
u16 *cap, lnkctl, aspm_ctl;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
if (!save_state)
return;
pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &lnkctl);
/*
* Update ASPM and CLKREQ bits of LNKCTL in save_state. We only
* write PCI_EXP_LNKCTL_CCC during enumeration, so it shouldn't
* change after being captured in save_state.
*/
aspm_ctl = lnkctl & (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
lnkctl &= ~(PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
/* Depends on pci_save_pcie_state(): cap[1] is LNKCTL */
cap = (u16 *)&save_state->cap.data[0];
cap[1] = lnkctl | aspm_ctl;
}
static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
{
struct pci_dev *child;
struct pci_bus *linkbus = link->pdev->subordinate;
u32 val = enable ? PCI_EXP_LNKCTL_CLKREQ_EN : 0;
list_for_each_entry(child, &linkbus->devices, bus_list)
list_for_each_entry(child, &linkbus->devices, bus_list) {
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_CLKREQ_EN,
val);
pci_update_aspm_saved_state(child);
}
link->clkpm_enabled = !!enable;
}
@ -769,6 +955,12 @@ static void pcie_config_aspm_link(struct pcie_link_state *link, u32 state)
pcie_config_aspm_dev(parent, upstream);
link->aspm_enabled = state;
/* Update latest ASPM configuration in saved context */
pci_save_aspm_l1ss_state(link->downstream);
pci_update_aspm_saved_state(link->downstream);
pci_save_aspm_l1ss_state(parent);
pci_update_aspm_saved_state(parent);
}
static void pcie_config_aspm_path(struct pcie_link_state *link)
@ -938,6 +1130,78 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
up_read(&pci_bus_sem);
}
void pci_bridge_reconfigure_ltr(struct pci_dev *pdev)
{
struct pci_dev *bridge;
u32 ctl;
bridge = pci_upstream_bridge(pdev);
if (bridge && bridge->ltr_path) {
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl);
if (!(ctl & PCI_EXP_DEVCTL2_LTR_EN)) {
pci_dbg(bridge, "re-enabling LTR\n");
pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
}
}
}
void pci_configure_ltr(struct pci_dev *pdev)
{
struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
struct pci_dev *bridge;
u32 cap, ctl;
if (!pci_is_pcie(pdev))
return;
pcie_capability_read_dword(pdev, PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_LTR))
return;
pcie_capability_read_dword(pdev, PCI_EXP_DEVCTL2, &ctl);
if (ctl & PCI_EXP_DEVCTL2_LTR_EN) {
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
pdev->ltr_path = 1;
return;
}
bridge = pci_upstream_bridge(pdev);
if (bridge && bridge->ltr_path)
pdev->ltr_path = 1;
return;
}
if (!host->native_ltr)
return;
/*
* Software must not enable LTR in an Endpoint unless the Root
* Complex and all intermediate Switches indicate support for LTR.
* PCIe r4.0, sec 6.18.
*/
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) {
pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
pdev->ltr_path = 1;
return;
}
/*
* If we're configuring a hot-added device, LTR was likely
* disabled in the upstream bridge, so re-enable it before enabling
* it in the new device.
*/
bridge = pci_upstream_bridge(pdev);
if (bridge && bridge->ltr_path) {
pci_bridge_reconfigure_ltr(pdev);
pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
pdev->ltr_path = 1;
}
}
/* Recheck latencies and update aspm_capable for links under the root */
static void pcie_update_aspm_capable(struct pcie_link_state *root)
{
@ -1447,3 +1711,5 @@ bool pcie_aspm_support_enabled(void)
{
return aspm_support_enabled;
}
#endif /* CONFIG_PCIEASPM */

View File

@ -190,7 +190,8 @@ pci_ers_result_t dpc_reset_link(struct pci_dev *pdev)
static void dpc_process_rp_pio_error(struct pci_dev *pdev)
{
u16 cap = pdev->dpc_cap, dpc_status, first_error;
u32 status, mask, sev, syserr, exc, dw0, dw1, dw2, dw3, log, prefix;
u32 status, mask, sev, syserr, exc, log, prefix;
struct pcie_tlp_log tlp_log;
int i;
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_STATUS, &status);
@ -216,16 +217,9 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
if (pdev->dpc_rp_log_size < 4)
goto clear_status;
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG,
&dw0);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 4,
&dw1);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 8,
&dw2);
pci_read_config_dword(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG + 12,
&dw3);
pcie_read_tlp_log(pdev, cap + PCI_EXP_DPC_RP_PIO_HEADER_LOG, &tlp_log);
pci_err(pdev, "TLP Header: %#010x %#010x %#010x %#010x\n",
dw0, dw1, dw2, dw3);
tlp_log.dw[0], tlp_log.dw[1], tlp_log.dw[2], tlp_log.dw[3]);
if (pdev->dpc_rp_log_size < 5)
goto clear_status;
@ -234,7 +228,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
for (i = 0; i < pdev->dpc_rp_log_size - 5; i++) {
pci_read_config_dword(pdev,
cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix);
cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix);
pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix);
}
clear_status:
@ -303,10 +297,70 @@ void dpc_process_error(struct pci_dev *pdev)
}
}
static void pci_clear_surpdn_errors(struct pci_dev *pdev)
{
if (pdev->dpc_rp_extensions)
pci_write_config_dword(pdev, pdev->dpc_cap +
PCI_EXP_DPC_RP_PIO_STATUS, ~0);
/*
* In practice, Surprise Down errors have been observed to also set
* error bits in the Status Register as well as the Fatal Error
* Detected bit in the Device Status Register.
*/
pci_write_config_word(pdev, PCI_STATUS, 0xffff);
pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_FED);
}
static void dpc_handle_surprise_removal(struct pci_dev *pdev)
{
if (!pcie_wait_for_link(pdev, false)) {
pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n");
goto out;
}
if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev))
goto out;
pci_aer_raw_clear_status(pdev);
pci_clear_surpdn_errors(pdev);
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
PCI_EXP_DPC_STATUS_TRIGGER);
out:
clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags);
wake_up_all(&dpc_completed_waitqueue);
}
static bool dpc_is_surprise_removal(struct pci_dev *pdev)
{
u16 status;
if (!pdev->is_hotplug_bridge)
return false;
if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS,
&status))
return false;
return status & PCI_ERR_UNC_SURPDN;
}
static irqreturn_t dpc_handler(int irq, void *context)
{
struct pci_dev *pdev = context;
/*
* According to PCIe r6.0 sec 6.7.6, errors are an expected side effect
* of async removal and should be ignored by software.
*/
if (dpc_is_surprise_removal(pdev)) {
dpc_handle_surprise_removal(pdev);
return IRQ_HANDLED;
}
dpc_process_error(pdev);
/* We configure DPC so it only triggers on ERR_FATAL */

View File

@ -13,6 +13,7 @@
#define dev_fmt(fmt) "AER: " fmt
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@ -85,6 +86,18 @@ static int report_error_detected(struct pci_dev *dev,
return 0;
}
static int pci_pm_runtime_get_sync(struct pci_dev *pdev, void *data)
{
pm_runtime_get_sync(&pdev->dev);
return 0;
}
static int pci_pm_runtime_put(struct pci_dev *pdev, void *data)
{
pm_runtime_put(&pdev->dev);
return 0;
}
static int report_frozen_detected(struct pci_dev *dev, void *data)
{
return report_error_detected(dev, pci_channel_io_frozen, data);
@ -207,6 +220,8 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
else
bridge = pci_upstream_bridge(dev);
pci_walk_bridge(bridge, pci_pm_runtime_get_sync, NULL);
pci_dbg(bridge, "broadcast error_detected message\n");
if (state == pci_channel_io_frozen) {
pci_walk_bridge(bridge, report_frozen_detected, &status);
@ -251,10 +266,15 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
pcie_clear_device_status(dev);
pci_aer_clear_nonfatal_status(dev);
}
pci_walk_bridge(bridge, pci_pm_runtime_put, NULL);
pci_info(bridge, "device recovery successful\n");
return status;
failed:
pci_walk_bridge(bridge, pci_pm_runtime_put, NULL);
pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
/* TODO: Should kernel panic here? */

View File

@ -96,7 +96,7 @@ struct pcie_port_service_driver {
int pcie_port_service_register(struct pcie_port_service_driver *new);
void pcie_port_service_unregister(struct pcie_port_service_driver *new);
extern struct bus_type pcie_port_bus_type;
extern const struct bus_type pcie_port_bus_type;
struct pci_dev;

View File

@ -2209,67 +2209,6 @@ static void pci_configure_relaxed_ordering(struct pci_dev *dev)
}
}
static void pci_configure_ltr(struct pci_dev *dev)
{
#ifdef CONFIG_PCIEASPM
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
struct pci_dev *bridge;
u32 cap, ctl;
if (!pci_is_pcie(dev))
return;
/* Read L1 PM substate capabilities */
dev->l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP2, &cap);
if (!(cap & PCI_EXP_DEVCAP2_LTR))
return;
pcie_capability_read_dword(dev, PCI_EXP_DEVCTL2, &ctl);
if (ctl & PCI_EXP_DEVCTL2_LTR_EN) {
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
dev->ltr_path = 1;
return;
}
bridge = pci_upstream_bridge(dev);
if (bridge && bridge->ltr_path)
dev->ltr_path = 1;
return;
}
if (!host->native_ltr)
return;
/*
* Software must not enable LTR in an Endpoint unless the Root
* Complex and all intermediate Switches indicate support for LTR.
* PCIe r4.0, sec 6.18.
*/
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) {
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
dev->ltr_path = 1;
return;
}
/*
* If we're configuring a hot-added device, LTR was likely
* disabled in the upstream bridge, so re-enable it before enabling
* it in the new device.
*/
bridge = pci_upstream_bridge(dev);
if (bridge && bridge->ltr_path) {
pci_bridge_reconfigure_ltr(dev);
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_LTR_EN);
dev->ltr_path = 1;
}
#endif
}
static void pci_configure_eetlp_prefix(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_PASID
@ -2320,6 +2259,7 @@ static void pci_configure_device(struct pci_dev *dev)
pci_configure_extended_tags(dev, NULL);
pci_configure_relaxed_ordering(dev);
pci_configure_ltr(dev);
pci_configure_aspm_l1ss(dev);
pci_configure_eetlp_prefix(dev);
pci_configure_serr(dev);
@ -2357,6 +2297,10 @@ static void pci_release_dev(struct device *dev)
kfree(pci_dev);
}
static const struct device_type pci_dev_type = {
.groups = pci_dev_attr_groups,
};
struct pci_dev *pci_alloc_dev(struct pci_bus *bus)
{
struct pci_dev *dev;

View File

@ -3765,6 +3765,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset);
*/
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
/*
* Apparently the LSI / Agere FW643 can't recover after a Secondary Bus
* Reset and requires a power-off or suspend/resume and rescan. Prevent
* use of that reset.
*/
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATT, 0x5900, quirk_no_bus_reset);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATT, 0x5901, quirk_no_bus_reset);
/*
* Some TI KeyStone C667X devices do not support bus/hot reset. The PCIESS
* automatically disables LTSSM when Secondary Bus Reset is received and
@ -5527,6 +5535,7 @@ static void quirk_no_ext_tags(struct pci_dev *pdev)
pci_walk_bus(bridge->bus, pci_configure_extended_tags, NULL);
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_3WARE, 0x1004, quirk_no_ext_tags);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0132, quirk_no_ext_tags);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0140, quirk_no_ext_tags);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0141, quirk_no_ext_tags);
@ -6225,6 +6234,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2b, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa73f, dpc_log_size);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xa76e, dpc_log_size);
#endif
/*

View File

@ -1,64 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support routines for initializing a PCI subsystem
*
* Extruded from code written by
* Dave Rusling (david.rusling@reo.mts.dec.com)
* David Mosberger (davidm@cs.arizona.edu)
* David Miller (davem@redhat.com)
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/cache.h>
#include "pci.h"
void pci_assign_irq(struct pci_dev *dev)
{
u8 pin;
u8 slot = -1;
int irq = 0;
struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
if (!(hbrg->map_irq)) {
pci_dbg(dev, "runtime IRQ mapping not provided by arch\n");
return;
}
/*
* If this device is not on the primary bus, we need to figure out
* which interrupt pin it will come in on. We know which slot it
* will come in on because that slot is where the bridge is. Each
* time the interrupt line passes through a PCI-PCI bridge we must
* apply the swizzle function.
*/
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
/* Cope with illegal. */
if (pin > 4)
pin = 1;
if (pin) {
/* Follow the chain of bridges, swizzling as we go. */
if (hbrg->swizzle_irq)
slot = (*(hbrg->swizzle_irq))(dev, &pin);
/*
* If a swizzling function is not used, map_irq() must
* ignore slot.
*/
irq = (*(hbrg->map_irq))(dev, slot, pin);
if (irq == -1)
irq = 0;
}
dev->irq = irq;
pci_dbg(dev, "assign IRQ: got %d\n", dev->irq);
/*
* Always tell the device, so the driver knows what is the real IRQ
* to use; the device does not use it.
*/
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}

View File

@ -1672,7 +1672,7 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
rc = switchtec_init_isr(stdev);
if (rc) {
dev_err(&stdev->dev, "failed to init isr.\n");
goto err_put;
goto err_exit_pci;
}
iowrite32(SWITCHTEC_EVENT_CLEAR |
@ -1693,6 +1693,8 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
err_devadd:
stdev_kill(stdev);
err_exit_pci:
switchtec_exit_pci(stdev);
err_put:
ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));
put_device(&stdev->dev);

View File

@ -18,11 +18,8 @@
struct pci_dev;
struct aer_header_log_regs {
u32 dw0;
u32 dw1;
u32 dw2;
u32 dw3;
struct pcie_tlp_log {
u32 dw[4];
};
struct aer_capability_regs {
@ -33,13 +30,15 @@ struct aer_capability_regs {
u32 cor_status;
u32 cor_mask;
u32 cap_control;
struct aer_header_log_regs header_log;
struct pcie_tlp_log header_log;
u32 root_command;
u32 root_status;
u16 cor_err_source;
u16 uncor_err_source;
};
int pcie_read_tlp_log(struct pci_dev *dev, int where, struct pcie_tlp_log *log);
#if defined(CONFIG_PCIEAER)
int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
int pcie_aer_is_native(struct pci_dev *dev);

View File

@ -145,6 +145,37 @@ struct pci_epc {
unsigned long function_num_map;
};
/**
* @BAR_PROGRAMMABLE: The BAR mask can be configured by the EPC.
* @BAR_FIXED: The BAR mask is fixed by the hardware.
* @BAR_RESERVED: The BAR should not be touched by an EPF driver.
*/
enum pci_epc_bar_type {
BAR_PROGRAMMABLE = 0,
BAR_FIXED,
BAR_RESERVED,
};
/**
* struct pci_epc_bar_desc - hardware description for a BAR
* @type: the type of the BAR
* @fixed_size: the fixed size, only applicable if type is BAR_FIXED_MASK.
* @only_64bit: if true, an EPF driver is not allowed to choose if this BAR
* should be configured as 32-bit or 64-bit, the EPF driver must
* configure this BAR as 64-bit. Additionally, the BAR succeeding
* this BAR must be set to type BAR_RESERVED.
*
* only_64bit should not be set on a BAR of type BAR_RESERVED.
* (If BARx is a 64-bit BAR that an EPF driver is not allowed to
* touch, then both BARx and BARx+1 must be set to type
* BAR_RESERVED.)
*/
struct pci_epc_bar_desc {
enum pci_epc_bar_type type;
u64 fixed_size;
bool only_64bit;
};
/**
* struct pci_epc_features - features supported by a EPC device per function
* @linkup_notifier: indicate if the EPC device can notify EPF driver on link up
@ -152,9 +183,7 @@ struct pci_epc {
* for initialization
* @msi_capable: indicate if the endpoint function has MSI capability
* @msix_capable: indicate if the endpoint function has MSI-X capability
* @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
* @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
* @bar_fixed_size: Array specifying the size supported by each BAR
* @bar: array specifying the hardware description for each BAR
* @align: alignment size required for BAR buffer allocation
*/
struct pci_epc_features {
@ -162,9 +191,7 @@ struct pci_epc_features {
unsigned int core_init_notifier : 1;
unsigned int msi_capable : 1;
unsigned int msix_capable : 1;
u8 reserved_bar;
u8 bar_fixed_64bit;
u64 bar_fixed_size[PCI_STD_NUM_BARS];
struct pci_epc_bar_desc bar[PCI_STD_NUM_BARS];
size_t align;
};

View File

@ -15,6 +15,7 @@
#include <linux/pci.h>
struct pci_epf;
struct pci_epc_features;
enum pci_epc_interface_type;
enum pci_barno {
@ -216,7 +217,8 @@ int __pci_epf_register_driver(struct pci_epf_driver *driver,
struct module *owner);
void pci_epf_unregister_driver(struct pci_epf_driver *driver);
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar,
size_t align, enum pci_epc_interface_type type);
const struct pci_epc_features *epc_features,
enum pci_epc_interface_type type);
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
enum pci_epc_interface_type type);
int pci_epf_bind(struct pci_epf *epf);

View File

@ -390,9 +390,9 @@ struct pci_dev {
unsigned int d3hot_delay; /* D3hot->D0 transition time in ms */
unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
u16 l1ss; /* L1SS Capability pointer */
#ifdef CONFIG_PCIEASPM
struct pcie_link_state *link_state; /* ASPM link state */
u16 l1ss; /* L1SS Capability pointer */
unsigned int ltr_path:1; /* Latency Tolerance Reporting
supported from root to here */
#endif

View File

@ -300,7 +300,7 @@ TRACE_EVENT(aer_event,
const u32 status,
const u8 severity,
const u8 tlp_header_valid,
struct aer_header_log_regs *tlp),
struct pcie_tlp_log *tlp),
TP_ARGS(dev_name, status, severity, tlp_header_valid, tlp),
@ -318,10 +318,10 @@ TRACE_EVENT(aer_event,
__entry->severity = severity;
__entry->tlp_header_valid = tlp_header_valid;
if (tlp_header_valid) {
__entry->tlp_header[0] = tlp->dw0;
__entry->tlp_header[1] = tlp->dw1;
__entry->tlp_header[2] = tlp->dw2;
__entry->tlp_header[3] = tlp->dw3;
__entry->tlp_header[0] = tlp->dw[0];
__entry->tlp_header[1] = tlp->dw[1];
__entry->tlp_header[2] = tlp->dw[2];
__entry->tlp_header[3] = tlp->dw[3];
}
),

View File

@ -70,9 +70,6 @@ source "lib/math/Kconfig"
config NO_GENERIC_PCI_IOPORT_MAP
bool
config GENERIC_PCI_IOMAP
bool
config GENERIC_IOMAP
bool
select GENERIC_PCI_IOMAP

View File

@ -152,7 +152,6 @@ CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
obj-y += math/ crypto/
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/device.h>
#include <linux/err.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/gfp.h>
#include <linux/export.h>
@ -311,212 +311,6 @@ void devm_ioport_unmap(struct device *dev, void __iomem *addr)
EXPORT_SYMBOL(devm_ioport_unmap);
#endif /* CONFIG_HAS_IOPORT_MAP */
#ifdef CONFIG_PCI
/*
* PCI iomap devres
*/
#define PCIM_IOMAP_MAX PCI_STD_NUM_BARS
struct pcim_iomap_devres {
void __iomem *table[PCIM_IOMAP_MAX];
};
static void pcim_iomap_release(struct device *gendev, void *res)
{
struct pci_dev *dev = to_pci_dev(gendev);
struct pcim_iomap_devres *this = res;
int i;
for (i = 0; i < PCIM_IOMAP_MAX; i++)
if (this->table[i])
pci_iounmap(dev, this->table[i]);
}
/**
* pcim_iomap_table - access iomap allocation table
* @pdev: PCI device to access iomap table for
*
* Access iomap allocation table for @dev. If iomap table doesn't
* exist and @pdev is managed, it will be allocated. All iomaps
* recorded in the iomap table are automatically unmapped on driver
* detach.
*
* This function might sleep when the table is first allocated but can
* be safely called without context and guaranteed to succeed once
* allocated.
*/
void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
{
struct pcim_iomap_devres *dr, *new_dr;
dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
if (dr)
return dr->table;
new_dr = devres_alloc_node(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL,
dev_to_node(&pdev->dev));
if (!new_dr)
return NULL;
dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
return dr->table;
}
EXPORT_SYMBOL(pcim_iomap_table);
/**
* pcim_iomap - Managed pcim_iomap()
* @pdev: PCI device to iomap for
* @bar: BAR to iomap
* @maxlen: Maximum length of iomap
*
* Managed pci_iomap(). Map is automatically unmapped on driver
* detach.
*/
void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
{
void __iomem **tbl;
BUG_ON(bar >= PCIM_IOMAP_MAX);
tbl = (void __iomem **)pcim_iomap_table(pdev);
if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
return NULL;
tbl[bar] = pci_iomap(pdev, bar, maxlen);
return tbl[bar];
}
EXPORT_SYMBOL(pcim_iomap);
/**
* pcim_iounmap - Managed pci_iounmap()
* @pdev: PCI device to iounmap for
* @addr: Address to unmap
*
* Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
*/
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
{
void __iomem **tbl;
int i;
pci_iounmap(pdev, addr);
tbl = (void __iomem **)pcim_iomap_table(pdev);
BUG_ON(!tbl);
for (i = 0; i < PCIM_IOMAP_MAX; i++)
if (tbl[i] == addr) {
tbl[i] = NULL;
return;
}
WARN_ON(1);
}
EXPORT_SYMBOL(pcim_iounmap);
/**
* pcim_iomap_regions - Request and iomap PCI BARs
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to request and iomap
* @name: Name used when requesting regions
*
* Request and iomap regions specified by @mask.
*/
int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
{
void __iomem * const *iomap;
int i, rc;
iomap = pcim_iomap_table(pdev);
if (!iomap)
return -ENOMEM;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
unsigned long len;
if (!(mask & (1 << i)))
continue;
rc = -EINVAL;
len = pci_resource_len(pdev, i);
if (!len)
goto err_inval;
rc = pci_request_region(pdev, i, name);
if (rc)
goto err_inval;
rc = -ENOMEM;
if (!pcim_iomap(pdev, i, 0))
goto err_region;
}
return 0;
err_region:
pci_release_region(pdev, i);
err_inval:
while (--i >= 0) {
if (!(mask & (1 << i)))
continue;
pcim_iounmap(pdev, iomap[i]);
pci_release_region(pdev, i);
}
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions);
/**
* pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to iomap
* @name: Name used when requesting regions
*
* Request all PCI BARs and iomap regions specified by @mask.
*/
int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
const char *name)
{
int request_mask = ((1 << 6) - 1) & ~mask;
int rc;
rc = pci_request_selected_regions(pdev, request_mask, name);
if (rc)
return rc;
rc = pcim_iomap_regions(pdev, mask, name);
if (rc)
pci_release_selected_regions(pdev, request_mask);
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions_request_all);
/**
* pcim_iounmap_regions - Unmap and release PCI BARs
* @pdev: PCI device to map IO resources for
* @mask: Mask of BARs to unmap and release
*
* Unmap and release regions specified by @mask.
*/
void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
{
void __iomem * const *iomap;
int i;
iomap = pcim_iomap_table(pdev);
if (!iomap)
return;
for (i = 0; i < PCIM_IOMAP_MAX; i++) {
if (!(mask & (1 << i)))
continue;
pcim_iounmap(pdev, iomap[i]);
pci_release_region(pdev, i);
}
}
EXPORT_SYMBOL(pcim_iounmap_regions);
#endif /* CONFIG_PCI */
static void devm_arch_phys_ac_add_release(struct device *dev, void *res)
{
arch_phys_wc_del(*((int *)res));