mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-27 22:24:11 +08:00
pci-v5.11-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAl/ZJwsUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vyGGQ//UhNBwb061zUaLWvaDy2RY67tGsED kSNucKqrtaJtWaZDL3fmi8e15lwc4J/xWd96X0sd0udddrVto3WBjYd+CfbfhW8M rQufCGlaj+VAZEzrwwbo1cTHXGH3g57BZbVlebCxJJ3mycIv716N4bdo0jz5vf9J /PotN6yr5bCMWfO9320cmdaFDO2PK5o+AcRxUtkmFD854yJRZvmlxczFhj33pBB1 LLQlbi+Hr367WpK2uT2E36Z3POXwUqWOxSAs3Q4ql57/3UY1THZPIn5TmgXGqo7F Dr3TRlScWxftssFSAmGZat7lBEaDBh9UnHPAsic0cjlUg6+PE7O+2iLZ7XrtPokL Z8LVhdVlwLTNTfonsBSlMGFZJjh/zO9u1QtKYQjFhE5tUU3DUDaJz/pdcyjgaGQ1 RJNMlsHgdg89v7IJeyote+IfIpQs9YcyDxvXbXW8EFf8ft6KprTj1YNcsjRpgmwN xhvTX40oDV9HwF3UUzO6xCdvmhmgD0n4m9cRR4kH+KtiImkZJ4tMh50AQnIs2wag I1N2XRld7dqVGWLu4TYkmzxVgjJ9n8ylIRpHy9aMAR9TN+Q/ovLYxJvQkR4NYvxX hft3YLgpF1ZKlyflvHmmKszLqdlPX5e56UQl3/VSRD3IQGe1+HzWOhrssWkPnNSc 0P8b7YpJU4WnVzQ= =xRTv -----END PGP SIGNATURE----- Merge tag 'pci-v5.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: "Enumeration: - Decode PCIe 64 GT/s link speed (Gustavo Pimentel) - Remove unused HAVE_PCI_SET_MWI (Heiner Kallweit) - Reduce pci_set_cacheline_size() message to debug level (Heiner Kallweit) - Fix pci_slot_release() NULL pointer dereference (Jubin Zhong) - Unify ECAM constants in native PCI Express drivers (Krzysztof Wilczyński) - Return u8 from pci_find_capability() and similar (Puranjay Mohan) - Return u16 from pci_find_ext_capability() and similar (Bjorn Helgaas) - Fix ACPI companion lookup for device 0 on the root bus (Rafael J. Wysocki) Resource management: - Keep both device and resource name for config space remaps (Alexander Lobakin) - Bounds-check command-line resource alignment requests (Bjorn Helgaas) - Fix overflow in command-line resource alignment requests (Colin Ian King) Driver binding: - Avoid duplicate IDs in driver dynamic IDs list (Zhenzhong Duan) Power management: - Save/restore Precision Time Measurement Capability for suspend/resume (David E. Box) - Disable PTM during suspend to save power (David E. Box) - Add sysfs attribute for device power state (Maximilian Luz) - Rename pci_wakeup_bus() to pci_resume_bus() (Mika Westerberg) - Do not generate wakeup event when runtime resuming device (Mika Westerberg) - Save/restore ASPM L1SS Capability for suspend/resume (Vidya Sagar) Virtualization: - Mark AMD Raven iGPU ATS as broken in some platforms (Alex Deucher) - Add function 1 DMA alias quirk for Marvell 9215 SATA controller (Bjorn Helgaas) MSI: - Disable MSI for Pericom PCIe-USB adapter (Andy Shevchenko) - Improve warnings for 32-bit-limited MSI support (Vidya Sagar) Error handling: - Cache RCEC EA Capability offset in pci_init_capabilities() (Sean V Kelley) - Rename reset_link() to reset_subordinates() (Sean V Kelley) - Write AER Capability only when we control it (Sean V Kelley) - Clear AER status only when we control AER (Sean V Kelley) - Bind RCEC devices to the Root Port driver (Qiuxu Zhuo) - Recover from RCiEP AER errors (Qiuxu Zhuo) - Recover from RCEC AER errors (Sean V Kelley) - Add pcie_link_rcec() to associate RCiEPs (Sean V Kelley) - Add pcie_walk_rcec() to RCEC AER handling (Sean V Kelley) - Add pcie_walk_rcec() to RCEC PME handling (Sean V Kelley) - Add RCEC AER error injection support (Qiuxu Zhuo) Broadcom iProc PCIe controller driver: - Fix out-of-bound array accesses (Bharat Gooty) - Invalidate correct PAXB inbound windows (Roman Bacik) - Enhance PCIe Link information display (Srinath Mannam) Cadence PCIe controller driver: - Make "cdns,max-outbound-regions" property optional (Kishon Vijay Abraham I) Intel VMD host bridge driver: - Offset client MSI-X vectors (Jon Derrick) - Update type of __iomem pointers (Krzysztof Wilczyński) NVIDIA Tegra PCIe controller driver: - Move "dbi" accesses to post common DWC initialization (Vidya Sagar) - Read "dbi" base address to program in application logic (Vidya Sagar) - Fix ASPM-L1SS advertisement disable code (Vidya Sagar) - Set DesignWare IP version (Vidya Sagar) - Continue unconfig sequence even if parts fail (Vidya Sagar) - Check return value of tegra_pcie_init_controller() (Vidya Sagar) - Disable LTSSM during L2 entry (Vidya Sagar) Qualcomm PCIe controller driver: - Document PCIe bindings for SM8250 SoC (Manivannan Sadhasivam) - Add SM8250 SoC support (Manivannan Sadhasivam) - Add support for configuring BDF to SID mapping for SM8250 (Manivannan Sadhasivam) Renesas R-Car PCIe controller driver: - rcar: Drop unused members from struct rcar_pcie_host (Lad Prabhakar) - PCI: rcar-pci-host: Document r8a774e1 bindings (Lad Prabhakar) - PCI: rcar-pci-host: Convert bindings to json-schema (Yoshihiro Shimoda) - PCI: rcar-pci-host: Document r8a77965 bindings (Yoshihiro Shimoda) Samsung Exynos PCIe controller driver: - Rework driver to support Exynos5433 PCIe PHY (Jaehoon Chung) - Rework driver to support Exynos5433 variant (Jaehoon Chung) - Drop samsung,exynos5440-pcie binding (Marek Szyprowski) - Add the samsung,exynos-pcie binding (Marek Szyprowski) - Add the samsung,exynos-pcie-phy binding (Marek Szyprowski) Synopsys DesignWare PCIe controller driver: - Support multiple ATU memory regions (Rob Herring) - Move intel-gw ATU offset out of driver match data (Rob Herring) - Move "dbi", "dbi2", and "addr_space" resource setup into common code (Rob Herring) - Remove intel-gw unneeded function wrappers (Rob Herring) - Ensure all outbound ATU windows are reset (Rob Herring) - Use the common MSI irq_chip in dra7xx (Rob Herring) - Drop the .set_num_vectors() host op (Rob Herring) - Move MSI interrupt setup into DWC common code (Rob Herring) - Rework MSI initialization (Rob Herring) - Move link handling into common code (Rob Herring) - Move dw_pcie_msi_init() into core (Rob Herring) - Move dw_pcie_setup_rc() to DWC common code (Rob Herring) - Remove unnecessary wrappers around dw_pcie_host_init() (Rob Herring) - Drop keystone duplicated 'num-viewport'" (Rob Herring) - Move inbound and outbound windows to common struct (Rob Herring) - Detect number of iATU windows (Rob Herring) - Warn if non-prefetchable memory aperture size is > 32-bit (Vidya Sagar) - Add support to program ATU for >4GB memory (Vidya Sagar) - Set 32-bit DMA mask for MSI target address allocation (Vidya Sagar) TI J721E PCIe driver: - Fix "ti,syscon-pcie-ctrl" to take argument (Kishon Vijay Abraham I) - Add host mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham I) - Add EP mode dt-bindings for TI's J7200 SoC (Kishon Vijay Abraham I) - Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg (Kishon Vijay Abraham I) TI Keystone PCIe controller driver: - Enable compile-testing on !ARM (Alex Dewar)" * tag 'pci-v5.11-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (100 commits) PCI: Add function 1 DMA alias quirk for Marvell 9215 SATA controller PCI/ACPI: Fix companion lookup for device 0 on the root bus PCI: Keep both device and resource name for config space remaps PCI: xgene: Removed unused ".bus_shift" initialisers from pci-xgene.c PCI: vmd: Update type of the __iomem pointers PCI: iproc: Convert to use the new ECAM constants PCI: thunder-pem: Add constant for custom ".bus_shift" initialiser PCI: Unify ECAM constants in native PCI Express drivers PCI: Disable PTM during suspend to save power PCI/PTM: Save/restore Precision Time Measurement Capability for suspend/resume PCI: Mark AMD Raven iGPU ATS as broken in some platforms PCI: j721e: Get offset within "syscon" from "ti,syscon-pcie-ctrl" phandle arg dt-bindings: PCI: Add EP mode dt-bindings for TI's J7200 SoC dt-bindings: PCI: Add host mode dt-bindings for TI's J7200 SoC dt-bindings: pci: ti,j721e: Fix "ti,syscon-pcie-ctrl" to take argument PCI: dwc: Set 32-bit DMA mask for MSI target address allocation PCI: qcom: Add support for configuring BDF to SID mapping for SM8250 PCI: Reduce pci_set_cacheline_size() message to debug level PCI: Remove unused HAVE_PCI_SET_MWI PCI: qcom: Add SM8250 SoC support ...
This commit is contained in:
commit
489e9fea66
@ -366,3 +366,12 @@ Contact: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Description: If ASPM is supported for an endpoint, these files can be
|
||||
used to disable or enable the individual power management
|
||||
states. Write y/1/on to enable, n/0/off to disable.
|
||||
|
||||
What: /sys/bus/pci/devices/.../power_state
|
||||
Date: November 2020
|
||||
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
|
||||
Description:
|
||||
This file contains the current PCI power state of the device.
|
||||
The value comes from the PCI kernel device state and can be one
|
||||
of: "unknown", "error", "D0", D1", "D2", "D3hot", "D3cold".
|
||||
The file is read only.
|
||||
|
@ -20,7 +20,4 @@ properties:
|
||||
maximum: 32
|
||||
default: 32
|
||||
|
||||
required:
|
||||
- cdns,max-outbound-regions
|
||||
|
||||
additionalProperties: true
|
||||
|
@ -13,6 +13,7 @@
|
||||
- "qcom,pcie-ipq8074" for ipq8074
|
||||
- "qcom,pcie-qcs404" for qcs404
|
||||
- "qcom,pcie-sdm845" for sdm845
|
||||
- "qcom,pcie-sm8250" for sm8250
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
@ -27,6 +28,7 @@
|
||||
- "dbi" DesignWare PCIe registers
|
||||
- "elbi" External local bus interface registers
|
||||
- "config" PCIe configuration space
|
||||
- "atu" ATU address space (optional)
|
||||
|
||||
- device_type:
|
||||
Usage: required
|
||||
@ -131,7 +133,7 @@
|
||||
- "slave_bus" AXI Slave clock
|
||||
|
||||
-clock-names:
|
||||
Usage: required for sdm845
|
||||
Usage: required for sdm845 and sm8250
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "aux" Auxiliary clock
|
||||
@ -206,7 +208,7 @@
|
||||
- "ahb" AHB reset
|
||||
|
||||
- reset-names:
|
||||
Usage: required for sdm845
|
||||
Usage: required for sdm845 and sm8250
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "pci" PCIe core reset
|
||||
|
115
Documentation/devicetree/bindings/pci/rcar-pci-host.yaml
Normal file
115
Documentation/devicetree/bindings/pci/rcar-pci-host.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Renesas Electronics Corp.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/rcar-pci-host.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car PCIe Host
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marek.vasut+renesas@gmail.com>
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: pci-bus.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,pcie-r8a7742 # RZ/G1H
|
||||
- renesas,pcie-r8a7743 # RZ/G1M
|
||||
- renesas,pcie-r8a7744 # RZ/G1N
|
||||
- renesas,pcie-r8a7790 # R-Car H2
|
||||
- renesas,pcie-r8a7791 # R-Car M2-W
|
||||
- renesas,pcie-r8a7793 # R-Car M2-N
|
||||
- const: renesas,pcie-rcar-gen2 # R-Car Gen2 and RZ/G1
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,pcie-r8a774a1 # RZ/G2M
|
||||
- renesas,pcie-r8a774b1 # RZ/G2N
|
||||
- renesas,pcie-r8a774c0 # RZ/G2E
|
||||
- renesas,pcie-r8a774e1 # RZ/G2H
|
||||
- renesas,pcie-r8a7795 # R-Car H3
|
||||
- renesas,pcie-r8a7796 # R-Car M3-W
|
||||
- renesas,pcie-r8a77961 # R-Car M3-W+
|
||||
- renesas,pcie-r8a77965 # R-Car M3-N
|
||||
- renesas,pcie-r8a77980 # R-Car V3H
|
||||
- renesas,pcie-r8a77990 # R-Car E3
|
||||
- const: renesas,pcie-rcar-gen3 # R-Car Gen3 and RZ/G2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pcie
|
||||
- const: pcie_bus
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: pcie
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a7791-sysc.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pcie: pcie@fe000000 {
|
||||
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
|
||||
reg = <0 0xfe000000 0 0x80000>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
bus-range = <0x00 0xff>;
|
||||
device_type = "pci";
|
||||
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000>,
|
||||
<0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000>,
|
||||
<0x02000000 0 0x30000000 0 0x30000000 0 0x08000000>,
|
||||
<0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
|
||||
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>,
|
||||
<0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
|
||||
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 319>, <&pcie_bus_clk>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 319>;
|
||||
};
|
||||
};
|
@ -1,72 +0,0 @@
|
||||
* Renesas R-Car PCIe interface
|
||||
|
||||
Required properties:
|
||||
compatible: "renesas,pcie-r8a7742" for the R8A7742 SoC;
|
||||
"renesas,pcie-r8a7743" for the R8A7743 SoC;
|
||||
"renesas,pcie-r8a7744" for the R8A7744 SoC;
|
||||
"renesas,pcie-r8a774a1" for the R8A774A1 SoC;
|
||||
"renesas,pcie-r8a774b1" for the R8A774B1 SoC;
|
||||
"renesas,pcie-r8a774c0" for the R8A774C0 SoC;
|
||||
"renesas,pcie-r8a7779" for the R8A7779 SoC;
|
||||
"renesas,pcie-r8a7790" for the R8A7790 SoC;
|
||||
"renesas,pcie-r8a7791" for the R8A7791 SoC;
|
||||
"renesas,pcie-r8a7793" for the R8A7793 SoC;
|
||||
"renesas,pcie-r8a7795" for the R8A7795 SoC;
|
||||
"renesas,pcie-r8a7796" for the R8A77960 SoC;
|
||||
"renesas,pcie-r8a77961" for the R8A77961 SoC;
|
||||
"renesas,pcie-r8a77980" for the R8A77980 SoC;
|
||||
"renesas,pcie-r8a77990" for the R8A77990 SoC;
|
||||
"renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or
|
||||
RZ/G1 compatible device.
|
||||
"renesas,pcie-rcar-gen3" for a generic R-Car Gen3 or
|
||||
RZ/G2 compatible device.
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: base address and length of the PCIe controller registers.
|
||||
- #address-cells: set to <3>
|
||||
- #size-cells: set to <2>
|
||||
- bus-range: PCI bus numbers covered
|
||||
- device_type: set to "pci"
|
||||
- ranges: ranges for the PCI memory and I/O regions.
|
||||
- dma-ranges: ranges for the inbound memory regions.
|
||||
- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
|
||||
source for hardware related interrupts (e.g. link speed change).
|
||||
- #interrupt-cells: set to <1>
|
||||
- interrupt-map-mask and interrupt-map: standard PCI properties
|
||||
to define the mapping of the PCIe interface to interrupt numbers.
|
||||
- clocks: from common clock binding: clock specifiers for the PCIe controller
|
||||
and PCIe bus clocks.
|
||||
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
|
||||
|
||||
Optional properties:
|
||||
- phys: from common PHY binding: PHY phandle and specifier (only make sense
|
||||
for R-Car gen3 SoCs where the PCIe PHYs have their own register blocks).
|
||||
- phy-names: from common PHY binding: should be "pcie".
|
||||
|
||||
Example:
|
||||
|
||||
SoC-specific DT Entry:
|
||||
|
||||
pcie: pcie@fe000000 {
|
||||
compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2";
|
||||
reg = <0 0xfe000000 0 0x80000>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
bus-range = <0x00 0xff>;
|
||||
device_type = "pci";
|
||||
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
|
||||
0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
|
||||
0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
|
||||
0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
|
||||
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
|
||||
0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
|
||||
interrupts = <0 116 4>, <0 117 4>, <0 118 4>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic 0 116 4>;
|
||||
clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
};
|
119
Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml
Normal file
119
Documentation/devicetree/bindings/pci/samsung,exynos-pcie.yaml
Normal file
@ -0,0 +1,119 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/samsung,exynos-pcie.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung SoC series PCIe Host Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Jaehoon Chung <jh80.chung@samsung.com>
|
||||
|
||||
description: |+
|
||||
Exynos5433 SoC PCIe host controller is based on the Synopsys DesignWare
|
||||
PCIe IP and thus inherits all the common properties defined in
|
||||
designware-pcie.txt.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pci/pci-bus.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: samsung,exynos5433-pcie
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Data Bus Interface (DBI) registers.
|
||||
- description: External Local Bus interface (ELBI) registers.
|
||||
- description: PCIe configuration space region.
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: elbi
|
||||
- const: config
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PCIe bridge clock
|
||||
- description: PCIe bus clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pcie
|
||||
- const: pcie_bus
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
vdd10-supply:
|
||||
description:
|
||||
Phandle to a regulator that provides 1.0V power to the PCIe block.
|
||||
|
||||
vdd18-supply:
|
||||
description:
|
||||
Phandle to a regulator that provides 1.8V power to the PCIe block.
|
||||
|
||||
num-lanes:
|
||||
const: 1
|
||||
|
||||
num-viewport:
|
||||
const: 3
|
||||
|
||||
required:
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- "#interrupt-cells"
|
||||
- interrupt-map
|
||||
- interrupt-map-mask
|
||||
- ranges
|
||||
- bus-range
|
||||
- device_type
|
||||
- num-lanes
|
||||
- num-viewport
|
||||
- clocks
|
||||
- clock-names
|
||||
- phys
|
||||
- vdd10-supply
|
||||
- vdd18-supply
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/exynos5433.h>
|
||||
|
||||
pcie: pcie@15700000 {
|
||||
compatible = "samsung,exynos5433-pcie";
|
||||
reg = <0x15700000 0x1000>, <0x156b0000 0x1000>, <0x0c000000 0x1000>;
|
||||
reg-names = "dbi", "elbi", "config";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
device_type = "pci";
|
||||
interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu_fsys CLK_PCIE>, <&cmu_fsys CLK_PCLK_PCIE_PHY>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
phys = <&pcie_phy>;
|
||||
pinctrl-0 = <&pcie_bus &pcie_wlanen>;
|
||||
pinctrl-names = "default";
|
||||
num-lanes = <1>;
|
||||
num-viewport = <3>;
|
||||
bus-range = <0x00 0xff>;
|
||||
ranges = <0x81000000 0 0 0x0c001000 0 0x00010000>,
|
||||
<0x82000000 0 0x0c011000 0x0c011000 0 0x03feefff>;
|
||||
vdd10-supply = <&ldo6_reg>;
|
||||
vdd18-supply = <&ldo7_reg>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
...
|
@ -1,58 +0,0 @@
|
||||
* Samsung Exynos 5440 PCIe interface
|
||||
|
||||
This PCIe host controller is based on the Synopsys DesignWare PCIe IP
|
||||
and thus inherits all the common properties defined in designware-pcie.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible: "samsung,exynos5440-pcie"
|
||||
- reg: base addresses and lengths of the PCIe controller,
|
||||
- reg-names : First name should be set to "elbi".
|
||||
And use the "config" instead of getting the configuration address space
|
||||
from "ranges".
|
||||
NOTE: When using the "config" property, reg-names must be set.
|
||||
- interrupts: A list of interrupt outputs for level interrupt,
|
||||
pulse interrupt, special interrupt.
|
||||
- phys: From PHY binding. Phandle for the generic PHY.
|
||||
Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt
|
||||
|
||||
For other common properties, refer to
|
||||
Documentation/devicetree/bindings/pci/designware-pcie.txt
|
||||
|
||||
Example:
|
||||
|
||||
SoC-specific DT Entry (with using PHY framework):
|
||||
|
||||
pcie_phy0: pcie-phy@270000 {
|
||||
...
|
||||
reg = <0x270000 0x1000>, <0x271000 0x40>;
|
||||
reg-names = "phy", "block";
|
||||
...
|
||||
};
|
||||
|
||||
pcie@290000 {
|
||||
compatible = "samsung,exynos5440-pcie", "snps,dw-pcie";
|
||||
reg = <0x290000 0x1000>, <0x40000000 0x1000>;
|
||||
reg-names = "elbi", "config";
|
||||
clocks = <&clock 28>, <&clock 27>;
|
||||
clock-names = "pcie", "pcie_bus";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
device_type = "pci";
|
||||
phys = <&pcie_phy0>;
|
||||
ranges = <0x81000000 0 0 0x60001000 0 0x00010000
|
||||
0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
|
||||
num-lanes = <4>;
|
||||
};
|
||||
|
||||
Board-specific DT Entry:
|
||||
|
||||
pcie@290000 {
|
||||
reset-gpio = <&pin_ctrl 5 0>;
|
||||
};
|
||||
|
||||
pcie@2a0000 {
|
||||
reset-gpio = <&pin_ctrl 22 0>;
|
||||
};
|
@ -15,8 +15,14 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,j721e-pcie-ep
|
||||
oneOf:
|
||||
- description: PCIe EP controller in J7200
|
||||
items:
|
||||
- const: ti,j7200-pcie-ep
|
||||
- const: ti,j721e-pcie-ep
|
||||
- description: PCIe EP controller in J721E
|
||||
items:
|
||||
- const: ti,j721e-pcie-ep
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
@ -29,9 +35,12 @@ properties:
|
||||
- const: mem
|
||||
|
||||
ti,syscon-pcie-ctrl:
|
||||
description: Phandle to the SYSCON entry required for configuring PCIe mode
|
||||
and link speed.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to the SYSCON entry
|
||||
- description: pcie_ctrl register offset within SYSCON
|
||||
description: Specifier for configuring PCIe mode and link speed.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
@ -57,7 +66,6 @@ required:
|
||||
- power-domains
|
||||
- clocks
|
||||
- clock-names
|
||||
- cdns,max-outbound-regions
|
||||
- dma-coherent
|
||||
- max-functions
|
||||
- phys
|
||||
@ -80,13 +88,12 @@ examples:
|
||||
<0x00 0x0d000000 0x00 0x00800000>,
|
||||
<0x00 0x10000000 0x00 0x08000000>;
|
||||
reg-names = "intd_cfg", "user_cfg", "reg", "mem";
|
||||
ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
|
||||
ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
|
||||
max-link-speed = <3>;
|
||||
num-lanes = <2>;
|
||||
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
|
||||
clocks = <&k3_clks 239 1>;
|
||||
clock-names = "fck";
|
||||
cdns,max-outbound-regions = <16>;
|
||||
max-functions = /bits/ 8 <6>;
|
||||
dma-coherent;
|
||||
phys = <&serdes0_pcie_link>;
|
||||
|
@ -15,8 +15,14 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,j721e-pcie-host
|
||||
oneOf:
|
||||
- description: PCIe controller in J7200
|
||||
items:
|
||||
- const: ti,j7200-pcie-host
|
||||
- const: ti,j721e-pcie-host
|
||||
- description: PCIe controller in J721E
|
||||
items:
|
||||
- const: ti,j721e-pcie-host
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
@ -29,9 +35,12 @@ properties:
|
||||
- const: cfg
|
||||
|
||||
ti,syscon-pcie-ctrl:
|
||||
description: Phandle to the SYSCON entry required for configuring PCIe mode
|
||||
and link speed.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
- items:
|
||||
- description: Phandle to the SYSCON entry
|
||||
- description: pcie_ctrl register offset within SYSCON
|
||||
description: Specifier for configuring PCIe mode and link speed.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
@ -48,7 +57,11 @@ properties:
|
||||
const: 0x104c
|
||||
|
||||
device-id:
|
||||
const: 0xb00d
|
||||
oneOf:
|
||||
- items:
|
||||
- const: 0xb00d
|
||||
- items:
|
||||
- const: 0xb00f
|
||||
|
||||
msi-map: true
|
||||
|
||||
@ -90,7 +103,7 @@ examples:
|
||||
<0x00 0x0d000000 0x00 0x00800000>,
|
||||
<0x00 0x10000000 0x00 0x00001000>;
|
||||
reg-names = "intd_cfg", "user_cfg", "reg", "cfg";
|
||||
ti,syscon-pcie-ctrl = <&pcie0_ctrl>;
|
||||
ti,syscon-pcie-ctrl = <&pcie0_ctrl 0x4070>;
|
||||
max-link-speed = <3>;
|
||||
num-lanes = <2>;
|
||||
power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>;
|
||||
|
@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,exynos-pcie-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung SoC series PCIe PHY Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Jaehoon Chung <jh80.chung@samsung.com>
|
||||
|
||||
properties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
const: samsung,exynos5433-pcie-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
samsung,pmu-syscon:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description: phandle for PMU system controller interface, used to
|
||||
control PMU registers bits for PCIe PHY
|
||||
|
||||
samsung,fsys-sysreg:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description: phandle for FSYS sysreg interface, used to control
|
||||
sysreg registers bits for PCIe PHY
|
||||
|
||||
required:
|
||||
- "#phy-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- samsung,pmu-syscon
|
||||
- samsung,fsys-sysreg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pcie_phy: pcie-phy@15680000 {
|
||||
compatible = "samsung,exynos5433-pcie-phy";
|
||||
reg = <0x15680000 0x1000>;
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
samsung,fsys-sysreg = <&syscon_fsys>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
...
|
@ -13656,6 +13656,8 @@ M: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/PCI/endpoint/*
|
||||
F: Documentation/misc-devices/pci-endpoint-test.rst
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kishon/pci-endpoint.git
|
||||
F: drivers/misc/pci_endpoint_test.c
|
||||
F: drivers/pci/endpoint/
|
||||
|
@ -1038,7 +1038,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
|
||||
mutex_lock(&vgasr_mutex);
|
||||
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
|
||||
mutex_unlock(&vgasr_mutex);
|
||||
pci_wakeup_bus(pdev->bus);
|
||||
pci_resume_bus(pdev->bus);
|
||||
return dev->bus->pm->runtime_resume(dev);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o \
|
||||
remove.o pci.o pci-driver.o search.o \
|
||||
pci-sysfs.o rom.o setup-res.o irq.o vpd.o \
|
||||
setup-bus.o vc.o mmap.o setup-irq.o
|
||||
setup-bus.o vc.o mmap.o setup-irq.o msi.o
|
||||
|
||||
obj-$(CONFIG_PCI) += pcie/
|
||||
|
||||
@ -18,7 +18,6 @@ endif
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
|
||||
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
|
||||
obj-$(CONFIG_PCI_MSI) += msi.o
|
||||
obj-$(CONFIG_PCI_ATS) += ats.o
|
||||
obj-$(CONFIG_PCI_IOV) += iov.o
|
||||
obj-$(CONFIG_PCI_BRIDGE_EMUL) += pci-bridge-emul.o
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pci.h>
|
||||
@ -153,7 +154,8 @@ static const struct cdns_pcie_ops j721e_pcie_ops = {
|
||||
.link_up = j721e_pcie_link_up,
|
||||
};
|
||||
|
||||
static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
|
||||
static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
u32 mask = J721E_MODE_RC;
|
||||
@ -164,7 +166,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
|
||||
if (mode == PCI_MODE_RC)
|
||||
val = J721E_MODE_RC;
|
||||
|
||||
ret = regmap_update_bits(syscon, 0, mask, val);
|
||||
ret = regmap_update_bits(syscon, offset, mask, val);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to set pcie mode\n");
|
||||
|
||||
@ -172,7 +174,7 @@ static int j721e_pcie_set_mode(struct j721e_pcie *pcie, struct regmap *syscon)
|
||||
}
|
||||
|
||||
static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
|
||||
struct regmap *syscon)
|
||||
struct regmap *syscon, unsigned int offset)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
@ -185,7 +187,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
|
||||
link_speed = 2;
|
||||
|
||||
val = link_speed - 1;
|
||||
ret = regmap_update_bits(syscon, 0, GENERATION_SEL_MASK, val);
|
||||
ret = regmap_update_bits(syscon, offset, GENERATION_SEL_MASK, val);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to set link speed\n");
|
||||
|
||||
@ -193,7 +195,7 @@ static int j721e_pcie_set_link_speed(struct j721e_pcie *pcie,
|
||||
}
|
||||
|
||||
static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
|
||||
struct regmap *syscon)
|
||||
struct regmap *syscon, unsigned int offset)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
u32 lanes = pcie->num_lanes;
|
||||
@ -201,7 +203,7 @@ static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
|
||||
int ret;
|
||||
|
||||
val = LANE_COUNT(lanes - 1);
|
||||
ret = regmap_update_bits(syscon, 0, LANE_COUNT_MASK, val);
|
||||
ret = regmap_update_bits(syscon, offset, LANE_COUNT_MASK, val);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to set link count\n");
|
||||
|
||||
@ -212,6 +214,8 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct of_phandle_args args;
|
||||
unsigned int offset = 0;
|
||||
struct regmap *syscon;
|
||||
int ret;
|
||||
|
||||
@ -221,19 +225,25 @@ static int j721e_pcie_ctrl_init(struct j721e_pcie *pcie)
|
||||
return PTR_ERR(syscon);
|
||||
}
|
||||
|
||||
ret = j721e_pcie_set_mode(pcie, syscon);
|
||||
/* Do not error out to maintain old DT compatibility */
|
||||
ret = of_parse_phandle_with_fixed_args(node, "ti,syscon-pcie-ctrl", 1,
|
||||
0, &args);
|
||||
if (!ret)
|
||||
offset = args.args[0];
|
||||
|
||||
ret = j721e_pcie_set_mode(pcie, syscon, offset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pci mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = j721e_pcie_set_link_speed(pcie, syscon);
|
||||
ret = j721e_pcie_set_link_speed(pcie, syscon, offset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set link speed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = j721e_pcie_set_lane_count(pcie, syscon);
|
||||
ret = j721e_pcie_set_lane_count(pcie, syscon, offset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set num-lanes\n");
|
||||
return ret;
|
||||
|
@ -530,12 +530,9 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
|
||||
}
|
||||
pcie->mem_res = res;
|
||||
|
||||
ret = of_property_read_u32(np, "cdns,max-outbound-regions",
|
||||
&ep->max_regions);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
|
||||
return ret;
|
||||
}
|
||||
ep->max_regions = CDNS_PCIE_MAX_OB;
|
||||
of_property_read_u32(np, "cdns,max-outbound-regions", &ep->max_regions);
|
||||
|
||||
ep->ob_addr = devm_kcalloc(dev,
|
||||
ep->max_regions, sizeof(*ep->ob_addr),
|
||||
GFP_KERNEL);
|
||||
|
@ -197,6 +197,7 @@ enum cdns_pcie_rp_bar {
|
||||
};
|
||||
|
||||
#define CDNS_PCIE_RP_MAX_IB 0x3
|
||||
#define CDNS_PCIE_MAX_OB 32
|
||||
|
||||
struct cdns_pcie_rp_ib_bar {
|
||||
u64 size;
|
||||
|
@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP
|
||||
selected.
|
||||
|
||||
config PCI_EXYNOS
|
||||
bool "Samsung Exynos PCIe controller"
|
||||
depends on SOC_EXYNOS5440 || COMPILE_TEST
|
||||
tristate "Samsung Exynos PCIe controller"
|
||||
depends on ARCH_EXYNOS || COMPILE_TEST
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
help
|
||||
Enables support for the PCIe controller in the Samsung Exynos SoCs
|
||||
to work in host mode. The PCI controller is based on the DesignWare
|
||||
hardware and therefore the driver re-uses the DesignWare core
|
||||
functions to implement the driver.
|
||||
|
||||
config PCI_IMX6
|
||||
bool "Freescale i.MX6/7/8 PCIe controller"
|
||||
@ -107,7 +112,7 @@ config PCI_KEYSTONE
|
||||
|
||||
config PCI_KEYSTONE_HOST
|
||||
bool "PCI Keystone Host Mode"
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
select PCI_KEYSTONE
|
||||
@ -119,7 +124,7 @@ config PCI_KEYSTONE_HOST
|
||||
|
||||
config PCI_KEYSTONE_EP
|
||||
bool "PCI Keystone Endpoint Mode"
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || ((ARM || ARM64) && COMPILE_TEST)
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCI_KEYSTONE
|
||||
@ -169,6 +174,7 @@ config PCIE_QCOM
|
||||
depends on OF && (ARCH_QCOM || COMPILE_TEST)
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
select CRC8
|
||||
help
|
||||
Say Y here to enable PCIe controller support on Qualcomm SoCs. The
|
||||
PCIe controller uses the DesignWare core plus Qualcomm-specific
|
||||
|
@ -181,11 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
dra7xx_pcie_establish_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
dw_pcie_msi_init(pp);
|
||||
dra7xx_pcie_enable_interrupts(dra7xx);
|
||||
|
||||
return 0;
|
||||
@ -377,133 +372,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
u64 msi_target;
|
||||
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
msg->address_lo = lower_32_bits(msi_target);
|
||||
msg->address_hi = upper_32_bits(msi_target);
|
||||
|
||||
msg->data = d->hwirq;
|
||||
|
||||
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
|
||||
(int)d->hwirq, msg->address_hi, msg->address_lo);
|
||||
}
|
||||
|
||||
static int dra7xx_pcie_msi_set_affinity(struct irq_data *d,
|
||||
const struct cpumask *mask,
|
||||
bool force)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_bottom_mask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
|
||||
pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_bottom_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
|
||||
pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_bottom_ack(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
|
||||
}
|
||||
|
||||
static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
|
||||
.name = "DRA7XX-PCI-MSI",
|
||||
.irq_ack = dra7xx_pcie_bottom_ack,
|
||||
.irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg,
|
||||
.irq_set_affinity = dra7xx_pcie_msi_set_affinity,
|
||||
.irq_mask = dra7xx_pcie_bottom_mask,
|
||||
.irq_unmask = dra7xx_pcie_bottom_unmask,
|
||||
};
|
||||
|
||||
static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
u32 ctrl, num_ctrls;
|
||||
int ret;
|
||||
|
||||
pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
|
||||
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
/* Initialize IRQ Status array */
|
||||
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
|
||||
pp->irq_mask[ctrl] = ~0;
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
~0);
|
||||
}
|
||||
|
||||
ret = dw_pcie_allocate_domains(pp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
ret = dma_mapping_error(dev, pp->msi_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to map MSI data\n");
|
||||
pp->msi_data = 0;
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
|
||||
.host_init = dra7xx_pcie_host_init,
|
||||
.msi_host_init = dra7xx_pcie_msi_host_init,
|
||||
};
|
||||
|
||||
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
@ -578,7 +448,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci = dra7xx->pci;
|
||||
|
||||
@ -594,13 +463,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
|
||||
if (IS_ERR(pci->dbi_base2))
|
||||
return PTR_ERR(pci->dbi_base2);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize endpoint\n");
|
||||
@ -622,6 +484,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
|
||||
/* MSI IRQ is muxed */
|
||||
pp->msi_irq = -ENODEV;
|
||||
|
||||
ret = dra7xx_pcie_init_irq_domain(pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -2,26 +2,23 @@
|
||||
/*
|
||||
* PCIe host controller driver for Samsung Exynos SoCs
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
|
||||
* https://www.samsung.com
|
||||
*
|
||||
* Author: Jingoo Han <jg1.han@samsung.com>
|
||||
* Jaehoon Chung <jh80.chung@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/resource.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
@ -37,102 +34,43 @@
|
||||
#define PCIE_IRQ_SPECIAL 0x008
|
||||
#define PCIE_IRQ_EN_PULSE 0x00c
|
||||
#define PCIE_IRQ_EN_LEVEL 0x010
|
||||
#define IRQ_MSI_ENABLE BIT(2)
|
||||
#define PCIE_IRQ_EN_SPECIAL 0x014
|
||||
#define PCIE_PWR_RESET 0x018
|
||||
#define PCIE_SW_WAKE 0x018
|
||||
#define PCIE_BUS_EN BIT(1)
|
||||
#define PCIE_CORE_RESET 0x01c
|
||||
#define PCIE_CORE_RESET_ENABLE BIT(0)
|
||||
#define PCIE_STICKY_RESET 0x020
|
||||
#define PCIE_NONSTICKY_RESET 0x024
|
||||
#define PCIE_APP_INIT_RESET 0x028
|
||||
#define PCIE_APP_LTSSM_ENABLE 0x02c
|
||||
#define PCIE_ELBI_RDLH_LINKUP 0x064
|
||||
#define PCIE_ELBI_RDLH_LINKUP 0x074
|
||||
#define PCIE_ELBI_XMLH_LINKUP BIT(4)
|
||||
#define PCIE_ELBI_LTSSM_ENABLE 0x1
|
||||
#define PCIE_ELBI_SLV_AWMISC 0x11c
|
||||
#define PCIE_ELBI_SLV_ARMISC 0x120
|
||||
#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
|
||||
|
||||
struct exynos_pcie_mem_res {
|
||||
void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
|
||||
};
|
||||
|
||||
struct exynos_pcie_clk_res {
|
||||
struct clk *clk;
|
||||
struct clk *bus_clk;
|
||||
};
|
||||
|
||||
struct exynos_pcie {
|
||||
struct dw_pcie *pci;
|
||||
struct exynos_pcie_mem_res *mem_res;
|
||||
struct exynos_pcie_clk_res *clk_res;
|
||||
const struct exynos_pcie_ops *ops;
|
||||
int reset_gpio;
|
||||
|
||||
struct dw_pcie pci;
|
||||
void __iomem *elbi_base;
|
||||
struct clk *clk;
|
||||
struct clk *bus_clk;
|
||||
struct phy *phy;
|
||||
struct regulator_bulk_data supplies[2];
|
||||
};
|
||||
|
||||
struct exynos_pcie_ops {
|
||||
int (*get_mem_resources)(struct platform_device *pdev,
|
||||
struct exynos_pcie *ep);
|
||||
int (*get_clk_resources)(struct exynos_pcie *ep);
|
||||
int (*init_clk_resources)(struct exynos_pcie *ep);
|
||||
void (*deinit_clk_resources)(struct exynos_pcie *ep);
|
||||
};
|
||||
|
||||
static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
|
||||
struct exynos_pcie *ep)
|
||||
static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
|
||||
if (!ep->mem_res)
|
||||
return -ENOMEM;
|
||||
|
||||
ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ep->mem_res->elbi_base))
|
||||
return PTR_ERR(ep->mem_res->elbi_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
|
||||
if (!ep->clk_res)
|
||||
return -ENOMEM;
|
||||
|
||||
ep->clk_res->clk = devm_clk_get(dev, "pcie");
|
||||
if (IS_ERR(ep->clk_res->clk)) {
|
||||
dev_err(dev, "Failed to get pcie rc clock\n");
|
||||
return PTR_ERR(ep->clk_res->clk);
|
||||
}
|
||||
|
||||
ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
|
||||
if (IS_ERR(ep->clk_res->bus_clk)) {
|
||||
dev_err(dev, "Failed to get pcie bus clock\n");
|
||||
return PTR_ERR(ep->clk_res->bus_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct device *dev = pci->dev;
|
||||
struct device *dev = ep->pci.dev;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(ep->clk_res->clk);
|
||||
ret = clk_prepare_enable(ep->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot enable pcie rc clock");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ep->clk_res->bus_clk);
|
||||
ret = clk_prepare_enable(ep->bus_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot enable pcie bus clock");
|
||||
goto err_bus_clk;
|
||||
@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
|
||||
return 0;
|
||||
|
||||
err_bus_clk:
|
||||
clk_disable_unprepare(ep->clk_res->clk);
|
||||
clk_disable_unprepare(ep->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
|
||||
static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
|
||||
{
|
||||
clk_disable_unprepare(ep->clk_res->bus_clk);
|
||||
clk_disable_unprepare(ep->clk_res->clk);
|
||||
clk_disable_unprepare(ep->bus_clk);
|
||||
clk_disable_unprepare(ep->clk);
|
||||
}
|
||||
|
||||
static const struct exynos_pcie_ops exynos5440_pcie_ops = {
|
||||
.get_mem_resources = exynos5440_pcie_get_mem_resources,
|
||||
.get_clk_resources = exynos5440_pcie_get_clk_resources,
|
||||
.init_clk_resources = exynos5440_pcie_init_clk_resources,
|
||||
.deinit_clk_resources = exynos5440_pcie_deinit_clk_resources,
|
||||
};
|
||||
|
||||
static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, base + reg);
|
||||
@ -173,115 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
|
||||
val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
|
||||
if (on)
|
||||
val |= PCIE_ELBI_SLV_DBI_ENABLE;
|
||||
else
|
||||
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
|
||||
}
|
||||
|
||||
static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
|
||||
val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
|
||||
if (on)
|
||||
val |= PCIE_ELBI_SLV_DBI_ENABLE;
|
||||
else
|
||||
val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
|
||||
}
|
||||
|
||||
static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
|
||||
val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
|
||||
val &= ~PCIE_CORE_RESET_ENABLE;
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
|
||||
val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
|
||||
val |= PCIE_CORE_RESET_ENABLE;
|
||||
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
|
||||
exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
|
||||
static int exynos_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct device *dev = pci->dev;
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
if (ep->reset_gpio >= 0)
|
||||
devm_gpio_request_one(dev, ep->reset_gpio,
|
||||
GPIOF_OUT_INIT_HIGH, "RESET");
|
||||
}
|
||||
|
||||
static int exynos_pcie_establish_link(struct exynos_pcie *ep)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(dev, "Link already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
exynos_pcie_assert_core_reset(ep);
|
||||
|
||||
phy_reset(ep->phy);
|
||||
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1,
|
||||
PCIE_PWR_RESET);
|
||||
|
||||
phy_power_on(ep->phy);
|
||||
phy_init(ep->phy);
|
||||
|
||||
exynos_pcie_deassert_core_reset(ep);
|
||||
dw_pcie_setup_rc(pp);
|
||||
exynos_pcie_assert_reset(ep);
|
||||
val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
|
||||
val &= ~PCIE_BUS_EN;
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
|
||||
|
||||
/* assert LTSSM enable */
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
|
||||
exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
|
||||
PCIE_APP_LTSSM_ENABLE);
|
||||
|
||||
/* check if the link is up or not */
|
||||
if (!dw_pcie_wait_for_link(pci))
|
||||
return 0;
|
||||
|
||||
phy_power_off(ep->phy);
|
||||
return -ETIMEDOUT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
|
||||
}
|
||||
|
||||
static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* enable INTX interrupt */
|
||||
val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
|
||||
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
|
||||
}
|
||||
|
||||
static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
|
||||
@ -292,26 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void exynos_pcie_msi_init(struct exynos_pcie *ep)
|
||||
static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u32 val;
|
||||
u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
|
||||
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
|
||||
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
/* enable MSI interrupt */
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
|
||||
val |= IRQ_MSI_ENABLE;
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
|
||||
}
|
||||
|
||||
static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep)
|
||||
{
|
||||
exynos_pcie_enable_irq_pulse(ep);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
exynos_pcie_msi_init(ep);
|
||||
exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
|
||||
exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
|
||||
exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
|
||||
}
|
||||
|
||||
static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
@ -370,13 +245,9 @@ static struct pci_ops exynos_pci_ops = {
|
||||
static int exynos_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
u32 val;
|
||||
u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP);
|
||||
if (val == PCIE_ELBI_LTSSM_ENABLE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return (val & PCIE_ELBI_XMLH_LINKUP);
|
||||
}
|
||||
|
||||
static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
@ -386,8 +257,14 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
|
||||
pp->bridge->ops = &exynos_pci_ops;
|
||||
|
||||
exynos_pcie_establish_link(ep);
|
||||
exynos_pcie_enable_interrupts(ep);
|
||||
exynos_pcie_assert_core_reset(ep);
|
||||
|
||||
phy_reset(ep->phy);
|
||||
phy_power_on(ep->phy);
|
||||
phy_init(ep->phy);
|
||||
|
||||
exynos_pcie_deassert_core_reset(ep);
|
||||
exynos_pcie_enable_irq_pulse(ep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -396,32 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
|
||||
.host_init = exynos_pcie_host_init,
|
||||
};
|
||||
|
||||
static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
|
||||
static int exynos_add_pcie_port(struct exynos_pcie *ep,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = ep->pci;
|
||||
struct dw_pcie *pci = &ep->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 1);
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
|
||||
ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
|
||||
IRQF_SHARED, "exynos-pcie", ep);
|
||||
IRQF_SHARED, "exynos-pcie", ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to request irq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
pp->ops = &exynos_pcie_host_ops;
|
||||
pp->msi_irq = -ENODEV;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
@ -436,12 +308,12 @@ static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.read_dbi = exynos_pcie_read_dbi,
|
||||
.write_dbi = exynos_pcie_write_dbi,
|
||||
.link_up = exynos_pcie_link_up,
|
||||
.start_link = exynos_pcie_start_link,
|
||||
};
|
||||
|
||||
static int __init exynos_pcie_probe(struct platform_device *pdev)
|
||||
static int exynos_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci;
|
||||
struct exynos_pcie *ep;
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
@ -450,42 +322,44 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
||||
if (!ep)
|
||||
return -ENOMEM;
|
||||
|
||||
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
|
||||
if (!pci)
|
||||
return -ENOMEM;
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
ep->pci = pci;
|
||||
ep->ops = (const struct exynos_pcie_ops *)
|
||||
of_device_get_match_data(dev);
|
||||
|
||||
ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
ep->pci.dev = dev;
|
||||
ep->pci.ops = &dw_pcie_ops;
|
||||
|
||||
ep->phy = devm_of_phy_get(dev, np, NULL);
|
||||
if (IS_ERR(ep->phy)) {
|
||||
if (PTR_ERR(ep->phy) != -ENODEV)
|
||||
return PTR_ERR(ep->phy);
|
||||
if (IS_ERR(ep->phy))
|
||||
return PTR_ERR(ep->phy);
|
||||
|
||||
ep->phy = NULL;
|
||||
/* External Local Bus interface (ELBI) registers */
|
||||
ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
|
||||
if (IS_ERR(ep->elbi_base))
|
||||
return PTR_ERR(ep->elbi_base);
|
||||
|
||||
ep->clk = devm_clk_get(dev, "pcie");
|
||||
if (IS_ERR(ep->clk)) {
|
||||
dev_err(dev, "Failed to get pcie rc clock\n");
|
||||
return PTR_ERR(ep->clk);
|
||||
}
|
||||
|
||||
if (ep->ops && ep->ops->get_mem_resources) {
|
||||
ret = ep->ops->get_mem_resources(pdev, ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
ep->bus_clk = devm_clk_get(dev, "pcie_bus");
|
||||
if (IS_ERR(ep->bus_clk)) {
|
||||
dev_err(dev, "Failed to get pcie bus clock\n");
|
||||
return PTR_ERR(ep->bus_clk);
|
||||
}
|
||||
|
||||
if (ep->ops && ep->ops->get_clk_resources &&
|
||||
ep->ops->init_clk_resources) {
|
||||
ret = ep->ops->get_clk_resources(ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = ep->ops->init_clk_resources(ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ep->supplies[0].supply = "vdd18";
|
||||
ep->supplies[1].supply = "vdd10";
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies),
|
||||
ep->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = exynos_pcie_init_clk_resources(ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, ep);
|
||||
|
||||
@ -497,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
fail_probe:
|
||||
phy_exit(ep->phy);
|
||||
exynos_pcie_deinit_clk_resources(ep);
|
||||
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
|
||||
|
||||
if (ep->ops && ep->ops->deinit_clk_resources)
|
||||
ep->ops->deinit_clk_resources(ep);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -507,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_pcie *ep = platform_get_drvdata(pdev);
|
||||
|
||||
if (ep->ops && ep->ops->deinit_clk_resources)
|
||||
ep->ops->deinit_clk_resources(ep);
|
||||
dw_pcie_host_deinit(&ep->pci.pp);
|
||||
exynos_pcie_assert_core_reset(ep);
|
||||
phy_power_off(ep->phy);
|
||||
phy_exit(ep->phy);
|
||||
exynos_pcie_deinit_clk_resources(ep);
|
||||
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct exynos_pcie *ep = dev_get_drvdata(dev);
|
||||
|
||||
exynos_pcie_assert_core_reset(ep);
|
||||
phy_power_off(ep->phy);
|
||||
phy_exit(ep->phy);
|
||||
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct exynos_pcie *ep = dev_get_drvdata(dev);
|
||||
struct dw_pcie *pci = &ep->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* exynos_pcie_host_init controls ep->phy */
|
||||
exynos_pcie_host_init(pp);
|
||||
dw_pcie_setup_rc(pp);
|
||||
exynos_pcie_start_link(pci);
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops exynos_pcie_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq,
|
||||
exynos_pcie_resume_noirq)
|
||||
};
|
||||
|
||||
static const struct of_device_id exynos_pcie_of_match[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5440-pcie",
|
||||
.data = &exynos5440_pcie_ops
|
||||
},
|
||||
{},
|
||||
{ .compatible = "samsung,exynos5433-pcie", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver exynos_pcie_driver = {
|
||||
.probe = exynos_pcie_probe,
|
||||
.remove = __exit_p(exynos_pcie_remove),
|
||||
.driver = {
|
||||
.name = "exynos-pcie",
|
||||
.of_match_table = exynos_pcie_of_match,
|
||||
.pm = &exynos_pcie_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
/* Exynos PCIe driver does not allow module unload */
|
||||
|
||||
static int __init exynos_pcie_init(void)
|
||||
{
|
||||
return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
|
||||
}
|
||||
subsys_initcall(exynos_pcie_init);
|
||||
module_platform_driver(exynos_pcie_driver);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
|
||||
|
@ -745,9 +745,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
static int imx6_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = imx6_pcie->pci;
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u32 tmp;
|
||||
@ -834,9 +834,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
|
||||
imx6_pcie_init_phy(imx6_pcie);
|
||||
imx6_pcie_deassert_core_reset(imx6_pcie);
|
||||
imx6_setup_phy_mpll(imx6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
imx6_pcie_establish_link(imx6_pcie);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -845,33 +842,8 @@ static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
|
||||
.host_init = imx6_pcie_host_init,
|
||||
};
|
||||
|
||||
static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = imx6_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
pp->ops = &imx6_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
/* No special ops needed, but pcie-designware still expects this struct */
|
||||
.start_link = imx6_pcie_start_link,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@ -980,7 +952,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
|
||||
imx6_pcie_deassert_core_reset(imx6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
ret = imx6_pcie_establish_link(imx6_pcie);
|
||||
ret = imx6_pcie_start_link(imx6_pcie->pci);
|
||||
if (ret < 0)
|
||||
dev_info(dev, "pcie link is down after resume.\n");
|
||||
|
||||
@ -1014,6 +986,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
pci->pp.ops = &imx6_pcie_host_ops;
|
||||
|
||||
imx6_pcie->pci = pci;
|
||||
imx6_pcie->drvdata = of_device_get_match_data(dev);
|
||||
@ -1163,7 +1136,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = imx6_add_pcie_port(imx6_pcie, pdev);
|
||||
ret = dw_pcie_host_init(&pci->pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -121,6 +121,7 @@ struct keystone_pcie {
|
||||
|
||||
int msi_host_irq;
|
||||
int num_lanes;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
struct device_link **link;
|
||||
struct device_node *msi_intc_np;
|
||||
@ -272,14 +273,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
|
||||
ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy function so that DW core doesn't configure MSI
|
||||
*/
|
||||
static int ks_pcie_am654_msi_host_init(struct pcie_port *pp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
|
||||
@ -394,9 +387,9 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
|
||||
static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
u32 val;
|
||||
u32 num_viewport = ks_pcie->num_viewport;
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u32 num_viewport = pci->num_viewport;
|
||||
u64 start, end;
|
||||
struct resource *mem;
|
||||
int i;
|
||||
@ -519,14 +512,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
|
||||
static int ks_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_dbg(dev, "link is already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initiate Link Training */
|
||||
val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
|
||||
ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
|
||||
@ -821,8 +808,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
ks_pcie_stop_link(pci);
|
||||
ks_pcie_setup_rc_app_regs(ks_pcie);
|
||||
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
|
||||
@ -841,9 +826,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
"Asynchronous external abort");
|
||||
#endif
|
||||
|
||||
ks_pcie_start_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -854,7 +836,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
|
||||
|
||||
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
|
||||
.host_init = ks_pcie_host_init,
|
||||
.msi_host_init = ks_pcie_am654_msi_host_init,
|
||||
};
|
||||
|
||||
static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
|
||||
@ -864,23 +845,6 @@ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
|
||||
return ks_pcie_handle_error_irq(ks_pcie);
|
||||
}
|
||||
|
||||
static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size, u32 val)
|
||||
{
|
||||
@ -977,33 +941,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
|
||||
.get_features = &ks_pcie_am654_get_features,
|
||||
};
|
||||
|
||||
static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
|
||||
ep = &pci->ep;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
int num_lanes = ks_pcie->num_lanes;
|
||||
@ -1157,6 +1094,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
unsigned int version;
|
||||
void __iomem *base;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
u32 num_lanes;
|
||||
char name[10];
|
||||
@ -1288,6 +1226,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to read *num-viewport* property\n");
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
/*
|
||||
* "Power Sequencing and Reset Signal Timings" table in
|
||||
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
|
||||
@ -1301,8 +1245,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
gpiod_set_value_cansleep(gpiod, 1);
|
||||
}
|
||||
|
||||
ks_pcie->num_viewport = num_viewport;
|
||||
pci->pp.ops = host_ops;
|
||||
ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
|
||||
ret = dw_pcie_host_init(&pci->pp);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
break;
|
||||
@ -1313,7 +1258,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
pci->ep.ops = ep_ops;
|
||||
ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
|
||||
ret = dw_pcie_ep_init(&pci->ep);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
break;
|
||||
|
@ -18,8 +18,6 @@
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
|
||||
|
||||
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
struct ls_pcie_ep_drvdata {
|
||||
@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = pcie->drvdata->ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
struct ls_pcie_ep *pcie;
|
||||
struct pci_epc_features *ls_epc;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||
if (!pcie)
|
||||
@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
|
||||
pci->ep.ops = &ls_pcie_ep_ops;
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
ret = ls_add_pcie_ep(pcie, pdev);
|
||||
|
||||
return ret;
|
||||
return dw_pcie_ep_init(&pci->ep);
|
||||
}
|
||||
|
||||
static struct platform_driver ls_pcie_ep_driver = {
|
||||
|
@ -83,14 +83,6 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie)
|
||||
iowrite32(val, pci->dbi_base + PCIE_STRFMR1);
|
||||
}
|
||||
|
||||
static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PCIE_IATU_NUM; i++)
|
||||
dw_pcie_disable_atu(pcie->pci, i, DW_PCIE_REGION_OUTBOUND);
|
||||
}
|
||||
|
||||
static int ls1021_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u32 state;
|
||||
@ -136,12 +128,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct ls_pcie *pcie = to_ls_pcie(pci);
|
||||
|
||||
/*
|
||||
* Disable outbound windows configured by the bootloader to avoid
|
||||
* one transaction hitting multiple outbound windows.
|
||||
* dw_pcie_setup_rc() will reconfigure the outbound windows.
|
||||
*/
|
||||
ls_pcie_disable_outbound_atus(pcie);
|
||||
ls_pcie_fix_error_response(pcie);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
@ -150,8 +136,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
|
||||
|
||||
ls_pcie_drop_msg_tlp(pcie);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,37 +166,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp)
|
||||
return ls_pcie_host_init(pp);
|
||||
}
|
||||
|
||||
static int ls_pcie_msi_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *msi_node;
|
||||
|
||||
/*
|
||||
* The MSI domain is set by the generic of_msi_configure(). This
|
||||
* .msi_host_init() function keeps us from doing the default MSI
|
||||
* domain setup in dw_pcie_host_init() and also enforces the
|
||||
* requirement that "msi-parent" exists.
|
||||
*/
|
||||
msi_node = of_parse_phandle(np, "msi-parent", 0);
|
||||
if (!msi_node) {
|
||||
dev_err(dev, "failed to find msi-parent\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
of_node_put(msi_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
|
||||
.host_init = ls1021_pcie_host_init,
|
||||
.msi_host_init = ls_pcie_msi_host_init,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
|
||||
.host_init = ls_pcie_host_init,
|
||||
.msi_host_init = ls_pcie_msi_host_init,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
|
||||
@ -273,31 +232,12 @@ static const struct of_device_id ls_pcie_of_match[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __init ls_add_pcie_port(struct ls_pcie *pcie)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
||||
pp->ops = pcie->drvdata->ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ls_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci;
|
||||
struct ls_pcie *pcie;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
||||
if (!pcie)
|
||||
@ -311,6 +251,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = pcie->drvdata->dw_pcie_ops;
|
||||
pci->pp.ops = pcie->drvdata->ops;
|
||||
|
||||
pcie->pci = pci;
|
||||
|
||||
@ -326,11 +267,7 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
ret = ls_add_pcie_port(pcie);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return dw_pcie_host_init(&pci->pp);
|
||||
}
|
||||
|
||||
static struct platform_driver ls_pcie_driver = {
|
||||
|
@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
|
||||
gpiod_set_value_cansleep(mp->reset_gpio, 0);
|
||||
}
|
||||
|
||||
static void meson_pcie_init_dw(struct meson_pcie *mp)
|
||||
static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
}
|
||||
|
||||
static int meson_pcie_establish_link(struct meson_pcie *mp)
|
||||
static int meson_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
|
||||
meson_pcie_init_dw(mp);
|
||||
meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
|
||||
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
struct meson_pcie *mp = to_meson_pcie(pci);
|
||||
|
||||
meson_pcie_ltssm_enable(mp);
|
||||
meson_pcie_assert_reset(mp);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
|
||||
@ -380,15 +374,11 @@ static int meson_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct meson_pcie *mp = to_meson_pcie(pci);
|
||||
int ret;
|
||||
|
||||
pp->bridge->ops = &meson_pci_ops;
|
||||
|
||||
ret = meson_pcie_establish_link(mp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_pcie_msi_init(pp);
|
||||
meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
|
||||
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -397,33 +387,9 @@ static const struct dw_pcie_host_ops meson_pcie_host_ops = {
|
||||
.host_init = meson_pcie_host_init,
|
||||
};
|
||||
|
||||
static int meson_add_pcie_port(struct meson_pcie *mp,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
pp->ops = &meson_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = meson_pcie_link_up,
|
||||
.start_link = meson_pcie_start_link,
|
||||
};
|
||||
|
||||
static int meson_pcie_probe(struct platform_device *pdev)
|
||||
@ -440,6 +406,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
|
||||
pci = &mp->pci;
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
pci->pp.ops = &meson_pcie_host_ops;
|
||||
pci->num_lanes = 1;
|
||||
|
||||
mp->phy = devm_phy_get(dev, "pcie");
|
||||
@ -486,7 +453,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, mp);
|
||||
|
||||
ret = meson_add_pcie_port(mp, pdev);
|
||||
ret = dw_pcie_host_init(&pci->pp);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Add PCIe port failed, %d\n", ret);
|
||||
goto err_phy;
|
||||
|
@ -76,7 +76,6 @@ static int al_pcie_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops al_pcie_ops = {
|
||||
.bus_shift = 20,
|
||||
.init = al_pcie_init,
|
||||
.pci_ops = {
|
||||
.map_bus = al_pcie_map_bus,
|
||||
@ -138,8 +137,6 @@ struct al_pcie {
|
||||
struct al_pcie_target_bus_cfg target_bus_cfg;
|
||||
};
|
||||
|
||||
#define PCIE_ECAM_DEVFN(x) (((x) & 0xff) << 12)
|
||||
|
||||
#define to_al_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
static inline u32 al_pcie_controller_readl(struct al_pcie *pcie, u32 offset)
|
||||
@ -226,11 +223,6 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
|
||||
struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
|
||||
unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
|
||||
unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
|
||||
void __iomem *pci_base_addr;
|
||||
|
||||
pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
|
||||
(busnr_ecam << 20) +
|
||||
PCIE_ECAM_DEVFN(devfn));
|
||||
|
||||
if (busnr_reg != target_bus_cfg->reg_val) {
|
||||
dev_dbg(pcie->pci->dev, "Changing target bus busnum val from 0x%x to 0x%x\n",
|
||||
@ -241,7 +233,7 @@ static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
|
||||
target_bus_cfg->reg_mask);
|
||||
}
|
||||
|
||||
return pci_base_addr + where;
|
||||
return pp->va_cfg0_base + PCIE_ECAM_OFFSET(busnr_ecam, devfn, where);
|
||||
}
|
||||
|
||||
static struct pci_ops al_child_pci_ops = {
|
||||
@ -264,7 +256,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
|
||||
target_bus_cfg = &pcie->target_bus_cfg;
|
||||
|
||||
ecam_bus_mask = (pcie->ecam_size >> 20) - 1;
|
||||
ecam_bus_mask = (pcie->ecam_size >> PCIE_ECAM_BUS_SHIFT) - 1;
|
||||
if (ecam_bus_mask > 255) {
|
||||
dev_warn(pcie->dev, "ECAM window size is larger than 256MB. Cutting off at 256\n");
|
||||
ecam_bus_mask = 255;
|
||||
@ -322,23 +314,6 @@ static const struct dw_pcie_host_ops al_pcie_host_ops = {
|
||||
.host_init = al_pcie_host_init,
|
||||
};
|
||||
|
||||
static int al_add_pcie_port(struct pcie_port *pp,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
pp->ops = &al_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
};
|
||||
|
||||
@ -347,7 +322,6 @@ static int al_pcie_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *controller_res;
|
||||
struct resource *ecam_res;
|
||||
struct resource *dbi_res;
|
||||
struct al_pcie *al_pcie;
|
||||
struct dw_pcie *pci;
|
||||
|
||||
@ -361,15 +335,11 @@ static int al_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
pci->pp.ops = &al_pcie_host_ops;
|
||||
|
||||
al_pcie->pci = pci;
|
||||
al_pcie->dev = dev;
|
||||
|
||||
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
if (!ecam_res) {
|
||||
dev_err(dev, "couldn't find 'config' reg in DT\n");
|
||||
@ -386,12 +356,11 @@ static int al_pcie_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(al_pcie->controller_base);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n",
|
||||
dbi_res, controller_res);
|
||||
dev_dbg(dev, "From DT: controller_base: %pR\n", controller_res);
|
||||
|
||||
platform_set_drvdata(pdev, al_pcie);
|
||||
|
||||
return al_add_pcie_port(&pci->pp, pdev);
|
||||
return dw_pcie_host_init(&pci->pp);
|
||||
}
|
||||
|
||||
static const struct of_device_id al_pcie_of_match[] = {
|
||||
|
@ -154,11 +154,23 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
|
||||
static int armada8k_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
u32 reg;
|
||||
|
||||
/* Start LTSSM */
|
||||
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
|
||||
reg |= PCIE_APP_LTSSM_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada8k_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
u32 reg;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
if (!dw_pcie_link_up(pci)) {
|
||||
/* Disable LTSSM state machine to enable configuration */
|
||||
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
|
||||
@ -193,26 +205,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
|
||||
PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
|
||||
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg);
|
||||
|
||||
if (!dw_pcie_link_up(pci)) {
|
||||
/* Configuration done. Start LTSSM */
|
||||
reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
|
||||
reg |= PCIE_APP_LTSSM_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
|
||||
}
|
||||
|
||||
/* Wait until the link becomes active again */
|
||||
if (dw_pcie_wait_for_link(pci))
|
||||
dev_err(pci->dev, "Link not up after reconfiguration\n");
|
||||
}
|
||||
|
||||
static int armada8k_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
armada8k_pcie_establish_link(pcie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -269,6 +261,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = armada8k_pcie_link_up,
|
||||
.start_link = armada8k_pcie_start_link,
|
||||
};
|
||||
|
||||
static int armada8k_pcie_probe(struct platform_device *pdev)
|
||||
|
@ -328,10 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
artpec6_pcie_establish_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -340,31 +336,6 @@ static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
|
||||
.host_init = artpec6_pcie_host_init,
|
||||
};
|
||||
|
||||
static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
pp->ops = &artpec6_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
@ -403,38 +374,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.raise_irq = artpec6_pcie_raise_irq,
|
||||
};
|
||||
|
||||
static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
|
||||
if (IS_ERR(pci->dbi_base2))
|
||||
return PTR_ERR(pci->dbi_base2);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -469,10 +408,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
artpec6_pcie->variant = variant;
|
||||
artpec6_pcie->mode = mode;
|
||||
|
||||
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
artpec6_pcie->phy_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "phy");
|
||||
if (IS_ERR(artpec6_pcie->phy_base))
|
||||
@ -491,7 +426,9 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST))
|
||||
return -ENODEV;
|
||||
|
||||
ret = artpec6_add_pcie_port(artpec6_pcie, pdev);
|
||||
pci->pp.ops = &artpec6_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(&pci->pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
@ -504,9 +441,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val &= ~PCIECFG_DEVICE_TYPE_MASK;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
ret = artpec6_add_pcie_ep(artpec6_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pci->ep.ops = &pcie_ep_ops;
|
||||
|
||||
return dw_pcie_ep_init(&pci->ep);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
#include <linux/pci-epc.h>
|
||||
@ -160,8 +161,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u32 free_win;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
free_win = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
|
||||
if (free_win >= ep->num_ib_windows) {
|
||||
free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows);
|
||||
if (free_win >= pci->num_ib_windows) {
|
||||
dev_err(pci->dev, "No free inbound window\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -186,8 +187,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u32 free_win;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
free_win = find_first_zero_bit(ep->ob_window_map, ep->num_ob_windows);
|
||||
if (free_win >= ep->num_ob_windows) {
|
||||
free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows);
|
||||
if (free_win >= pci->num_ob_windows) {
|
||||
dev_err(pci->dev, "No free outbound window\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -263,8 +264,9 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
|
||||
u32 *atu_index)
|
||||
{
|
||||
u32 index;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
for (index = 0; index < ep->num_ob_windows; index++) {
|
||||
for (index = 0; index < pci->num_ob_windows; index++) {
|
||||
if (ep->outbound_addr[index] != addr)
|
||||
continue;
|
||||
*atu_index = index;
|
||||
@ -676,55 +678,57 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
int ret;
|
||||
void *addr;
|
||||
u8 func_no;
|
||||
struct resource *res;
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct device *dev = pci->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct pci_epc_features *epc_features;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
INIT_LIST_HEAD(&ep->func_list);
|
||||
|
||||
if (!pci->dbi_base || !pci->dbi_base2) {
|
||||
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
|
||||
return -EINVAL;
|
||||
if (!pci->dbi_base) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to read *num-ib-windows* property\n");
|
||||
return ret;
|
||||
}
|
||||
if (ep->num_ib_windows > MAX_IATU_IN) {
|
||||
dev_err(dev, "Invalid *num-ib-windows*\n");
|
||||
return -EINVAL;
|
||||
if (!pci->dbi_base2) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
|
||||
if (!res)
|
||||
pci->dbi_base2 = pci->dbi_base + SZ_4K;
|
||||
else {
|
||||
pci->dbi_base2 = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(pci->dbi_base2))
|
||||
return PTR_ERR(pci->dbi_base2);
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Unable to read *num-ob-windows* property\n");
|
||||
return ret;
|
||||
}
|
||||
if (ep->num_ob_windows > MAX_IATU_OUT) {
|
||||
dev_err(dev, "Invalid *num-ob-windows*\n");
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ep->ib_window_map = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(ep->num_ib_windows),
|
||||
BITS_TO_LONGS(pci->num_ib_windows),
|
||||
sizeof(long),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ib_window_map)
|
||||
return -ENOMEM;
|
||||
|
||||
ep->ob_window_map = devm_kcalloc(dev,
|
||||
BITS_TO_LONGS(ep->num_ob_windows),
|
||||
BITS_TO_LONGS(pci->num_ob_windows),
|
||||
sizeof(long),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ob_window_map)
|
||||
return -ENOMEM;
|
||||
|
||||
addr = devm_kcalloc(dev, ep->num_ob_windows, sizeof(phys_addr_t),
|
||||
addr = devm_kcalloc(dev, pci->num_ob_windows, sizeof(phys_addr_t),
|
||||
GFP_KERNEL);
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
|
@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
static void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
{
|
||||
if (pp->msi_irq) {
|
||||
irq_set_chained_handler(pp->msi_irq, NULL);
|
||||
@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
static void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
u64 msi_target = (u64)pp->msi_data;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCI_MSI))
|
||||
if (!pci_msi_enabled() || !pp->has_msi_ctrl)
|
||||
return;
|
||||
|
||||
/* Program the msi_data */
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
|
||||
|
||||
int dw_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
@ -310,6 +309,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
dev_err(dev, "Missing *config* reg space\n");
|
||||
}
|
||||
|
||||
if (!pci->dbi_base) {
|
||||
struct resource *dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
}
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, 0);
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
@ -350,44 +356,54 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
|
||||
if (ret)
|
||||
pci->num_viewport = 2;
|
||||
|
||||
if (pci->link_gen < 1)
|
||||
pci->link_gen = of_pci_get_max_link_speed(np);
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
/*
|
||||
* If a specific SoC driver needs to change the
|
||||
* default number of vectors, it needs to implement
|
||||
* the set_num_vectors callback.
|
||||
*/
|
||||
if (!pp->ops->set_num_vectors) {
|
||||
pp->num_vectors = MSI_DEF_NUM_VECTORS;
|
||||
} else {
|
||||
pp->ops->set_num_vectors(pp);
|
||||
pp->has_msi_ctrl = !(pp->ops->msi_host_init ||
|
||||
of_property_read_bool(np, "msi-parent") ||
|
||||
of_property_read_bool(np, "msi-map"));
|
||||
|
||||
if (pp->num_vectors > MAX_MSI_IRQS ||
|
||||
pp->num_vectors == 0) {
|
||||
dev_err(dev,
|
||||
"Invalid number of vectors\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!pp->num_vectors) {
|
||||
pp->num_vectors = MSI_DEF_NUM_VECTORS;
|
||||
} else if (pp->num_vectors > MAX_MSI_IRQS) {
|
||||
dev_err(dev, "Invalid number of vectors\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pp->ops->msi_host_init) {
|
||||
if (pp->ops->msi_host_init) {
|
||||
ret = pp->ops->msi_host_init(pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else if (pp->has_msi_ctrl) {
|
||||
if (!pp->msi_irq) {
|
||||
pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
|
||||
if (pp->msi_irq < 0) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
}
|
||||
|
||||
pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
|
||||
|
||||
ret = dw_pcie_allocate_domains(pp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pp->msi_irq)
|
||||
if (pp->msi_irq > 0)
|
||||
irq_set_chained_handler_and_data(pp->msi_irq,
|
||||
dw_chained_msi_isr,
|
||||
pp);
|
||||
|
||||
ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32));
|
||||
if (!ret) {
|
||||
dev_warn(pci->dev,
|
||||
"Failed to set DMA mask to 32-bit. "
|
||||
"Devices with only 32-bit MSI support"
|
||||
" may not work properly\n");
|
||||
}
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
@ -397,10 +413,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
pp->msi_data = 0;
|
||||
goto err_free_msi;
|
||||
}
|
||||
} else {
|
||||
ret = pp->ops->msi_host_init(pp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,6 +426,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
|
||||
ret = pci->ops->start_link(pci);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
/* Ignore errors, the link may come up later */
|
||||
dw_pcie_wait_for_link(pci);
|
||||
|
||||
bridge->sysdata = pp;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
@ -421,7 +445,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
return 0;
|
||||
|
||||
err_free_msi:
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
if (pp->has_msi_ctrl)
|
||||
dw_pcie_free_msi(pp);
|
||||
return ret;
|
||||
}
|
||||
@ -431,7 +455,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
|
||||
{
|
||||
pci_stop_root_bus(pp->bridge->bus);
|
||||
pci_remove_root_bus(pp->bridge->bus);
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
if (pp->has_msi_ctrl)
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
|
||||
@ -464,9 +488,7 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
|
||||
type = PCIE_ATU_TYPE_CFG1;
|
||||
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
type, pp->cfg0_base,
|
||||
busdev, pp->cfg0_size);
|
||||
dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size);
|
||||
|
||||
return pp->va_cfg0_base + where;
|
||||
}
|
||||
@ -480,9 +502,8 @@ static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
|
||||
ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
if (!ret && pci->io_cfg_atu_shared)
|
||||
dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
|
||||
return ret;
|
||||
@ -497,9 +518,8 @@ static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
|
||||
ret = pci_generic_config_write(bus, devfn, where, size, val);
|
||||
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
if (!ret && pci->io_cfg_atu_shared)
|
||||
dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
|
||||
return ret;
|
||||
@ -531,6 +551,7 @@ static struct pci_ops dw_pcie_ops = {
|
||||
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
{
|
||||
int i;
|
||||
u32 val, ctrl, num_ctrls;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
@ -542,7 +563,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init) {
|
||||
if (pp->has_msi_ctrl) {
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
/* Initialize IRQ Status array */
|
||||
@ -580,27 +601,45 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
|
||||
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
|
||||
|
||||
/* Ensure all outbound windows are disabled so there are multiple matches */
|
||||
for (i = 0; i < pci->num_ob_windows; i++)
|
||||
dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND);
|
||||
|
||||
/*
|
||||
* If the platform provides its own child bus config accesses, it means
|
||||
* the platform uses its own address translation component rather than
|
||||
* ATU, so we should not program the ATU here.
|
||||
*/
|
||||
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
|
||||
struct resource_entry *tmp, *entry = NULL;
|
||||
int atu_idx = 0;
|
||||
struct resource_entry *entry;
|
||||
|
||||
/* Get last memory resource entry */
|
||||
resource_list_for_each_entry(tmp, &pp->bridge->windows)
|
||||
if (resource_type(tmp->res) == IORESOURCE_MEM)
|
||||
entry = tmp;
|
||||
resource_list_for_each_entry(entry, &pp->bridge->windows) {
|
||||
if (resource_type(entry->res) != IORESOURCE_MEM)
|
||||
continue;
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, entry->res->start,
|
||||
entry->res->start - entry->offset,
|
||||
resource_size(entry->res));
|
||||
if (pci->num_viewport > 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
if (pci->num_ob_windows <= ++atu_idx)
|
||||
break;
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, atu_idx,
|
||||
PCIE_ATU_TYPE_MEM, entry->res->start,
|
||||
entry->res->start - entry->offset,
|
||||
resource_size(entry->res));
|
||||
}
|
||||
|
||||
if (pp->io_size) {
|
||||
if (pci->num_ob_windows > ++atu_idx)
|
||||
dw_pcie_prog_outbound_atu(pci, atu_idx,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
else
|
||||
pci->io_cfg_atu_shared = true;
|
||||
}
|
||||
|
||||
if (pci->num_ob_windows <= atu_idx)
|
||||
dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)",
|
||||
pci->num_ob_windows);
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
|
@ -33,25 +33,7 @@ struct dw_plat_pcie_of_data {
|
||||
|
||||
static const struct of_device_id dw_plat_pcie_of_match[];
|
||||
|
||||
static int dw_plat_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_plat_set_num_vectors(struct pcie_port *pp)
|
||||
{
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
|
||||
.host_init = dw_plat_pcie_host_init,
|
||||
.set_num_vectors = dw_plat_set_num_vectors,
|
||||
};
|
||||
|
||||
static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
|
||||
@ -122,12 +104,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
|
||||
if (pp->irq < 0)
|
||||
return pp->irq;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
pp->ops = &dw_plat_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
@ -139,43 +116,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci = dw_plat_pcie->pci;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
|
||||
if (IS_ERR(pci->dbi_base2))
|
||||
return PTR_ERR(pci->dbi_base2);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to initialize endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_plat_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_plat_pcie *dw_plat_pcie;
|
||||
struct dw_pcie *pci;
|
||||
struct resource *res; /* Resource from DT */
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
const struct dw_plat_pcie_of_data *data;
|
||||
@ -202,14 +147,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
|
||||
dw_plat_pcie->pci = pci;
|
||||
dw_plat_pcie->mode = mode;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
if (!res)
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
pci->dbi_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
platform_set_drvdata(pdev, dw_plat_pcie);
|
||||
|
||||
switch (dw_plat_pcie->mode) {
|
||||
@ -225,9 +162,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
|
||||
if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
|
||||
return -ENODEV;
|
||||
|
||||
ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pci->ep.ops = &pcie_ep_ops;
|
||||
return dw_pcie_ep_init(&pci->ep);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
|
||||
|
@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr,
|
||||
u32 size)
|
||||
u64 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
u64 limit_addr = cpu_addr + size - 1;
|
||||
@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
lower_32_bits(pci_addr));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
|
||||
upper_32_bits(pci_addr));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
|
||||
type | PCIE_ATU_FUNC_NUM(func_no));
|
||||
val = type | PCIE_ATU_FUNC_NUM(func_no);
|
||||
val = upper_32_bits(size - 1) ?
|
||||
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
|
||||
PCIE_ATU_ENABLE);
|
||||
|
||||
@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
|
||||
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
u64 pci_addr, u64 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
|
||||
@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
u64 cpu_addr, u64 pci_addr, u64 size)
|
||||
{
|
||||
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
@ -544,6 +546,70 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_pcie_iatu_detect_regions_unroll(struct dw_pcie *pci)
|
||||
{
|
||||
int max_region, i, ob = 0, ib = 0;
|
||||
u32 val;
|
||||
|
||||
max_region = min((int)pci->atu_size / 512, 256);
|
||||
|
||||
for (i = 0; i < max_region; i++) {
|
||||
dw_pcie_writel_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
|
||||
0x11110000);
|
||||
|
||||
val = dw_pcie_readl_ob_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
|
||||
if (val == 0x11110000)
|
||||
ob++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_region; i++) {
|
||||
dw_pcie_writel_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET,
|
||||
0x11110000);
|
||||
|
||||
val = dw_pcie_readl_ib_unroll(pci, i, PCIE_ATU_UNR_LOWER_TARGET);
|
||||
if (val == 0x11110000)
|
||||
ib++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
pci->num_ib_windows = ib;
|
||||
pci->num_ob_windows = ob;
|
||||
}
|
||||
|
||||
static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
|
||||
{
|
||||
int max_region, i, ob = 0, ib = 0;
|
||||
u32 val;
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, 0xFF);
|
||||
max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1;
|
||||
|
||||
for (i = 0; i < max_region; i++) {
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
|
||||
if (val == 0x11110000)
|
||||
ob++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_region; i++) {
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET);
|
||||
if (val == 0x11110000)
|
||||
ib++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
pci->num_ib_windows = ib;
|
||||
pci->num_ob_windows = ob;
|
||||
}
|
||||
|
||||
void dw_pcie_setup(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
@ -554,15 +620,30 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
if (pci->version >= 0x480A || (!pci->version &&
|
||||
dw_pcie_iatu_unroll_enabled(pci))) {
|
||||
pci->iatu_unroll_enabled = true;
|
||||
if (!pci->atu_base)
|
||||
pci->atu_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "atu");
|
||||
if (IS_ERR(pci->atu_base))
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
}
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
|
||||
if (!pci->atu_base) {
|
||||
struct resource *res =
|
||||
platform_get_resource_byname(pdev, IORESOURCE_MEM, "atu");
|
||||
if (res)
|
||||
pci->atu_size = resource_size(res);
|
||||
pci->atu_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pci->atu_base))
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
}
|
||||
|
||||
if (!pci->atu_size)
|
||||
/* Pick a minimal default, enough for 8 in and 8 out windows */
|
||||
pci->atu_size = SZ_4K;
|
||||
|
||||
dw_pcie_iatu_detect_regions_unroll(pci);
|
||||
} else
|
||||
dw_pcie_iatu_detect_regions(pci);
|
||||
|
||||
dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
|
||||
"enabled" : "disabled");
|
||||
|
||||
dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound",
|
||||
pci->num_ob_windows, pci->num_ib_windows);
|
||||
|
||||
if (pci->link_gen > 0)
|
||||
dw_pcie_link_set_max_speed(pci, pci->link_gen);
|
||||
|
||||
|
@ -80,10 +80,8 @@
|
||||
#define PCIE_ATU_VIEWPORT 0x900
|
||||
#define PCIE_ATU_REGION_INBOUND BIT(31)
|
||||
#define PCIE_ATU_REGION_OUTBOUND 0
|
||||
#define PCIE_ATU_REGION_INDEX2 0x2
|
||||
#define PCIE_ATU_REGION_INDEX1 0x1
|
||||
#define PCIE_ATU_REGION_INDEX0 0x0
|
||||
#define PCIE_ATU_CR1 0x904
|
||||
#define PCIE_ATU_INCREASE_REGION_SIZE BIT(13)
|
||||
#define PCIE_ATU_TYPE_MEM 0x0
|
||||
#define PCIE_ATU_TYPE_IO 0x2
|
||||
#define PCIE_ATU_TYPE_CFG0 0x4
|
||||
@ -174,11 +172,11 @@ enum dw_pcie_device_mode {
|
||||
|
||||
struct dw_pcie_host_ops {
|
||||
int (*host_init)(struct pcie_port *pp);
|
||||
void (*set_num_vectors)(struct pcie_port *pp);
|
||||
int (*msi_host_init)(struct pcie_port *pp);
|
||||
};
|
||||
|
||||
struct pcie_port {
|
||||
bool has_msi_ctrl:1;
|
||||
u64 cfg0_base;
|
||||
void __iomem *va_cfg0_base;
|
||||
u32 cfg0_size;
|
||||
@ -239,8 +237,6 @@ struct dw_pcie_ep {
|
||||
phys_addr_t *outbound_addr;
|
||||
unsigned long *ib_window_map;
|
||||
unsigned long *ob_window_map;
|
||||
u32 num_ib_windows;
|
||||
u32 num_ob_windows;
|
||||
void __iomem *msi_mem;
|
||||
phys_addr_t msi_mem_phys;
|
||||
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
|
||||
@ -265,8 +261,9 @@ struct dw_pcie {
|
||||
void __iomem *dbi_base2;
|
||||
/* Used when iatu_unroll_enabled is true */
|
||||
void __iomem *atu_base;
|
||||
u32 num_viewport;
|
||||
u8 iatu_unroll_enabled;
|
||||
size_t atu_size;
|
||||
u32 num_ib_windows;
|
||||
u32 num_ob_windows;
|
||||
struct pcie_port pp;
|
||||
struct dw_pcie_ep ep;
|
||||
const struct dw_pcie_ops *ops;
|
||||
@ -274,6 +271,8 @@ struct dw_pcie {
|
||||
int num_lanes;
|
||||
int link_gen;
|
||||
u8 n_fts[2];
|
||||
bool iatu_unroll_enabled: 1;
|
||||
bool io_cfg_atu_shared: 1;
|
||||
};
|
||||
|
||||
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
|
||||
@ -295,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
u64 size);
|
||||
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
@ -365,8 +364,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
|
||||
|
||||
#ifdef CONFIG_PCIE_DW_HOST
|
||||
irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
|
||||
void dw_pcie_msi_init(struct pcie_port *pp);
|
||||
void dw_pcie_free_msi(struct pcie_port *pp);
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp);
|
||||
int dw_pcie_host_init(struct pcie_port *pp);
|
||||
void dw_pcie_host_deinit(struct pcie_port *pp);
|
||||
@ -379,14 +376,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static inline void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
{
|
||||
}
|
||||
|
@ -100,7 +100,6 @@ static int hisi_pcie_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops hisi_pcie_ops = {
|
||||
.bus_shift = 20,
|
||||
.init = hisi_pcie_init,
|
||||
.pci_ops = {
|
||||
.map_bus = hisi_pcie_map_bus,
|
||||
@ -135,7 +134,6 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
static const struct pci_ecam_ops hisi_pcie_platform_ops = {
|
||||
.bus_shift = 20,
|
||||
.init = hisi_pcie_platform_init,
|
||||
.pci_ops = {
|
||||
.map_bus = hisi_pcie_map_bus,
|
||||
|
@ -169,40 +169,32 @@ static int histb_pcie_link_up(struct dw_pcie *pci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int histb_pcie_establish_link(struct pcie_port *pp)
|
||||
static int histb_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct histb_pcie *hipcie = to_histb_pcie(pci);
|
||||
u32 regval;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_info(pci->dev, "Link already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCIe RC work mode */
|
||||
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
|
||||
regval &= ~PCIE_DEVICE_TYPE_MASK;
|
||||
regval |= PCIE_WM_RC;
|
||||
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
|
||||
|
||||
/* setup root complex */
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
/* assert LTSSM enable */
|
||||
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7);
|
||||
regval |= PCIE_APP_LTSSM_ENABLE;
|
||||
histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int histb_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct histb_pcie *hipcie = to_histb_pcie(pci);
|
||||
u32 regval;
|
||||
|
||||
pp->bridge->ops = &histb_pci_ops;
|
||||
|
||||
histb_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
/* PCIe RC work mode */
|
||||
regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
|
||||
regval &= ~PCIE_DEVICE_TYPE_MASK;
|
||||
regval |= PCIE_WM_RC;
|
||||
histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -300,6 +292,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.read_dbi = histb_pcie_read_dbi,
|
||||
.write_dbi = histb_pcie_write_dbi,
|
||||
.link_up = histb_pcie_link_up,
|
||||
.start_link = histb_pcie_start_link,
|
||||
};
|
||||
|
||||
static int histb_pcie_probe(struct platform_device *pdev)
|
||||
@ -400,12 +393,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(hipcie->bus_reset);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
hipcie->phy = devm_phy_get(dev, "phy");
|
||||
if (IS_ERR(hipcie->phy)) {
|
||||
dev_info(dev, "no pcie-phy found\n");
|
||||
|
@ -58,8 +58,6 @@
|
||||
|
||||
struct intel_pcie_soc {
|
||||
unsigned int pcie_ver;
|
||||
unsigned int pcie_atu_offset;
|
||||
u32 num_viewport;
|
||||
};
|
||||
|
||||
struct intel_pcie_port {
|
||||
@ -153,15 +151,6 @@ static void intel_pcie_init_n_fts(struct dw_pcie *pci)
|
||||
pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
}
|
||||
|
||||
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_ltssm_disable(lpp);
|
||||
intel_pcie_link_setup(lpp);
|
||||
intel_pcie_init_n_fts(&lpp->pci);
|
||||
dw_pcie_setup_rc(&lpp->pci.pp);
|
||||
dw_pcie_upconfig_setup(&lpp->pci);
|
||||
}
|
||||
|
||||
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
|
||||
{
|
||||
struct device *dev = lpp->pci.dev;
|
||||
@ -213,14 +202,6 @@ static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp)
|
||||
gpiod_set_value_cansleep(lpp->reset_gpio, 0);
|
||||
}
|
||||
|
||||
static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_device_rst_deassert(lpp);
|
||||
intel_pcie_ltssm_enable(lpp);
|
||||
|
||||
return dw_pcie_wait_for_link(&lpp->pci);
|
||||
}
|
||||
|
||||
static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp)
|
||||
{
|
||||
pcie_app_wr(lpp, PCIE_APP_IRNEN, 0);
|
||||
@ -234,10 +215,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
||||
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
lpp->core_clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(lpp->core_clk)) {
|
||||
ret = PTR_ERR(lpp->core_clk);
|
||||
@ -274,11 +251,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp)
|
||||
{
|
||||
phy_exit(lpp->phy);
|
||||
}
|
||||
|
||||
static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 value;
|
||||
@ -315,6 +287,7 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
|
||||
static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie *pci = &lpp->pci;
|
||||
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_device_rst_assert(lpp);
|
||||
@ -331,8 +304,18 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
intel_pcie_rc_setup(lpp);
|
||||
ret = intel_pcie_app_logic_setup(lpp);
|
||||
pci->atu_base = pci->dbi_base + 0xC0000;
|
||||
|
||||
intel_pcie_ltssm_disable(lpp);
|
||||
intel_pcie_link_setup(lpp);
|
||||
intel_pcie_init_n_fts(pci);
|
||||
dw_pcie_setup_rc(&pci->pp);
|
||||
dw_pcie_upconfig_setup(pci);
|
||||
|
||||
intel_pcie_device_rst_deassert(lpp);
|
||||
intel_pcie_ltssm_enable(lpp);
|
||||
|
||||
ret = dw_pcie_wait_for_link(pci);
|
||||
if (ret)
|
||||
goto app_init_err;
|
||||
|
||||
@ -346,7 +329,7 @@ app_init_err:
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
clk_err:
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
phy_exit(lpp->phy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -357,7 +340,7 @@ static void __intel_pcie_remove(struct intel_pcie_port *lpp)
|
||||
intel_pcie_turn_off(lpp);
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
phy_exit(lpp->phy);
|
||||
}
|
||||
|
||||
static int intel_pcie_remove(struct platform_device *pdev)
|
||||
@ -381,7 +364,7 @@ static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
phy_exit(lpp->phy);
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
return ret;
|
||||
}
|
||||
@ -401,14 +384,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp)
|
||||
return intel_pcie_host_setup(lpp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy function so that DW core doesn't configure MSI
|
||||
*/
|
||||
static int intel_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
|
||||
{
|
||||
return cpu_addr + BUS_IATU_OFFSET;
|
||||
@ -420,13 +395,10 @@ static const struct dw_pcie_ops intel_pcie_ops = {
|
||||
|
||||
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
|
||||
.host_init = intel_pcie_rc_init,
|
||||
.msi_host_init = intel_pcie_msi_init,
|
||||
};
|
||||
|
||||
static const struct intel_pcie_soc pcie_data = {
|
||||
.pcie_ver = 0x520A,
|
||||
.pcie_atu_offset = 0xC0000,
|
||||
.num_viewport = 3,
|
||||
};
|
||||
|
||||
static int intel_pcie_probe(struct platform_device *pdev)
|
||||
@ -461,7 +433,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pci->ops = &intel_pcie_ops;
|
||||
pci->version = data->pcie_ver;
|
||||
pci->atu_base = pci->dbi_base + data->pcie_atu_offset;
|
||||
pp->ops = &intel_pcie_dw_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
@ -470,12 +441,6 @@ static int intel_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Intel PCIe doesn't configure IO region, so set viewport
|
||||
* to not perform IO region access.
|
||||
*/
|
||||
pci->num_viewport = data->num_viewport;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
|
||||
if (IS_ERR(kirin_pcie->phy_base))
|
||||
return PTR_ERR(kirin_pcie->phy_base);
|
||||
|
||||
kirin_pcie->pci->dbi_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "dbi");
|
||||
if (IS_ERR(kirin_pcie->pci->dbi_base))
|
||||
return PTR_ERR(kirin_pcie->pci->dbi_base);
|
||||
|
||||
kirin_pcie->crgctrl =
|
||||
syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl");
|
||||
if (IS_ERR(kirin_pcie->crgctrl))
|
||||
@ -395,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirin_pcie_establish_link(struct pcie_port *pp)
|
||||
static int kirin_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
|
||||
struct device *dev = kirin_pcie->pci->dev;
|
||||
int count = 0;
|
||||
|
||||
if (kirin_pcie_link_up(pci))
|
||||
return 0;
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
/* assert LTSSM enable */
|
||||
kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT,
|
||||
PCIE_APP_LTSSM_ENABLE);
|
||||
|
||||
/* check if the link is up or not */
|
||||
while (!kirin_pcie_link_up(pci)) {
|
||||
usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
|
||||
count++;
|
||||
if (count == 1000) {
|
||||
dev_err(dev, "Link Fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -428,9 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
pp->bridge->ops = &kirin_pci_ops;
|
||||
|
||||
kirin_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -438,42 +412,13 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
|
||||
.read_dbi = kirin_pcie_read_dbi,
|
||||
.write_dbi = kirin_pcie_write_dbi,
|
||||
.link_up = kirin_pcie_link_up,
|
||||
.start_link = kirin_pcie_start_link,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
|
||||
.host_init = kirin_pcie_host_init,
|
||||
};
|
||||
|
||||
static int kirin_pcie_add_msi(struct dw_pcie *pci,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int irq;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
pci->pp.msi_irq = irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirin_add_pcie_port(struct dw_pcie *pci,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kirin_pcie_add_msi(pci, pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci->pp.ops = &kirin_pcie_host_ops;
|
||||
|
||||
return dw_pcie_host_init(&pci->pp);
|
||||
}
|
||||
|
||||
static int kirin_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -496,6 +441,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = &kirin_dw_pcie_ops;
|
||||
pci->pp.ops = &kirin_pcie_host_ops;
|
||||
kirin_pcie->pci = pci;
|
||||
|
||||
ret = kirin_pcie_get_clk(kirin_pcie, pdev);
|
||||
@ -521,7 +467,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, kirin_pcie);
|
||||
|
||||
return kirin_add_pcie_port(pci, pdev);
|
||||
return dw_pcie_host_init(&pci->pp);
|
||||
}
|
||||
|
||||
static const struct of_device_id kirin_pcie_match[] = {
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/crc8.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -57,6 +58,7 @@
|
||||
#define PCIE20_PARF_SID_OFFSET 0x234
|
||||
#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
|
||||
#define PCIE20_PARF_DEVICE_TYPE 0x1000
|
||||
#define PCIE20_PARF_BDF_TO_SID_TABLE_N 0x2000
|
||||
|
||||
#define PCIE20_ELBI_SYS_CTRL 0x04
|
||||
#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0)
|
||||
@ -97,6 +99,9 @@
|
||||
|
||||
#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
|
||||
#define QCOM_PCIE_2_1_0_MAX_CLOCKS 5
|
||||
|
||||
#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
|
||||
|
||||
struct qcom_pcie_resources_2_1_0 {
|
||||
struct clk_bulk_data clks[QCOM_PCIE_2_1_0_MAX_CLOCKS];
|
||||
struct reset_control *pci_reset;
|
||||
@ -179,6 +184,7 @@ struct qcom_pcie_ops {
|
||||
void (*deinit)(struct qcom_pcie *pcie);
|
||||
void (*post_deinit)(struct qcom_pcie *pcie);
|
||||
void (*ltssm_enable)(struct qcom_pcie *pcie);
|
||||
int (*config_sid)(struct qcom_pcie *pcie);
|
||||
};
|
||||
|
||||
struct qcom_pcie {
|
||||
@ -207,18 +213,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
|
||||
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
|
||||
}
|
||||
|
||||
static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
|
||||
static int qcom_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
|
||||
if (dw_pcie_link_up(pci))
|
||||
return 0;
|
||||
struct qcom_pcie *pcie = to_qcom_pcie(pci);
|
||||
|
||||
/* Enable Link Training state machine */
|
||||
if (pcie->ops->ltssm_enable)
|
||||
pcie->ops->ltssm_enable(pcie);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
|
||||
@ -1261,6 +1264,77 @@ static int qcom_pcie_link_up(struct dw_pcie *pci)
|
||||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
|
||||
static int qcom_pcie_config_sid_sm8250(struct qcom_pcie *pcie)
|
||||
{
|
||||
/* iommu map structure */
|
||||
struct {
|
||||
u32 bdf;
|
||||
u32 phandle;
|
||||
u32 smmu_sid;
|
||||
u32 smmu_sid_len;
|
||||
} *map;
|
||||
void __iomem *bdf_to_sid_base = pcie->parf + PCIE20_PARF_BDF_TO_SID_TABLE_N;
|
||||
struct device *dev = pcie->pci->dev;
|
||||
u8 qcom_pcie_crc8_table[CRC8_TABLE_SIZE];
|
||||
int i, nr_map, size = 0;
|
||||
u32 smmu_sid_base;
|
||||
|
||||
of_get_property(dev->of_node, "iommu-map", &size);
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
map = kzalloc(size, GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
of_property_read_u32_array(dev->of_node,
|
||||
"iommu-map", (u32 *)map, size / sizeof(u32));
|
||||
|
||||
nr_map = size / (sizeof(*map));
|
||||
|
||||
crc8_populate_msb(qcom_pcie_crc8_table, QCOM_PCIE_CRC8_POLYNOMIAL);
|
||||
|
||||
/* Registers need to be zero out first */
|
||||
memset_io(bdf_to_sid_base, 0, CRC8_TABLE_SIZE * sizeof(u32));
|
||||
|
||||
/* Extract the SMMU SID base from the first entry of iommu-map */
|
||||
smmu_sid_base = map[0].smmu_sid;
|
||||
|
||||
/* Look for an available entry to hold the mapping */
|
||||
for (i = 0; i < nr_map; i++) {
|
||||
u16 bdf_be = cpu_to_be16(map[i].bdf);
|
||||
u32 val;
|
||||
u8 hash;
|
||||
|
||||
hash = crc8(qcom_pcie_crc8_table, (u8 *)&bdf_be, sizeof(bdf_be),
|
||||
0);
|
||||
|
||||
val = readl(bdf_to_sid_base + hash * sizeof(u32));
|
||||
|
||||
/* If the register is already populated, look for next available entry */
|
||||
while (val) {
|
||||
u8 current_hash = hash++;
|
||||
u8 next_mask = 0xff;
|
||||
|
||||
/* If NEXT field is NULL then update it with next hash */
|
||||
if (!(val & next_mask)) {
|
||||
val |= (u32)hash;
|
||||
writel(val, bdf_to_sid_base + current_hash * sizeof(u32));
|
||||
}
|
||||
|
||||
val = readl(bdf_to_sid_base + hash * sizeof(u32));
|
||||
}
|
||||
|
||||
/* BDF [31:16] | SID [15:8] | NEXT [7:0] */
|
||||
val = map[i].bdf << 16 | (map[i].smmu_sid - smmu_sid_base) << 8 | 0;
|
||||
writel(val, bdf_to_sid_base + hash * sizeof(u32));
|
||||
}
|
||||
|
||||
kfree(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
@ -1283,16 +1357,16 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
|
||||
goto err_disable_phy;
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
qcom_ep_reset_deassert(pcie);
|
||||
|
||||
ret = qcom_pcie_establish_link(pcie);
|
||||
if (ret)
|
||||
goto err;
|
||||
if (pcie->ops->config_sid) {
|
||||
ret = pcie->ops->config_sid(pcie);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
qcom_ep_reset_assert(pcie);
|
||||
if (pcie->ops->post_deinit)
|
||||
@ -1361,14 +1435,25 @@ static const struct qcom_pcie_ops ops_2_7_0 = {
|
||||
.post_deinit = qcom_pcie_post_deinit_2_7_0,
|
||||
};
|
||||
|
||||
/* Qcom IP rev.: 1.9.0 */
|
||||
static const struct qcom_pcie_ops ops_1_9_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_7_0,
|
||||
.init = qcom_pcie_init_2_7_0,
|
||||
.deinit = qcom_pcie_deinit_2_7_0,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
.post_init = qcom_pcie_post_init_2_7_0,
|
||||
.post_deinit = qcom_pcie_post_deinit_2_7_0,
|
||||
.config_sid = qcom_pcie_config_sid_sm8250,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = qcom_pcie_link_up,
|
||||
.start_link = qcom_pcie_start_link,
|
||||
};
|
||||
|
||||
static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct pcie_port *pp;
|
||||
struct dw_pcie *pci;
|
||||
struct qcom_pcie *pcie;
|
||||
@ -1407,13 +1492,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
goto err_pm_runtime_put;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(pci->dbi_base)) {
|
||||
ret = PTR_ERR(pci->dbi_base);
|
||||
goto err_pm_runtime_put;
|
||||
}
|
||||
|
||||
pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
|
||||
if (IS_ERR(pcie->elbi)) {
|
||||
ret = PTR_ERR(pcie->elbi);
|
||||
@ -1432,14 +1510,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pp->ops = &qcom_pcie_dw_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0) {
|
||||
ret = pp->msi_irq;
|
||||
goto err_pm_runtime_put;
|
||||
}
|
||||
}
|
||||
|
||||
ret = phy_init(pcie->phy);
|
||||
if (ret) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
@ -1474,6 +1544,7 @@ static const struct of_device_id qcom_pcie_match[] = {
|
||||
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
|
||||
{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
|
||||
{ .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 },
|
||||
{ .compatible = "qcom,pcie-sm8250", .data = &ops_1_9_0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -66,32 +66,10 @@ struct pcie_app_reg {
|
||||
|
||||
#define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
static int spear13xx_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct dw_pcie *pci = spear13xx_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
|
||||
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
|
||||
u32 val;
|
||||
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(pci->dev, "link already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
/*
|
||||
* this controller support only 128 bytes read size, however its
|
||||
* default value in capability register is 512 bytes. So force
|
||||
* it to 128 here.
|
||||
*/
|
||||
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
|
||||
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
|
||||
|
||||
/* enable ltssm */
|
||||
writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
|
||||
@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
| ((u32)1 << REG_TRANSLATION_ENABLE),
|
||||
&app_reg->app_ctrl_0);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
|
||||
@ -124,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
|
||||
|
||||
static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = spear13xx_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
|
||||
|
||||
/* Enable MSI interrupt */
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
dw_pcie_msi_init(pp);
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
writel(readl(&app_reg->int_mask) |
|
||||
MSI_CTRL_INT, &app_reg->int_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static int spear13xx_pcie_link_up(struct dw_pcie *pci)
|
||||
@ -151,8 +125,23 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
|
||||
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u32 val;
|
||||
|
||||
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
|
||||
|
||||
/*
|
||||
* this controller support only 128 bytes read size, however its
|
||||
* default value in capability register is 512 bytes. So force
|
||||
* it to 128 here.
|
||||
*/
|
||||
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
|
||||
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
|
||||
|
||||
spear13xx_pcie_establish_link(spear13xx_pcie);
|
||||
spear13xx_pcie_enable_interrupts(spear13xx_pcie);
|
||||
|
||||
return 0;
|
||||
@ -183,6 +172,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
|
||||
}
|
||||
|
||||
pp->ops = &spear13xx_pcie_host_ops;
|
||||
pp->msi_irq = -ENODEV;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
@ -195,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = spear13xx_pcie_link_up,
|
||||
.start_link = spear13xx_pcie_start_link,
|
||||
};
|
||||
|
||||
static int spear13xx_pcie_probe(struct platform_device *pdev)
|
||||
@ -203,7 +194,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
|
||||
struct dw_pcie *pci;
|
||||
struct spear13xx_pcie *spear13xx_pcie;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL);
|
||||
@ -242,14 +232,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
|
||||
if (IS_ERR(pci->dbi_base)) {
|
||||
ret = PTR_ERR(pci->dbi_base);
|
||||
goto fail_clk;
|
||||
}
|
||||
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
|
||||
|
||||
if (of_property_read_bool(np, "st,pcie-is-gen1"))
|
||||
pci->link_gen = 1;
|
||||
|
||||
|
@ -765,8 +765,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
/* Enable MSI interrupt generation */
|
||||
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
|
||||
val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
|
||||
@ -861,6 +859,10 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
if (!pcie->pcie_cap_base)
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
|
||||
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
|
||||
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
|
||||
@ -889,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
|
||||
init_host_aspm(pcie);
|
||||
|
||||
/* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
|
||||
if (!pcie->supports_clkreq) {
|
||||
disable_aspm_l11(pcie);
|
||||
disable_aspm_l12(pcie);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
@ -990,11 +998,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
|
||||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
|
||||
static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
|
||||
{
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
@ -1019,7 +1022,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
|
||||
|
||||
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
|
||||
.host_init = tegra_pcie_dw_host_init,
|
||||
.set_num_vectors = tegra_pcie_set_msi_vec_num,
|
||||
};
|
||||
|
||||
static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
|
||||
@ -1061,9 +1063,16 @@ phy_exit:
|
||||
|
||||
static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(pcie->dev);
|
||||
struct device_node *np = pcie->dev->of_node;
|
||||
int ret;
|
||||
|
||||
pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
if (!pcie->dbi_res) {
|
||||
dev_err(pcie->dev, "Failed to find \"dbi\" region\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", &pcie->aspm_cmrt);
|
||||
if (ret < 0) {
|
||||
dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
|
||||
@ -1390,15 +1399,6 @@ static int tegra_pcie_config_controller(struct tegra_pcie_dw *pcie,
|
||||
|
||||
reset_control_deassert(pcie->core_rst);
|
||||
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
|
||||
/* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
|
||||
if (!pcie->supports_clkreq) {
|
||||
disable_aspm_l11(pcie);
|
||||
disable_aspm_l12(pcie);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail_phy:
|
||||
@ -1415,43 +1415,32 @@ fail_slot_reg_en:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __deinit_controller(struct tegra_pcie_dw *pcie)
|
||||
static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = reset_control_assert(pcie->core_rst);
|
||||
if (ret) {
|
||||
dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret);
|
||||
|
||||
tegra_pcie_disable_phy(pcie);
|
||||
|
||||
ret = reset_control_assert(pcie->core_apb_rst);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(pcie->core_clk);
|
||||
|
||||
ret = regulator_disable(pcie->pex_ctl_supply);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tegra_pcie_disable_slot_regulators(pcie);
|
||||
|
||||
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
|
||||
pcie->cid, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
|
||||
@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
|
||||
return 0;
|
||||
|
||||
fail_host_init:
|
||||
return __deinit_controller(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
|
||||
@ -1516,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
||||
data &= ~APPL_PINMUX_PEX_RST;
|
||||
appl_writel(pcie, data, APPL_PINMUX);
|
||||
|
||||
/*
|
||||
* Some cards do not go to detect state even after de-asserting
|
||||
* PERST#. So, de-assert LTSSM to bring link to detect state.
|
||||
*/
|
||||
data = readl(pcie->appl_base + APPL_CTRL);
|
||||
data &= ~APPL_CTRL_LTSSM_EN;
|
||||
writel(data, pcie->appl_base + APPL_CTRL);
|
||||
|
||||
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
|
||||
data,
|
||||
((data &
|
||||
@ -1523,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
||||
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
|
||||
LTSSM_STATE_PRE_DETECT,
|
||||
1, LTSSM_TIMEOUT);
|
||||
if (err) {
|
||||
if (err)
|
||||
dev_info(pcie->dev, "Link didn't go to detect state\n");
|
||||
} else {
|
||||
/* Disable LTSSM after link is in detect state */
|
||||
data = appl_readl(pcie, APPL_CTRL);
|
||||
data &= ~APPL_CTRL_LTSSM_EN;
|
||||
appl_writel(pcie, data, APPL_CTRL);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* DBI registers may not be accessible after this as PLL-E would be
|
||||
@ -1544,30 +1536,20 @@ static void tegra_pcie_dw_pme_turnoff(struct tegra_pcie_dw *pcie)
|
||||
appl_writel(pcie, data, APPL_PINMUX);
|
||||
}
|
||||
|
||||
static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
|
||||
static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
tegra_pcie_downstream_dev_to_D0(pcie);
|
||||
dw_pcie_host_deinit(&pcie->pci.pp);
|
||||
tegra_pcie_dw_pme_turnoff(pcie);
|
||||
|
||||
return __deinit_controller(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
}
|
||||
|
||||
static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
struct pcie_port *pp = &pcie->pci.pp;
|
||||
struct device *dev = pcie->dev;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
|
||||
if (!pp->msi_irq) {
|
||||
dev_err(dev, "Failed to get MSI interrupt\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
@ -1583,7 +1565,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
|
||||
goto fail_pm_get_sync;
|
||||
}
|
||||
|
||||
tegra_pcie_init_controller(pcie);
|
||||
ret = tegra_pcie_init_controller(pcie);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize controller: %d\n", ret);
|
||||
goto fail_pm_get_sync;
|
||||
}
|
||||
|
||||
pcie->link_state = tegra_pcie_dw_link_up(&pcie->pci);
|
||||
if (!pcie->link_state) {
|
||||
@ -1907,19 +1893,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
|
||||
struct dw_pcie *pci = &pcie->pci;
|
||||
struct device *dev = pcie->dev;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
char *name;
|
||||
int ret;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
ep->page_size = SZ_64K;
|
||||
|
||||
ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
|
||||
@ -1982,7 +1961,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *atu_dma_res;
|
||||
struct tegra_pcie_dw *pcie;
|
||||
struct resource *dbi_res;
|
||||
struct pcie_port *pp;
|
||||
struct dw_pcie *pci;
|
||||
struct phy **phys;
|
||||
@ -2001,8 +1979,10 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
pci->ops = &tegra_dw_pcie_ops;
|
||||
pci->n_fts[0] = N_FTS_VAL;
|
||||
pci->n_fts[1] = FTS_VAL;
|
||||
pci->version = 0x490A;
|
||||
|
||||
pp = &pci->pp;
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->mode = (enum dw_pcie_device_mode)data->mode;
|
||||
|
||||
@ -2091,20 +2071,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
|
||||
pcie->phys = phys;
|
||||
|
||||
dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
if (!dbi_res) {
|
||||
dev_err(dev, "Failed to find \"dbi\" region\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
pcie->dbi_res = dbi_res;
|
||||
|
||||
pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
/* Tegra HW locates DBI2 at a fixed offset from DBI */
|
||||
pci->dbi_base2 = pci->dbi_base + 0x1000;
|
||||
|
||||
atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"atu_dma");
|
||||
if (!atu_dma_res) {
|
||||
@ -2113,6 +2079,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
}
|
||||
pcie->atu_dma_res = atu_dma_res;
|
||||
|
||||
pci->atu_size = resource_size(atu_dma_res);
|
||||
pci->atu_base = devm_ioremap_resource(dev, atu_dma_res);
|
||||
if (IS_ERR(pci->atu_base))
|
||||
return PTR_ERR(pci->atu_base);
|
||||
@ -2225,8 +2192,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
|
||||
PORT_LOGIC_MSI_CTRL_INT_0_EN);
|
||||
tegra_pcie_downstream_dev_to_D0(pcie);
|
||||
tegra_pcie_dw_pme_turnoff(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
|
||||
return __deinit_controller(pcie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_resume_noirq(struct device *dev)
|
||||
@ -2254,7 +2222,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
|
||||
return 0;
|
||||
|
||||
fail_host_init:
|
||||
return __deinit_controller(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_resume_early(struct device *dev)
|
||||
@ -2292,7 +2261,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device *pdev)
|
||||
disable_irq(pcie->pci.pp.msi_irq);
|
||||
|
||||
tegra_pcie_dw_pme_turnoff(pcie);
|
||||
__deinit_controller(pcie);
|
||||
tegra_pcie_unconfig_controller(pcie);
|
||||
}
|
||||
|
||||
static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
|
||||
|
@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
|
||||
.get_features = uniphier_pcie_get_features,
|
||||
};
|
||||
|
||||
static int uniphier_add_pcie_ep(struct uniphier_pcie_ep_priv *priv,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = &priv->pci;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
ep->ops = &uniphier_pcie_ep_ops;
|
||||
|
||||
pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
|
||||
if (IS_ERR(pci->dbi_base2))
|
||||
return PTR_ERR(pci->dbi_base2);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to initialize endpoint (%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uniphier_pcie_ep_priv *priv;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
|
||||
priv->pci.dev = dev;
|
||||
priv->pci.ops = &dw_pcie_ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(priv->pci.dbi_base))
|
||||
return PTR_ERR(priv->pci.dbi_base);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return uniphier_add_pcie_ep(priv, pdev);
|
||||
priv->pci.ep.ops = &uniphier_pcie_ep_ops;
|
||||
return dw_pcie_ep_init(&priv->pci.ep);
|
||||
}
|
||||
|
||||
static const struct pci_epc_features uniphier_pro5_data = {
|
||||
|
@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci)
|
||||
return (val & mask) == mask;
|
||||
}
|
||||
|
||||
static int uniphier_pcie_establish_link(struct dw_pcie *pci)
|
||||
static int uniphier_pcie_start_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
|
||||
|
||||
if (dw_pcie_link_up(pci))
|
||||
return 0;
|
||||
|
||||
uniphier_pcie_ltssm_enable(priv, true);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uniphier_pcie_stop_link(struct dw_pcie *pci)
|
||||
@ -317,13 +314,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
|
||||
|
||||
uniphier_pcie_irq_enable(priv);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
ret = uniphier_pcie_establish_link(pci);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -331,31 +321,6 @@ static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
|
||||
.host_init = uniphier_pcie_host_init,
|
||||
};
|
||||
|
||||
static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = &priv->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
pp->ops = &uniphier_pcie_host_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq_byname(pdev, "msi");
|
||||
if (pp->msi_irq < 0)
|
||||
return pp->msi_irq;
|
||||
}
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to initialize host (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
@ -391,7 +356,7 @@ out_clk_disable:
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = uniphier_pcie_establish_link,
|
||||
.start_link = uniphier_pcie_start_link,
|
||||
.stop_link = uniphier_pcie_stop_link,
|
||||
.link_up = uniphier_pcie_link_up,
|
||||
};
|
||||
@ -400,7 +365,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct uniphier_pcie_priv *priv;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@ -410,11 +374,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
|
||||
priv->pci.dev = dev;
|
||||
priv->pci.ops = &dw_pcie_ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(priv->pci.dbi_base))
|
||||
return PTR_ERR(priv->pci.dbi_base);
|
||||
|
||||
priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
@ -437,7 +396,9 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return uniphier_add_pcie_port(priv, pdev);
|
||||
priv->pci.pp.ops = &uniphier_pcie_host_ops;
|
||||
|
||||
return dw_pcie_host_init(&priv->pci.pp);
|
||||
}
|
||||
|
||||
static const struct of_device_id uniphier_pcie_match[] = {
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -164,14 +165,6 @@
|
||||
#define PCIE_CONFIG_WR_TYPE0 0xa
|
||||
#define PCIE_CONFIG_WR_TYPE1 0xb
|
||||
|
||||
#define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20)
|
||||
#define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15)
|
||||
#define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12)
|
||||
#define PCIE_CONF_REG(reg) ((reg) & 0xffc)
|
||||
#define PCIE_CONF_ADDR(bus, devfn, where) \
|
||||
(PCIE_CONF_BUS(bus) | PCIE_CONF_DEV(PCI_SLOT(devfn)) | \
|
||||
PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where))
|
||||
|
||||
#define PIO_RETRY_CNT 500
|
||||
#define PIO_RETRY_DELAY 2 /* 2 us*/
|
||||
|
||||
@ -259,7 +252,14 @@ static void advk_pcie_issue_perst(struct advk_pcie *pcie)
|
||||
if (!pcie->reset_gpio)
|
||||
return;
|
||||
|
||||
/* PERST does not work for some cards when link training is enabled */
|
||||
/*
|
||||
* As required by PCI Express spec (PCI Express Base Specification, REV.
|
||||
* 4.0 PCI Express, February 19 2014, 6.6.1 Conventional Reset) a delay
|
||||
* for at least 100ms after de-asserting PERST# signal is needed before
|
||||
* link training is enabled. So ensure that link training is disabled
|
||||
* prior de-asserting PERST# signal to fulfill that PCI Express spec
|
||||
* requirement.
|
||||
*/
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
|
||||
reg &= ~LINK_TRAINING_EN;
|
||||
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
|
||||
@ -687,7 +687,7 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
||||
advk_writel(pcie, reg, PIO_CTRL);
|
||||
|
||||
/* Program the address registers */
|
||||
reg = PCIE_CONF_ADDR(bus->number, devfn, where);
|
||||
reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
|
||||
advk_writel(pcie, reg, PIO_ADDR_LS);
|
||||
advk_writel(pcie, 0, PIO_ADDR_MS);
|
||||
|
||||
@ -748,7 +748,7 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||
advk_writel(pcie, reg, PIO_CTRL);
|
||||
|
||||
/* Program the address registers */
|
||||
reg = PCIE_CONF_ADDR(bus->number, devfn, where);
|
||||
reg = ALIGN_DOWN(PCIE_ECAM_OFFSET(bus->number, devfn, where), 4);
|
||||
advk_writel(pcie, reg, PIO_ADDR_LS);
|
||||
advk_writel(pcie, 0, PIO_ADDR_MS);
|
||||
|
||||
|
@ -49,7 +49,6 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
|
||||
}
|
||||
|
||||
static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_dw_ecam_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
|
@ -346,7 +346,6 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops pci_thunder_ecam_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = thunder_ecam_config_read,
|
||||
|
@ -19,6 +19,15 @@
|
||||
#define PEM_CFG_WR 0x28
|
||||
#define PEM_CFG_RD 0x30
|
||||
|
||||
/*
|
||||
* Enhanced Configuration Access Mechanism (ECAM)
|
||||
*
|
||||
* N.B. This is a non-standard platform-specific ECAM bus shift value. For
|
||||
* standard values defined in the PCI Express Base Specification see
|
||||
* include/linux/pci-ecam.h.
|
||||
*/
|
||||
#define THUNDER_PCIE_ECAM_BUS_SHIFT 24
|
||||
|
||||
struct thunder_pem_pci {
|
||||
u32 ea_entry[3];
|
||||
void __iomem *pem_reg_base;
|
||||
@ -404,7 +413,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops thunder_pem_ecam_ops = {
|
||||
.bus_shift = 24,
|
||||
.bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
|
||||
.init = thunder_pem_acpi_init,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
@ -441,7 +450,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
static const struct pci_ecam_ops pci_thunder_pem_ops = {
|
||||
.bus_shift = 24,
|
||||
.bus_shift = THUNDER_PCIE_ECAM_BUS_SHIFT,
|
||||
.init = thunder_pem_platform_init,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
|
@ -257,7 +257,6 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v1_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
@ -272,7 +271,6 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
|
||||
}
|
||||
|
||||
const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
|
||||
.bus_shift = 16,
|
||||
.init = xgene_v2_pcie_ecam_init,
|
||||
.pci_ops = {
|
||||
.map_bus = xgene_pcie_map_bus,
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sizes.h>
|
||||
@ -127,11 +128,7 @@
|
||||
#define MSI_INT_MASK_CLR 0x14
|
||||
|
||||
#define PCIE_EXT_CFG_DATA 0x8000
|
||||
|
||||
#define PCIE_EXT_CFG_INDEX 0x9000
|
||||
#define PCIE_EXT_BUSNUM_SHIFT 20
|
||||
#define PCIE_EXT_SLOT_SHIFT 15
|
||||
#define PCIE_EXT_FUNC_SHIFT 12
|
||||
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1
|
||||
#define PCIE_RGR1_SW_INIT_1_PERST_SHIFT 0x0
|
||||
@ -695,15 +692,6 @@ static bool brcm_pcie_link_up(struct brcm_pcie *pcie)
|
||||
return dla && plu;
|
||||
}
|
||||
|
||||
/* Configuration space read/write support */
|
||||
static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg)
|
||||
{
|
||||
return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT)
|
||||
| ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT)
|
||||
| (busnr << PCIE_EXT_BUSNUM_SHIFT)
|
||||
| (reg & ~3);
|
||||
}
|
||||
|
||||
static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
@ -716,7 +704,7 @@ static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
return PCI_SLOT(devfn) ? NULL : base + where;
|
||||
|
||||
/* For devices, write to the config space index register */
|
||||
idx = brcm_pcie_cfg_index(bus->number, devfn, 0);
|
||||
idx = PCIE_ECAM_OFFSET(bus->number, devfn, 0);
|
||||
writel(idx, pcie->base + PCIE_EXT_CFG_INDEX);
|
||||
return base + PCIE_EXT_CFG_DATA + where;
|
||||
}
|
||||
@ -893,6 +881,7 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
|
||||
burst = 0x2; /* 512 bytes */
|
||||
|
||||
/* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */
|
||||
tmp = readl(base + PCIE_MISC_MISC_CTRL);
|
||||
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK);
|
||||
u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK);
|
||||
u32p_replace_bits(&tmp, burst, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
@ -39,16 +40,8 @@
|
||||
|
||||
#define CFG_IND_ADDR_MASK 0x00001ffc
|
||||
|
||||
#define CFG_ADDR_BUS_NUM_SHIFT 20
|
||||
#define CFG_ADDR_BUS_NUM_MASK 0x0ff00000
|
||||
#define CFG_ADDR_DEV_NUM_SHIFT 15
|
||||
#define CFG_ADDR_DEV_NUM_MASK 0x000f8000
|
||||
#define CFG_ADDR_FUNC_NUM_SHIFT 12
|
||||
#define CFG_ADDR_FUNC_NUM_MASK 0x00007000
|
||||
#define CFG_ADDR_REG_NUM_SHIFT 2
|
||||
#define CFG_ADDR_REG_NUM_MASK 0x00000ffc
|
||||
#define CFG_ADDR_CFG_TYPE_SHIFT 0
|
||||
#define CFG_ADDR_CFG_TYPE_MASK 0x00000003
|
||||
#define CFG_ADDR_CFG_TYPE_1 1
|
||||
|
||||
#define SYS_RC_INTX_MASK 0xf
|
||||
|
||||
@ -192,8 +185,15 @@ static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = {
|
||||
.imap_window_offset = 0x4,
|
||||
},
|
||||
{
|
||||
/* IARR1/IMAP1 (currently unused) */
|
||||
.type = IPROC_PCIE_IB_MAP_INVALID,
|
||||
/* IARR1/IMAP1 */
|
||||
.type = IPROC_PCIE_IB_MAP_MEM,
|
||||
.size_unit = SZ_1M,
|
||||
.region_sizes = { 8 },
|
||||
.nr_sizes = 1,
|
||||
.nr_windows = 8,
|
||||
.imap_addr_offset = 0x4,
|
||||
.imap_window_offset = 0x8,
|
||||
|
||||
},
|
||||
{
|
||||
/* IARR2/IMAP2 */
|
||||
@ -307,7 +307,7 @@ enum iproc_pcie_reg {
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXB BCMA registers */
|
||||
static const u16 iproc_pcie_reg_paxb_bcma[] = {
|
||||
static const u16 iproc_pcie_reg_paxb_bcma[IPROC_PCIE_MAX_NUM_REG] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
@ -318,7 +318,7 @@ static const u16 iproc_pcie_reg_paxb_bcma[] = {
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXB registers */
|
||||
static const u16 iproc_pcie_reg_paxb[] = {
|
||||
static const u16 iproc_pcie_reg_paxb[IPROC_PCIE_MAX_NUM_REG] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
@ -334,7 +334,7 @@ static const u16 iproc_pcie_reg_paxb[] = {
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXB v2 registers */
|
||||
static const u16 iproc_pcie_reg_paxb_v2[] = {
|
||||
static const u16 iproc_pcie_reg_paxb_v2[IPROC_PCIE_MAX_NUM_REG] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x120,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x124,
|
||||
@ -351,6 +351,8 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
|
||||
[IPROC_PCIE_OMAP3] = 0xdf8,
|
||||
[IPROC_PCIE_IARR0] = 0xd00,
|
||||
[IPROC_PCIE_IMAP0] = 0xc00,
|
||||
[IPROC_PCIE_IARR1] = 0xd08,
|
||||
[IPROC_PCIE_IMAP1] = 0xd70,
|
||||
[IPROC_PCIE_IARR2] = 0xd10,
|
||||
[IPROC_PCIE_IMAP2] = 0xcc0,
|
||||
[IPROC_PCIE_IARR3] = 0xe00,
|
||||
@ -363,7 +365,7 @@ static const u16 iproc_pcie_reg_paxb_v2[] = {
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXC v1 registers */
|
||||
static const u16 iproc_pcie_reg_paxc[] = {
|
||||
static const u16 iproc_pcie_reg_paxc[IPROC_PCIE_MAX_NUM_REG] = {
|
||||
[IPROC_PCIE_CLK_CTRL] = 0x000,
|
||||
[IPROC_PCIE_CFG_IND_ADDR] = 0x1f0,
|
||||
[IPROC_PCIE_CFG_IND_DATA] = 0x1f4,
|
||||
@ -372,7 +374,7 @@ static const u16 iproc_pcie_reg_paxc[] = {
|
||||
};
|
||||
|
||||
/* iProc PCIe PAXC v2 registers */
|
||||
static const u16 iproc_pcie_reg_paxc_v2[] = {
|
||||
static const u16 iproc_pcie_reg_paxc_v2[IPROC_PCIE_MAX_NUM_REG] = {
|
||||
[IPROC_PCIE_MSI_GIC_MODE] = 0x050,
|
||||
[IPROC_PCIE_MSI_BASE_ADDR] = 0x074,
|
||||
[IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078,
|
||||
@ -459,19 +461,15 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus,
|
||||
|
||||
static void __iomem *iproc_pcie_map_ep_cfg_reg(struct iproc_pcie *pcie,
|
||||
unsigned int busno,
|
||||
unsigned int slot,
|
||||
unsigned int fn,
|
||||
unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
u16 offset;
|
||||
u32 val;
|
||||
|
||||
/* EP device access */
|
||||
val = (busno << CFG_ADDR_BUS_NUM_SHIFT) |
|
||||
(slot << CFG_ADDR_DEV_NUM_SHIFT) |
|
||||
(fn << CFG_ADDR_FUNC_NUM_SHIFT) |
|
||||
(where & CFG_ADDR_REG_NUM_MASK) |
|
||||
(1 & CFG_ADDR_CFG_TYPE_MASK);
|
||||
val = ALIGN_DOWN(PCIE_ECAM_OFFSET(busno, devfn, where), 4) |
|
||||
CFG_ADDR_CFG_TYPE_1;
|
||||
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_ADDR, val);
|
||||
offset = iproc_pcie_reg_offset(pcie, IPROC_PCIE_CFG_DATA);
|
||||
@ -574,8 +572,6 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct iproc_pcie *pcie = iproc_data(bus);
|
||||
unsigned int slot = PCI_SLOT(devfn);
|
||||
unsigned int fn = PCI_FUNC(devfn);
|
||||
unsigned int busno = bus->number;
|
||||
void __iomem *cfg_data_p;
|
||||
unsigned int data;
|
||||
@ -590,7 +586,7 @@ static int iproc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
return ret;
|
||||
}
|
||||
|
||||
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
|
||||
cfg_data_p = iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
|
||||
|
||||
if (!cfg_data_p)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
@ -631,13 +627,11 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
|
||||
int busno, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
unsigned slot = PCI_SLOT(devfn);
|
||||
unsigned fn = PCI_FUNC(devfn);
|
||||
u16 offset;
|
||||
|
||||
/* root complex access */
|
||||
if (busno == 0) {
|
||||
if (slot > 0 || fn > 0)
|
||||
if (PCIE_ECAM_DEVFN(devfn) > 0)
|
||||
return NULL;
|
||||
|
||||
iproc_pcie_write_reg(pcie, IPROC_PCIE_CFG_IND_ADDR,
|
||||
@ -649,7 +643,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie,
|
||||
return (pcie->base + offset);
|
||||
}
|
||||
|
||||
return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where);
|
||||
return iproc_pcie_map_ep_cfg_reg(pcie, busno, devfn, where);
|
||||
}
|
||||
|
||||
static void __iomem *iproc_pcie_bus_map_cfg_bus(struct pci_bus *bus,
|
||||
@ -1470,6 +1464,7 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
||||
{
|
||||
struct device *dev;
|
||||
int ret;
|
||||
struct pci_dev *pdev;
|
||||
struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);
|
||||
|
||||
dev = pcie->dev;
|
||||
@ -1533,6 +1528,11 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
||||
goto err_power_off_phy;
|
||||
}
|
||||
|
||||
for_each_pci_bridge(pdev, host->bus) {
|
||||
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
pcie_print_link_status(pdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_off_phy:
|
||||
|
@ -50,9 +50,7 @@ static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
|
||||
/* Structure representing the PCIe interface */
|
||||
struct rcar_pcie_host {
|
||||
struct rcar_pcie pcie;
|
||||
struct device *dev;
|
||||
struct phy *phy;
|
||||
void __iomem *base;
|
||||
struct clk *bus_clk;
|
||||
struct rcar_msi msi;
|
||||
int (*phy_init_fn)(struct rcar_pcie_host *host);
|
||||
|
@ -157,12 +157,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
|
||||
struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
u32 busdev;
|
||||
void __iomem *addr;
|
||||
|
||||
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
|
||||
PCI_FUNC(devfn), where);
|
||||
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
|
||||
|
||||
if (!IS_ALIGNED(busdev, size)) {
|
||||
if (!IS_ALIGNED((uintptr_t)addr, size)) {
|
||||
*val = 0;
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
}
|
||||
@ -175,11 +174,11 @@ static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
|
||||
AXI_WRAPPER_TYPE1_CFG);
|
||||
|
||||
if (size == 4) {
|
||||
*val = readl(rockchip->reg_base + busdev);
|
||||
*val = readl(addr);
|
||||
} else if (size == 2) {
|
||||
*val = readw(rockchip->reg_base + busdev);
|
||||
*val = readw(addr);
|
||||
} else if (size == 1) {
|
||||
*val = readb(rockchip->reg_base + busdev);
|
||||
*val = readb(addr);
|
||||
} else {
|
||||
*val = 0;
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
@ -191,11 +190,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
|
||||
struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
u32 busdev;
|
||||
void __iomem *addr;
|
||||
|
||||
busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
|
||||
PCI_FUNC(devfn), where);
|
||||
if (!IS_ALIGNED(busdev, size))
|
||||
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
|
||||
|
||||
if (!IS_ALIGNED((uintptr_t)addr, size))
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
@ -206,11 +205,11 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
|
||||
AXI_WRAPPER_TYPE1_CFG);
|
||||
|
||||
if (size == 4)
|
||||
writel(val, rockchip->reg_base + busdev);
|
||||
writel(val, addr);
|
||||
else if (size == 2)
|
||||
writew(val, rockchip->reg_base + busdev);
|
||||
writew(val, addr);
|
||||
else if (size == 1)
|
||||
writeb(val, rockchip->reg_base + busdev);
|
||||
writeb(val, addr);
|
||||
else
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
|
||||
/*
|
||||
* The upper 16 bits of PCIE_CLIENT_CONFIG are a write mask for the lower 16
|
||||
@ -178,13 +179,6 @@
|
||||
#define MIN_AXI_ADDR_BITS_PASSED 8
|
||||
#define PCIE_RC_SEND_PME_OFF 0x11960
|
||||
#define ROCKCHIP_VENDOR_ID 0x1d87
|
||||
#define PCIE_ECAM_BUS(x) (((x) & 0xff) << 20)
|
||||
#define PCIE_ECAM_DEV(x) (((x) & 0x1f) << 15)
|
||||
#define PCIE_ECAM_FUNC(x) (((x) & 0x7) << 12)
|
||||
#define PCIE_ECAM_REG(x) (((x) & 0xfff) << 0)
|
||||
#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
|
||||
(PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
|
||||
PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
|
||||
#define PCIE_LINK_IS_L2(x) \
|
||||
(((x) & PCIE_CLIENT_DEBUG_LTSSM_MASK) == PCIE_CLIENT_DEBUG_LTSSM_L2)
|
||||
#define PCIE_LINK_UP(x) \
|
||||
|
@ -208,7 +208,6 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
}
|
||||
|
||||
static const struct pci_ecam_ops smp8759_ecam_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = smp8759_config_read,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
|
||||
@ -124,8 +125,6 @@
|
||||
#define E_ECAM_CR_ENABLE BIT(0)
|
||||
#define E_ECAM_SIZE_LOC GENMASK(20, 16)
|
||||
#define E_ECAM_SIZE_SHIFT 16
|
||||
#define ECAM_BUS_LOC_SHIFT 20
|
||||
#define ECAM_DEV_LOC_SHIFT 12
|
||||
#define NWL_ECAM_VALUE_DEFAULT 12
|
||||
|
||||
#define CFG_DMA_REG_BAR GENMASK(2, 0)
|
||||
@ -240,15 +239,11 @@ static void __iomem *nwl_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct nwl_pcie *pcie = bus->sysdata;
|
||||
int relbus;
|
||||
|
||||
if (!nwl_pcie_valid_device(bus, devfn))
|
||||
return NULL;
|
||||
|
||||
relbus = (bus->number << ECAM_BUS_LOC_SHIFT) |
|
||||
(devfn << ECAM_DEV_LOC_SHIFT);
|
||||
|
||||
return pcie->ecam_base + relbus + where;
|
||||
return pcie->ecam_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
|
||||
}
|
||||
|
||||
/* PCIe operations */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "../pci.h"
|
||||
@ -86,10 +87,6 @@
|
||||
/* Phy Status/Control Register definitions */
|
||||
#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11)
|
||||
|
||||
/* ECAM definitions */
|
||||
#define ECAM_BUS_NUM_SHIFT 20
|
||||
#define ECAM_DEV_NUM_SHIFT 12
|
||||
|
||||
/* Number of MSI IRQs */
|
||||
#define XILINX_NUM_MSI_IRQS 128
|
||||
|
||||
@ -183,15 +180,11 @@ static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct xilinx_pcie_port *port = bus->sysdata;
|
||||
int relbus;
|
||||
|
||||
if (!xilinx_pcie_valid_device(bus, devfn))
|
||||
return NULL;
|
||||
|
||||
relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
|
||||
(devfn << ECAM_DEV_NUM_SHIFT);
|
||||
|
||||
return port->reg_base + relbus + where;
|
||||
return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
|
||||
}
|
||||
|
||||
/* PCIe operations */
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
@ -52,6 +53,12 @@ enum vmd_features {
|
||||
* vendor-specific capability space
|
||||
*/
|
||||
VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP = (1 << 2),
|
||||
|
||||
/*
|
||||
* Device may use MSI-X vector 0 for software triggering and will not
|
||||
* be used for MSI remapping
|
||||
*/
|
||||
VMD_FEAT_OFFSET_FIRST_VECTOR = (1 << 3),
|
||||
};
|
||||
|
||||
/*
|
||||
@ -93,7 +100,7 @@ struct vmd_dev {
|
||||
struct pci_dev *dev;
|
||||
|
||||
spinlock_t cfg_lock;
|
||||
char __iomem *cfgbar;
|
||||
void __iomem *cfgbar;
|
||||
|
||||
int msix_count;
|
||||
struct vmd_irq_list *irqs;
|
||||
@ -103,6 +110,7 @@ struct vmd_dev {
|
||||
struct irq_domain *irq_domain;
|
||||
struct pci_bus *bus;
|
||||
u8 busn_start;
|
||||
u8 first_vec;
|
||||
};
|
||||
|
||||
static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
|
||||
@ -198,11 +206,11 @@ static irq_hw_number_t vmd_get_hwirq(struct msi_domain_info *info,
|
||||
*/
|
||||
static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *desc)
|
||||
{
|
||||
int i, best = 1;
|
||||
unsigned long flags;
|
||||
int i, best;
|
||||
|
||||
if (vmd->msix_count == 1)
|
||||
return &vmd->irqs[0];
|
||||
if (vmd->msix_count == 1 + vmd->first_vec)
|
||||
return &vmd->irqs[vmd->first_vec];
|
||||
|
||||
/*
|
||||
* White list for fast-interrupt handlers. All others will share the
|
||||
@ -212,11 +220,12 @@ static struct vmd_irq_list *vmd_next_irq(struct vmd_dev *vmd, struct msi_desc *d
|
||||
case PCI_CLASS_STORAGE_EXPRESS:
|
||||
break;
|
||||
default:
|
||||
return &vmd->irqs[0];
|
||||
return &vmd->irqs[vmd->first_vec];
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&list_lock, flags);
|
||||
for (i = 1; i < vmd->msix_count; i++)
|
||||
best = vmd->first_vec + 1;
|
||||
for (i = best; i < vmd->msix_count; i++)
|
||||
if (vmd->irqs[i].count < vmd->irqs[best].count)
|
||||
best = i;
|
||||
vmd->irqs[best].count++;
|
||||
@ -324,18 +333,16 @@ static void vmd_remove_irq_domain(struct vmd_dev *vmd)
|
||||
}
|
||||
}
|
||||
|
||||
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
|
||||
static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
|
||||
unsigned int devfn, int reg, int len)
|
||||
{
|
||||
char __iomem *addr = vmd->cfgbar +
|
||||
((bus->number - vmd->busn_start) << 20) +
|
||||
(devfn << 12) + reg;
|
||||
unsigned int busnr_ecam = bus->number - vmd->busn_start;
|
||||
u32 offset = PCIE_ECAM_OFFSET(busnr_ecam, devfn, reg);
|
||||
|
||||
if ((addr - vmd->cfgbar) + len >=
|
||||
resource_size(&vmd->dev->resource[VMD_CFGBAR]))
|
||||
if (offset + len >= resource_size(&vmd->dev->resource[VMD_CFGBAR]))
|
||||
return NULL;
|
||||
|
||||
return addr;
|
||||
return vmd->cfgbar + offset;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -346,7 +353,7 @@ static int vmd_pci_read(struct pci_bus *bus, unsigned int devfn, int reg,
|
||||
int len, u32 *value)
|
||||
{
|
||||
struct vmd_dev *vmd = vmd_from_bus(bus);
|
||||
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
@ -381,7 +388,7 @@ static int vmd_pci_write(struct pci_bus *bus, unsigned int devfn, int reg,
|
||||
int len, u32 value)
|
||||
{
|
||||
struct vmd_dev *vmd = vmd_from_bus(bus);
|
||||
char __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
void __iomem *addr = vmd_cfg_addr(vmd, bus, devfn, reg, len);
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
@ -549,8 +556,8 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
|
||||
if (vmd->msix_count < 0)
|
||||
return -ENODEV;
|
||||
|
||||
vmd->msix_count = pci_alloc_irq_vectors(dev, 1, vmd->msix_count,
|
||||
PCI_IRQ_MSIX);
|
||||
vmd->msix_count = pci_alloc_irq_vectors(dev, vmd->first_vec + 1,
|
||||
vmd->msix_count, PCI_IRQ_MSIX);
|
||||
if (vmd->msix_count < 0)
|
||||
return vmd->msix_count;
|
||||
|
||||
@ -718,6 +725,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
||||
|
||||
static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long features = (unsigned long) id->driver_data;
|
||||
struct vmd_dev *vmd;
|
||||
int err;
|
||||
|
||||
@ -742,13 +750,16 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)))
|
||||
return -ENODEV;
|
||||
|
||||
if (features & VMD_FEAT_OFFSET_FIRST_VECTOR)
|
||||
vmd->first_vec = 1;
|
||||
|
||||
err = vmd_alloc_irqs(vmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
spin_lock_init(&vmd->cfg_lock);
|
||||
pci_set_drvdata(dev, vmd);
|
||||
err = vmd_enable_domain(vmd, (unsigned long) id->driver_data);
|
||||
err = vmd_enable_domain(vmd, features);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -817,13 +828,16 @@ static const struct pci_device_id vmd_ids[] = {
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
|
||||
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS |
|
||||
VMD_FEAT_OFFSET_FIRST_VECTOR,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
|
||||
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS |
|
||||
VMD_FEAT_OFFSET_FIRST_VECTOR,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
|
||||
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW_VSCAP |
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS |
|
||||
VMD_FEAT_OFFSET_FIRST_VECTOR,},
|
||||
{0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, vmd_ids);
|
||||
|
@ -28,6 +28,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
|
||||
struct resource *cfgres, struct resource *busr,
|
||||
const struct pci_ecam_ops *ops)
|
||||
{
|
||||
unsigned int bus_shift = ops->bus_shift;
|
||||
struct pci_config_window *cfg;
|
||||
unsigned int bus_range, bus_range_max, bsz;
|
||||
struct resource *conflict;
|
||||
@ -40,20 +41,24 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
|
||||
if (!cfg)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* ECAM-compliant platforms need not supply ops->bus_shift */
|
||||
if (!bus_shift)
|
||||
bus_shift = PCIE_ECAM_BUS_SHIFT;
|
||||
|
||||
cfg->parent = dev;
|
||||
cfg->ops = ops;
|
||||
cfg->busr.start = busr->start;
|
||||
cfg->busr.end = busr->end;
|
||||
cfg->busr.flags = IORESOURCE_BUS;
|
||||
bus_range = resource_size(&cfg->busr);
|
||||
bus_range_max = resource_size(cfgres) >> ops->bus_shift;
|
||||
bus_range_max = resource_size(cfgres) >> bus_shift;
|
||||
if (bus_range > bus_range_max) {
|
||||
bus_range = bus_range_max;
|
||||
cfg->busr.end = busr->start + bus_range - 1;
|
||||
dev_warn(dev, "ECAM area %pR can only accommodate %pR (reduced from %pR desired)\n",
|
||||
cfgres, &cfg->busr, busr);
|
||||
}
|
||||
bsz = 1 << ops->bus_shift;
|
||||
bsz = 1 << bus_shift;
|
||||
|
||||
cfg->res.start = cfgres->start;
|
||||
cfg->res.end = cfgres->end;
|
||||
@ -131,25 +136,36 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct pci_config_window *cfg = bus->sysdata;
|
||||
unsigned int bus_shift = cfg->ops->bus_shift;
|
||||
unsigned int devfn_shift = cfg->ops->bus_shift - 8;
|
||||
unsigned int busn = bus->number;
|
||||
void __iomem *base;
|
||||
u32 bus_offset, devfn_offset;
|
||||
|
||||
if (busn < cfg->busr.start || busn > cfg->busr.end)
|
||||
return NULL;
|
||||
|
||||
busn -= cfg->busr.start;
|
||||
if (per_bus_mapping)
|
||||
if (per_bus_mapping) {
|
||||
base = cfg->winp[busn];
|
||||
else
|
||||
base = cfg->win + (busn << cfg->ops->bus_shift);
|
||||
return base + (devfn << devfn_shift) + where;
|
||||
busn = 0;
|
||||
} else
|
||||
base = cfg->win;
|
||||
|
||||
if (cfg->ops->bus_shift) {
|
||||
bus_offset = (busn & PCIE_ECAM_BUS_MASK) << bus_shift;
|
||||
devfn_offset = (devfn & PCIE_ECAM_DEVFN_MASK) << devfn_shift;
|
||||
where &= PCIE_ECAM_REG_MASK;
|
||||
|
||||
return base + (bus_offset | devfn_offset | where);
|
||||
}
|
||||
|
||||
return base + PCIE_ECAM_OFFSET(busn, devfn, where);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
|
||||
|
||||
/* ECAM ops */
|
||||
const struct pci_ecam_ops pci_generic_ecam_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
@ -161,7 +177,6 @@ EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
|
||||
/* ECAM ops for 32-bit access only (non-compliant) */
|
||||
const struct pci_ecam_ops pci_32b_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = pci_generic_config_read32,
|
||||
@ -171,7 +186,6 @@ const struct pci_ecam_ops pci_32b_ops = {
|
||||
|
||||
/* ECAM ops for 32-bit read only (non-compliant) */
|
||||
const struct pci_ecam_ops pci_32b_read_ops = {
|
||||
.bus_shift = 20,
|
||||
.pci_ops = {
|
||||
.map_bus = pci_ecam_map_bus,
|
||||
.read = pci_generic_config_read32,
|
||||
|
@ -294,7 +294,6 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
|
||||
default:
|
||||
err("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
|
||||
return -ENXIO;
|
||||
break;
|
||||
} /* end of switch */
|
||||
} /* end of valid device */
|
||||
} /* end of for */
|
||||
@ -1509,7 +1508,6 @@ static int unconfigure_boot_card(struct slot *slot_cur)
|
||||
default:
|
||||
err("MAJOR PROBLEM!!!! Cannot read device's header\n");
|
||||
return -1;
|
||||
break;
|
||||
} /* end of switch */
|
||||
} /* end of valid device */
|
||||
} /* end of for */
|
||||
|
@ -26,6 +26,8 @@
|
||||
|
||||
#include "pci.h"
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
|
||||
static int pci_msi_enable = 1;
|
||||
int pci_msi_ignore_mask;
|
||||
|
||||
@ -410,6 +412,17 @@ static void pci_intx_for_msi(struct pci_dev *dev, int enable)
|
||||
pci_intx(dev, enable);
|
||||
}
|
||||
|
||||
static void pci_msi_set_enable(struct pci_dev *dev, int enable)
|
||||
{
|
||||
u16 control;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
||||
control &= ~PCI_MSI_FLAGS_ENABLE;
|
||||
if (enable)
|
||||
control |= PCI_MSI_FLAGS_ENABLE;
|
||||
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
|
||||
}
|
||||
|
||||
static void __pci_restore_msi_state(struct pci_dev *dev)
|
||||
{
|
||||
u16 control;
|
||||
@ -432,6 +445,16 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
|
||||
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
|
||||
}
|
||||
|
||||
static void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
|
||||
ctrl &= ~clear;
|
||||
ctrl |= set;
|
||||
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
|
||||
}
|
||||
|
||||
static void __pci_restore_msix_state(struct pci_dev *dev)
|
||||
{
|
||||
struct msi_desc *entry;
|
||||
@ -600,11 +623,11 @@ static int msi_verify_entries(struct pci_dev *dev)
|
||||
struct msi_desc *entry;
|
||||
|
||||
for_each_pci_msi_entry(entry, dev) {
|
||||
if (!dev->no_64bit_msi || !entry->msg.address_hi)
|
||||
continue;
|
||||
pci_err(dev, "Device has broken 64-bit MSI but arch"
|
||||
" tried to assign one above 4G\n");
|
||||
return -EIO;
|
||||
if (entry->msg.address_hi && dev->no_64bit_msi) {
|
||||
pci_err(dev, "arch assigned 64-bit MSI address %#x%08x but device only supports 32 bits\n",
|
||||
entry->msg.address_hi, entry->msg.address_lo);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1577,3 +1600,40 @@ bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
|
||||
void pci_msi_init(struct pci_dev *dev)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
/*
|
||||
* Disable the MSI hardware to avoid screaming interrupts
|
||||
* during boot. This is the power on reset default so
|
||||
* usually this should be a noop.
|
||||
*/
|
||||
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
|
||||
if (!dev->msi_cap)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
|
||||
if (ctrl & PCI_MSI_FLAGS_ENABLE)
|
||||
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS,
|
||||
ctrl & ~PCI_MSI_FLAGS_ENABLE);
|
||||
|
||||
if (!(ctrl & PCI_MSI_FLAGS_64BIT))
|
||||
dev->no_64bit_msi = 1;
|
||||
}
|
||||
|
||||
void pci_msix_init(struct pci_dev *dev)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
||||
if (!dev->msix_cap)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
|
||||
if (ctrl & PCI_MSIX_FLAGS_ENABLE)
|
||||
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS,
|
||||
ctrl & ~PCI_MSIX_FLAGS_ENABLE);
|
||||
}
|
||||
|
@ -556,6 +556,11 @@ static int pci_parse_request_of_pci_ranges(struct device *dev,
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
|
||||
|
||||
if (!(res->flags & IORESOURCE_PREFETCH))
|
||||
if (upper_32_bits(resource_size(res)))
|
||||
dev_warn(dev, "Memory resource size exceeds max for 32 bits\n");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -609,7 +609,7 @@ bool pci_has_p2pmem(struct pci_dev *pdev)
|
||||
EXPORT_SYMBOL_GPL(pci_has_p2pmem);
|
||||
|
||||
/**
|
||||
* pci_p2pmem_find - find a peer-to-peer DMA memory device compatible with
|
||||
* pci_p2pmem_find_many - find a peer-to-peer DMA memory device compatible with
|
||||
* the specified list of clients and shortest distance (as determined
|
||||
* by pci_p2pmem_dma())
|
||||
* @clients: array of devices to check (NULL-terminated)
|
||||
@ -674,7 +674,7 @@ struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients)
|
||||
EXPORT_SYMBOL_GPL(pci_p2pmem_find_many);
|
||||
|
||||
/**
|
||||
* pci_alloc_p2p_mem - allocate peer-to-peer DMA memory
|
||||
* pci_alloc_p2pmem - allocate peer-to-peer DMA memory
|
||||
* @pdev: the device to allocate memory from
|
||||
* @size: number of bytes to allocate
|
||||
*
|
||||
@ -727,7 +727,7 @@ void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
|
||||
EXPORT_SYMBOL_GPL(pci_free_p2pmem);
|
||||
|
||||
/**
|
||||
* pci_virt_to_bus - return the PCI bus address for a given virtual
|
||||
* pci_p2pmem_virt_to_bus - return the PCI bus address for a given virtual
|
||||
* address obtained with pci_alloc_p2pmem()
|
||||
* @pdev: the device the memory was allocated from
|
||||
* @addr: address of the memory that was allocated
|
||||
@ -859,7 +859,7 @@ static int __pci_p2pdma_map_sg(struct pci_p2pdma_pagemap *p2p_pgmap,
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
|
||||
* pci_p2pdma_map_sg_attrs - map a PCI peer-to-peer scatterlist for DMA
|
||||
* @dev: device doing the DMA request
|
||||
* @sg: scatter list to map
|
||||
* @nents: elements in the scatterlist
|
||||
@ -896,7 +896,7 @@ int pci_p2pdma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
|
||||
EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg_attrs);
|
||||
|
||||
/**
|
||||
* pci_p2pdma_unmap_sg - unmap a PCI peer-to-peer scatterlist that was
|
||||
* pci_p2pdma_unmap_sg_attrs - unmap a PCI peer-to-peer scatterlist that was
|
||||
* mapped with pci_p2pdma_map_sg()
|
||||
* @dev: device doing the DMA request
|
||||
* @sg: scatter list to map
|
||||
|
@ -1162,14 +1162,34 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
|
||||
static struct acpi_device *acpi_pci_find_companion(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(dev);
|
||||
struct acpi_device *adev;
|
||||
bool check_children;
|
||||
u64 addr;
|
||||
|
||||
check_children = pci_is_bridge(pci_dev);
|
||||
/* Please ref to ACPI spec for the syntax of _ADR */
|
||||
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
|
||||
return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
|
||||
adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
|
||||
check_children);
|
||||
|
||||
/*
|
||||
* There may be ACPI device objects in the ACPI namespace that are
|
||||
* children of the device object representing the host bridge, but don't
|
||||
* represent PCI devices. Both _HID and _ADR may be present for them,
|
||||
* even though that is against the specification (for example, see
|
||||
* Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which
|
||||
* appears to indicate that they should not be taken into consideration
|
||||
* as potential companions of PCI devices on the root bus.
|
||||
*
|
||||
* To catch this special case, disregard the returned device object if
|
||||
* it has a valid _HID, addr is 0 and the PCI device at hand is on the
|
||||
* root bus.
|
||||
*/
|
||||
if (adev && adev->pnp.type.platform_id && !addr &&
|
||||
pci_is_root_bus(pci_dev->bus))
|
||||
return NULL;
|
||||
|
||||
return adev;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,80 @@ static void pci_free_dynids(struct pci_driver *drv)
|
||||
}
|
||||
|
||||
/**
|
||||
* store_new_id - sysfs frontend to pci_add_dynid()
|
||||
* pci_match_id - See if a PCI device matches a given pci_id table
|
||||
* @ids: array of PCI device ID structures to search in
|
||||
* @dev: the PCI device structure to match against.
|
||||
*
|
||||
* Used by a driver to check whether a PCI device is in its list of
|
||||
* supported devices. Returns the matching pci_device_id structure or
|
||||
* %NULL if there is no match.
|
||||
*
|
||||
* Deprecated; don't use this as it will not catch any dynamic IDs
|
||||
* that a driver might want to check for.
|
||||
*/
|
||||
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
if (ids) {
|
||||
while (ids->vendor || ids->subvendor || ids->class_mask) {
|
||||
if (pci_match_one_device(ids, dev))
|
||||
return ids;
|
||||
ids++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_match_id);
|
||||
|
||||
static const struct pci_device_id pci_device_id_any = {
|
||||
.vendor = PCI_ANY_ID,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
};
|
||||
|
||||
/**
|
||||
* pci_match_device - See if a device matches a driver's list of IDs
|
||||
* @drv: the PCI driver to match against
|
||||
* @dev: the PCI device structure to match against
|
||||
*
|
||||
* Used by a driver to check whether a PCI device is in its list of
|
||||
* supported devices or in the dynids list, which may have been augmented
|
||||
* via the sysfs "new_id" file. Returns the matching pci_device_id
|
||||
* structure or %NULL if there is no match.
|
||||
*/
|
||||
static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dynid *dynid;
|
||||
const struct pci_device_id *found_id = NULL;
|
||||
|
||||
/* When driver_override is set, only bind to the matching driver */
|
||||
if (dev->driver_override && strcmp(dev->driver_override, drv->name))
|
||||
return NULL;
|
||||
|
||||
/* Look at the dynamic ids first, before the static ones */
|
||||
spin_lock(&drv->dynids.lock);
|
||||
list_for_each_entry(dynid, &drv->dynids.list, node) {
|
||||
if (pci_match_one_device(&dynid->id, dev)) {
|
||||
found_id = &dynid->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&drv->dynids.lock);
|
||||
|
||||
if (!found_id)
|
||||
found_id = pci_match_id(drv->id_table, dev);
|
||||
|
||||
/* driver_override will always match, send a dummy id */
|
||||
if (!found_id && dev->driver_override)
|
||||
found_id = &pci_device_id_any;
|
||||
|
||||
return found_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* new_id_store - sysfs frontend to pci_add_dynid()
|
||||
* @driver: target device driver
|
||||
* @buf: buffer for scanning device ID data
|
||||
* @count: input size
|
||||
@ -125,7 +198,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
|
||||
pdev->subsystem_device = subdevice;
|
||||
pdev->class = class;
|
||||
|
||||
if (pci_match_id(pdrv->id_table, pdev))
|
||||
if (pci_match_device(pdrv, pdev))
|
||||
retval = -EEXIST;
|
||||
|
||||
kfree(pdev);
|
||||
@ -158,7 +231,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf,
|
||||
static DRIVER_ATTR_WO(new_id);
|
||||
|
||||
/**
|
||||
* store_remove_id - remove a PCI device ID from this driver
|
||||
* remove_id_store - remove a PCI device ID from this driver
|
||||
* @driver: target device driver
|
||||
* @buf: buffer for scanning device ID data
|
||||
* @count: input size
|
||||
@ -208,78 +281,6 @@ static struct attribute *pci_drv_attrs[] = {
|
||||
};
|
||||
ATTRIBUTE_GROUPS(pci_drv);
|
||||
|
||||
/**
|
||||
* pci_match_id - See if a pci device matches a given pci_id table
|
||||
* @ids: array of PCI device id structures to search in
|
||||
* @dev: the PCI device structure to match against.
|
||||
*
|
||||
* Used by a driver to check whether a PCI device present in the
|
||||
* system is in its list of supported devices. Returns the matching
|
||||
* pci_device_id structure or %NULL if there is no match.
|
||||
*
|
||||
* Deprecated, don't use this as it will not catch any dynamic ids
|
||||
* that a driver might want to check for.
|
||||
*/
|
||||
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
if (ids) {
|
||||
while (ids->vendor || ids->subvendor || ids->class_mask) {
|
||||
if (pci_match_one_device(ids, dev))
|
||||
return ids;
|
||||
ids++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_match_id);
|
||||
|
||||
static const struct pci_device_id pci_device_id_any = {
|
||||
.vendor = PCI_ANY_ID,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
};
|
||||
|
||||
/**
|
||||
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
|
||||
* @drv: the PCI driver to match against
|
||||
* @dev: the PCI device structure to match against
|
||||
*
|
||||
* Used by a driver to check whether a PCI device present in the
|
||||
* system is in its list of supported devices. Returns the matching
|
||||
* pci_device_id structure or %NULL if there is no match.
|
||||
*/
|
||||
static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dynid *dynid;
|
||||
const struct pci_device_id *found_id = NULL;
|
||||
|
||||
/* When driver_override is set, only bind to the matching driver */
|
||||
if (dev->driver_override && strcmp(dev->driver_override, drv->name))
|
||||
return NULL;
|
||||
|
||||
/* Look at the dynamic ids first, before the static ones */
|
||||
spin_lock(&drv->dynids.lock);
|
||||
list_for_each_entry(dynid, &drv->dynids.list, node) {
|
||||
if (pci_match_one_device(&dynid->id, dev)) {
|
||||
found_id = &dynid->id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&drv->dynids.lock);
|
||||
|
||||
if (!found_id)
|
||||
found_id = pci_match_id(drv->id_table, dev);
|
||||
|
||||
/* driver_override will always match, send a dummy id */
|
||||
if (!found_id && dev->driver_override)
|
||||
found_id = &pci_device_id_any;
|
||||
|
||||
return found_id;
|
||||
}
|
||||
|
||||
struct drv_dev_and_id {
|
||||
struct pci_driver *drv;
|
||||
struct pci_dev *dev;
|
||||
|
@ -124,6 +124,15 @@ static ssize_t cpulistaffinity_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(cpulistaffinity);
|
||||
|
||||
static ssize_t power_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", pci_power_name(pdev->current_state));
|
||||
}
|
||||
static DEVICE_ATTR_RO(power_state);
|
||||
|
||||
/* show resources */
|
||||
static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -581,6 +590,7 @@ static ssize_t driver_override_show(struct device *dev,
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
static struct attribute *pci_dev_attrs[] = {
|
||||
&dev_attr_power_state.attr,
|
||||
&dev_attr_resource.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_device.attr,
|
||||
|
@ -399,8 +399,8 @@ found:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap, int *ttl)
|
||||
static u8 __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap, int *ttl)
|
||||
{
|
||||
u8 id;
|
||||
u16 ent;
|
||||
@ -423,22 +423,22 @@ static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap)
|
||||
static u8 __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
|
||||
u8 pos, int cap)
|
||||
{
|
||||
int ttl = PCI_FIND_CAP_TTL;
|
||||
|
||||
return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
|
||||
}
|
||||
|
||||
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
|
||||
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
|
||||
{
|
||||
return __pci_find_next_cap(dev->bus, dev->devfn,
|
||||
pos + PCI_CAP_LIST_NEXT, cap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_next_capability);
|
||||
|
||||
static int __pci_bus_find_cap_start(struct pci_bus *bus,
|
||||
static u8 __pci_bus_find_cap_start(struct pci_bus *bus,
|
||||
unsigned int devfn, u8 hdr_type)
|
||||
{
|
||||
u16 status;
|
||||
@ -477,9 +477,9 @@ static int __pci_bus_find_cap_start(struct pci_bus *bus,
|
||||
* %PCI_CAP_ID_PCIX PCI-X
|
||||
* %PCI_CAP_ID_EXP PCI Express
|
||||
*/
|
||||
int pci_find_capability(struct pci_dev *dev, int cap)
|
||||
u8 pci_find_capability(struct pci_dev *dev, int cap)
|
||||
{
|
||||
int pos;
|
||||
u8 pos;
|
||||
|
||||
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
|
||||
if (pos)
|
||||
@ -502,10 +502,9 @@ EXPORT_SYMBOL(pci_find_capability);
|
||||
* device's PCI configuration space or 0 in case the device does not
|
||||
* support it.
|
||||
*/
|
||||
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
|
||||
u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
|
||||
{
|
||||
int pos;
|
||||
u8 hdr_type;
|
||||
u8 hdr_type, pos;
|
||||
|
||||
pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
|
||||
|
||||
@ -528,11 +527,11 @@ EXPORT_SYMBOL(pci_bus_find_capability);
|
||||
* not support it. Some capabilities can occur several times, e.g., the
|
||||
* vendor-specific capability, and this provides a way to find them all.
|
||||
*/
|
||||
int pci_find_next_ext_capability(struct pci_dev *dev, int start, int cap)
|
||||
u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 start, int cap)
|
||||
{
|
||||
u32 header;
|
||||
int ttl;
|
||||
int pos = PCI_CFG_SPACE_SIZE;
|
||||
u16 pos = PCI_CFG_SPACE_SIZE;
|
||||
|
||||
/* minimum 8 bytes per capability */
|
||||
ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
|
||||
@ -583,7 +582,7 @@ EXPORT_SYMBOL_GPL(pci_find_next_ext_capability);
|
||||
* %PCI_EXT_CAP_ID_DSN Device Serial Number
|
||||
* %PCI_EXT_CAP_ID_PWR Power Budgeting
|
||||
*/
|
||||
int pci_find_ext_capability(struct pci_dev *dev, int cap)
|
||||
u16 pci_find_ext_capability(struct pci_dev *dev, int cap)
|
||||
{
|
||||
return pci_find_next_ext_capability(dev, 0, cap);
|
||||
}
|
||||
@ -623,7 +622,7 @@ u64 pci_get_dsn(struct pci_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_get_dsn);
|
||||
|
||||
static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
|
||||
static u8 __pci_find_next_ht_cap(struct pci_dev *dev, u8 pos, int ht_cap)
|
||||
{
|
||||
int rc, ttl = PCI_FIND_CAP_TTL;
|
||||
u8 cap, mask;
|
||||
@ -650,11 +649,12 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_find_next_ht_capability - query a device's Hypertransport capabilities
|
||||
* pci_find_next_ht_capability - query a device's HyperTransport capabilities
|
||||
* @dev: PCI device to query
|
||||
* @pos: Position from which to continue searching
|
||||
* @ht_cap: Hypertransport capability code
|
||||
* @ht_cap: HyperTransport capability code
|
||||
*
|
||||
* To be used in conjunction with pci_find_ht_capability() to search for
|
||||
* all capabilities matching @ht_cap. @pos should always be a value returned
|
||||
@ -663,26 +663,26 @@ static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
|
||||
* NB. To be 100% safe against broken PCI devices, the caller should take
|
||||
* steps to avoid an infinite loop.
|
||||
*/
|
||||
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
|
||||
u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap)
|
||||
{
|
||||
return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
|
||||
|
||||
/**
|
||||
* pci_find_ht_capability - query a device's Hypertransport capabilities
|
||||
* pci_find_ht_capability - query a device's HyperTransport capabilities
|
||||
* @dev: PCI device to query
|
||||
* @ht_cap: Hypertransport capability code
|
||||
* @ht_cap: HyperTransport capability code
|
||||
*
|
||||
* Tell if a device supports a given Hypertransport capability.
|
||||
* Tell if a device supports a given HyperTransport capability.
|
||||
* Returns an address within the device's PCI configuration space
|
||||
* or 0 in case the device does not support the request capability.
|
||||
* The address points to the PCI capability, of type PCI_CAP_ID_HT,
|
||||
* which has a Hypertransport capability matching @ht_cap.
|
||||
* which has a HyperTransport capability matching @ht_cap.
|
||||
*/
|
||||
int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
|
||||
u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
|
||||
{
|
||||
int pos;
|
||||
u8 pos;
|
||||
|
||||
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
|
||||
if (pos)
|
||||
@ -1174,26 +1174,20 @@ int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_platform_power_transition);
|
||||
|
||||
/**
|
||||
* pci_wakeup - Wake up a PCI device
|
||||
* @pci_dev: Device to handle.
|
||||
* @ign: ignored parameter
|
||||
*/
|
||||
static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
|
||||
static int pci_resume_one(struct pci_dev *pci_dev, void *ign)
|
||||
{
|
||||
pci_wakeup_event(pci_dev);
|
||||
pm_request_resume(&pci_dev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_wakeup_bus - Walk given bus and wake up devices on it
|
||||
* pci_resume_bus - Walk given bus and runtime resume devices on it
|
||||
* @bus: Top bus of the subtree to walk.
|
||||
*/
|
||||
void pci_wakeup_bus(struct pci_bus *bus)
|
||||
void pci_resume_bus(struct pci_bus *bus)
|
||||
{
|
||||
if (bus)
|
||||
pci_walk_bus(bus, pci_wakeup, NULL);
|
||||
pci_walk_bus(bus, pci_resume_one, NULL);
|
||||
}
|
||||
|
||||
static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
|
||||
@ -1256,7 +1250,7 @@ int pci_power_up(struct pci_dev *dev)
|
||||
* may be powered on into D0uninitialized state, resume them to
|
||||
* give them a chance to suspend again
|
||||
*/
|
||||
pci_wakeup_bus(dev->subordinate);
|
||||
pci_resume_bus(dev->subordinate);
|
||||
}
|
||||
|
||||
return pci_raw_set_power_state(dev, PCI_D0);
|
||||
@ -1564,8 +1558,10 @@ int pci_save_state(struct pci_dev *dev)
|
||||
return i;
|
||||
|
||||
pci_save_ltr_state(dev);
|
||||
pci_save_aspm_l1ss_state(dev);
|
||||
pci_save_dpc_state(dev);
|
||||
pci_save_aer_state(dev);
|
||||
pci_save_ptm_state(dev);
|
||||
return pci_save_vc_state(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_save_state);
|
||||
@ -1669,6 +1665,7 @@ void pci_restore_state(struct pci_dev *dev)
|
||||
* LTR itself (in the PCIe capability).
|
||||
*/
|
||||
pci_restore_ltr_state(dev);
|
||||
pci_restore_aspm_l1ss_state(dev);
|
||||
|
||||
pci_restore_pcie_state(dev);
|
||||
pci_restore_pasid_state(dev);
|
||||
@ -1677,6 +1674,7 @@ void pci_restore_state(struct pci_dev *dev)
|
||||
pci_restore_vc_state(dev);
|
||||
pci_restore_rebar_state(dev);
|
||||
pci_restore_dpc_state(dev);
|
||||
pci_restore_ptm_state(dev);
|
||||
|
||||
pci_aer_clear_status(dev);
|
||||
pci_restore_aer_state(dev);
|
||||
@ -2606,12 +2604,24 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
|
||||
if (target_state == PCI_POWER_ERROR)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* There are systems (for example, Intel mobile chips since Coffee
|
||||
* Lake) where the power drawn while suspended can be significantly
|
||||
* reduced by disabling PTM on PCIe root ports as this allows the
|
||||
* port to enter a lower-power PM state and the SoC to reach a
|
||||
* lower-power idle state as a whole.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
pci_disable_ptm(dev);
|
||||
|
||||
pci_enable_wake(dev, target_state, wakeup);
|
||||
|
||||
error = pci_set_power_state(dev, target_state);
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
pci_enable_wake(dev, target_state, false);
|
||||
pci_restore_ptm_state(dev);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -2649,12 +2659,23 @@ int pci_finish_runtime_suspend(struct pci_dev *dev)
|
||||
|
||||
dev->runtime_d3cold = target_state == PCI_D3cold;
|
||||
|
||||
/*
|
||||
* There are systems (for example, Intel mobile chips since Coffee
|
||||
* Lake) where the power drawn while suspended can be significantly
|
||||
* reduced by disabling PTM on PCIe root ports as this allows the
|
||||
* port to enter a lower-power PM state and the SoC to reach a
|
||||
* lower-power idle state as a whole.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT)
|
||||
pci_disable_ptm(dev);
|
||||
|
||||
__pci_enable_wake(dev, target_state, pci_dev_run_wake(dev));
|
||||
|
||||
error = pci_set_power_state(dev, target_state);
|
||||
|
||||
if (error) {
|
||||
pci_enable_wake(dev, target_state, false);
|
||||
pci_restore_ptm_state(dev);
|
||||
dev->runtime_d3cold = false;
|
||||
}
|
||||
|
||||
@ -3332,6 +3353,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
|
||||
if (error)
|
||||
pci_err(dev, "unable to allocate suspend buffer for LTR\n");
|
||||
|
||||
error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
|
||||
2 * sizeof(u32));
|
||||
if (error)
|
||||
pci_err(dev, "unable to allocate suspend buffer for ASPM-L1SS\n");
|
||||
|
||||
pci_allocate_vc_save_buffers(dev);
|
||||
}
|
||||
|
||||
@ -3480,7 +3506,7 @@ bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_acs_path_enable - test ACS flags from start to end in a hierarchy
|
||||
* pci_acs_path_enabled - test ACS flags from start to end in a hierarchy
|
||||
* @start: starting downstream device
|
||||
* @end: ending upstream device or NULL to search to the root bus
|
||||
* @acs_flags: required flags
|
||||
@ -4188,7 +4214,14 @@ void __iomem *devm_pci_remap_cfg_resource(struct device *dev,
|
||||
}
|
||||
|
||||
size = resource_size(res);
|
||||
name = res->name ?: dev_name(dev);
|
||||
|
||||
if (res->name)
|
||||
name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", dev_name(dev),
|
||||
res->name);
|
||||
else
|
||||
name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
|
||||
if (!name)
|
||||
return IOMEM_ERR_PTR(-ENOMEM);
|
||||
|
||||
if (!devm_request_mem_region(dev, res->start, size, name)) {
|
||||
dev_err(dev, "can't request region for resource %pR\n", res);
|
||||
@ -4317,7 +4350,7 @@ int pci_set_cacheline_size(struct pci_dev *dev)
|
||||
if (cacheline_size == pci_cache_line_size)
|
||||
return 0;
|
||||
|
||||
pci_info(dev, "cache line size of %d is not supported\n",
|
||||
pci_dbg(dev, "cache line size of %d is not supported\n",
|
||||
pci_cache_line_size << 2);
|
||||
|
||||
return -EINVAL;
|
||||
@ -6202,19 +6235,21 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
|
||||
while (*p) {
|
||||
count = 0;
|
||||
if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
|
||||
p[count] == '@') {
|
||||
p[count] == '@') {
|
||||
p += count + 1;
|
||||
if (align_order > 63) {
|
||||
pr_err("PCI: Invalid requested alignment (order %d)\n",
|
||||
align_order);
|
||||
align_order = PAGE_SHIFT;
|
||||
}
|
||||
} else {
|
||||
align_order = -1;
|
||||
align_order = PAGE_SHIFT;
|
||||
}
|
||||
|
||||
ret = pci_dev_str_match(dev, p, &p);
|
||||
if (ret == 1) {
|
||||
*resize = true;
|
||||
if (align_order == -1)
|
||||
align = PAGE_SIZE;
|
||||
else
|
||||
align = 1 << align_order;
|
||||
align = 1ULL << align_order;
|
||||
break;
|
||||
} else if (ret < 0) {
|
||||
pr_err("PCI: Can't parse resource_alignment parameter: %s\n",
|
||||
|
@ -104,6 +104,8 @@ void pci_config_pm_runtime_get(struct pci_dev *dev);
|
||||
void pci_config_pm_runtime_put(struct pci_dev *dev);
|
||||
void pci_pm_init(struct pci_dev *dev);
|
||||
void pci_ea_init(struct pci_dev *dev);
|
||||
void pci_msi_init(struct pci_dev *dev);
|
||||
void pci_msix_init(struct pci_dev *dev);
|
||||
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
|
||||
void pci_free_cap_save_buffers(struct pci_dev *dev);
|
||||
bool pci_bridge_d3_possible(struct pci_dev *dev);
|
||||
@ -185,27 +187,6 @@ void pci_no_msi(void);
|
||||
static inline void pci_no_msi(void) { }
|
||||
#endif
|
||||
|
||||
static inline void pci_msi_set_enable(struct pci_dev *dev, int enable)
|
||||
{
|
||||
u16 control;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
||||
control &= ~PCI_MSI_FLAGS_ENABLE;
|
||||
if (enable)
|
||||
control |= PCI_MSI_FLAGS_ENABLE;
|
||||
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
|
||||
}
|
||||
|
||||
static inline void pci_msix_clear_and_set_ctrl(struct pci_dev *dev, u16 clear, u16 set)
|
||||
{
|
||||
u16 ctrl;
|
||||
|
||||
pci_read_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
|
||||
ctrl &= ~clear;
|
||||
ctrl |= set;
|
||||
pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, ctrl);
|
||||
}
|
||||
|
||||
void pci_realloc_get_opt(char *);
|
||||
|
||||
static inline int pci_no_d1d2(struct pci_dev *dev)
|
||||
@ -294,7 +275,8 @@ void pci_bus_put(struct pci_bus *bus);
|
||||
|
||||
/* PCIe link information from Link Capabilities 2 */
|
||||
#define PCIE_LNKCAP2_SLS2SPEED(lnkcap2) \
|
||||
((lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \
|
||||
((lnkcap2) & PCI_EXP_LNKCAP2_SLS_64_0GB ? PCIE_SPEED_64_0GT : \
|
||||
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_32_0GB ? PCIE_SPEED_32_0GT : \
|
||||
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_16_0GB ? PCIE_SPEED_16_0GT : \
|
||||
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_8_0GB ? PCIE_SPEED_8_0GT : \
|
||||
(lnkcap2) & PCI_EXP_LNKCAP2_SLS_5_0GB ? PCIE_SPEED_5_0GT : \
|
||||
@ -303,7 +285,8 @@ void pci_bus_put(struct pci_bus *bus);
|
||||
|
||||
/* PCIe speed to Mb/s reduced by encoding overhead */
|
||||
#define PCIE_SPEED2MBS_ENC(speed) \
|
||||
((speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
|
||||
((speed) == PCIE_SPEED_64_0GT ? 64000*128/130 : \
|
||||
(speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
|
||||
(speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
|
||||
(speed) == PCIE_SPEED_8_0GT ? 8000*128/130 : \
|
||||
(speed) == PCIE_SPEED_5_0GT ? 5000*8/10 : \
|
||||
@ -448,6 +431,15 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info);
|
||||
void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
||||
#endif /* CONFIG_PCIEAER */
|
||||
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
/* Cached RCEC Endpoint Association */
|
||||
struct rcec_ea {
|
||||
u8 nextbusn;
|
||||
u8 lastbusn;
|
||||
u32 bitmap;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_DPC
|
||||
void pci_save_dpc_state(struct pci_dev *dev);
|
||||
void pci_restore_dpc_state(struct pci_dev *dev);
|
||||
@ -460,6 +452,22 @@ static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
|
||||
static inline void pci_dpc_init(struct pci_dev *pdev) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
void pci_rcec_init(struct pci_dev *dev);
|
||||
void pci_rcec_exit(struct pci_dev *dev);
|
||||
void pcie_link_rcec(struct pci_dev *rcec);
|
||||
void pcie_walk_rcec(struct pci_dev *rcec,
|
||||
int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata);
|
||||
#else
|
||||
static inline void pci_rcec_init(struct pci_dev *dev) {}
|
||||
static inline void pci_rcec_exit(struct pci_dev *dev) {}
|
||||
static inline void pcie_link_rcec(struct pci_dev *rcec) {}
|
||||
static inline void pcie_walk_rcec(struct pci_dev *rcec,
|
||||
int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_ATS
|
||||
/* Address Translation Service */
|
||||
void pci_ats_init(struct pci_dev *dev);
|
||||
@ -516,6 +524,16 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
|
||||
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
#ifdef CONFIG_PCIE_PTM
|
||||
void pci_save_ptm_state(struct pci_dev *dev);
|
||||
void pci_restore_ptm_state(struct pci_dev *dev);
|
||||
void pci_disable_ptm(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pci_save_ptm_state(struct pci_dev *dev) { }
|
||||
static inline void pci_restore_ptm_state(struct pci_dev *dev) { }
|
||||
static inline void pci_disable_ptm(struct pci_dev *dev) { }
|
||||
#endif
|
||||
|
||||
unsigned long pci_cardbus_resource_alignment(struct resource *);
|
||||
|
||||
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
|
||||
@ -555,8 +573,8 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
|
||||
|
||||
/* PCI error reporting and recovery */
|
||||
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
||||
pci_channel_state_t state,
|
||||
pci_ers_result_t (*reset_link)(struct pci_dev *pdev));
|
||||
pci_channel_state_t state,
|
||||
pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev));
|
||||
|
||||
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
@ -564,11 +582,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_exit_link_state(struct pci_dev *pdev);
|
||||
void pcie_aspm_pm_state_change(struct pci_dev *pdev);
|
||||
void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
|
||||
void pci_save_aspm_l1ss_state(struct pci_dev *dev);
|
||||
void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
|
||||
#else
|
||||
static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
|
||||
static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
|
||||
static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
|
||||
static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_ECRC
|
||||
|
@ -2,7 +2,7 @@
|
||||
#
|
||||
# Makefile for PCI Express features and port driver
|
||||
|
||||
pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o
|
||||
pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o rcec.o
|
||||
|
||||
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
|
||||
|
||||
|
@ -300,7 +300,8 @@ int pci_aer_raw_clear_status(struct pci_dev *dev)
|
||||
return -EIO;
|
||||
|
||||
port_type = pci_pcie_type(dev);
|
||||
if (port_type == PCI_EXP_TYPE_ROOT_PORT) {
|
||||
if (port_type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
port_type == PCI_EXP_TYPE_RC_EC) {
|
||||
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, &status);
|
||||
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, status);
|
||||
}
|
||||
@ -595,7 +596,8 @@ static umode_t aer_stats_attrs_are_visible(struct kobject *kobj,
|
||||
if ((a == &dev_attr_aer_rootport_total_err_cor.attr ||
|
||||
a == &dev_attr_aer_rootport_total_err_fatal.attr ||
|
||||
a == &dev_attr_aer_rootport_total_err_nonfatal.attr) &&
|
||||
pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT)
|
||||
((pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
(pci_pcie_type(pdev) != PCI_EXP_TYPE_RC_EC)))
|
||||
return 0;
|
||||
|
||||
return a->mode;
|
||||
@ -916,7 +918,10 @@ static bool find_source_device(struct pci_dev *parent,
|
||||
if (result)
|
||||
return true;
|
||||
|
||||
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
|
||||
if (pci_pcie_type(parent) == PCI_EXP_TYPE_RC_EC)
|
||||
pcie_walk_rcec(parent, find_device_iter, e_info);
|
||||
else
|
||||
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
|
||||
|
||||
if (!e_info->error_dev_num) {
|
||||
pci_info(parent, "can't find device of ID%04x\n", e_info->id);
|
||||
@ -1034,6 +1039,7 @@ EXPORT_SYMBOL_GPL(aer_recover_queue);
|
||||
*/
|
||||
int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||
{
|
||||
int type = pci_pcie_type(dev);
|
||||
int aer = dev->aer_cap;
|
||||
int temp;
|
||||
|
||||
@ -1052,8 +1058,9 @@ int aer_get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
|
||||
&info->mask);
|
||||
if (!(info->status & ~info->mask))
|
||||
return 0;
|
||||
} else if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
|
||||
} else if (type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
type == PCI_EXP_TYPE_RC_EC ||
|
||||
type == PCI_EXP_TYPE_DOWNSTREAM ||
|
||||
info->severity == AER_NONFATAL) {
|
||||
|
||||
/* Link is still healthy for IO reads */
|
||||
@ -1205,6 +1212,7 @@ static int set_device_error_reporting(struct pci_dev *dev, void *data)
|
||||
int type = pci_pcie_type(dev);
|
||||
|
||||
if ((type == PCI_EXP_TYPE_ROOT_PORT) ||
|
||||
(type == PCI_EXP_TYPE_RC_EC) ||
|
||||
(type == PCI_EXP_TYPE_UPSTREAM) ||
|
||||
(type == PCI_EXP_TYPE_DOWNSTREAM)) {
|
||||
if (enable)
|
||||
@ -1229,9 +1237,12 @@ static void set_downstream_devices_error_reporting(struct pci_dev *dev,
|
||||
{
|
||||
set_device_error_reporting(dev, &enable);
|
||||
|
||||
if (!dev->subordinate)
|
||||
return;
|
||||
pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC)
|
||||
pcie_walk_rcec(dev, set_device_error_reporting, &enable);
|
||||
else if (dev->subordinate)
|
||||
pci_walk_bus(dev->subordinate, set_device_error_reporting,
|
||||
&enable);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1329,6 +1340,11 @@ static int aer_probe(struct pcie_device *dev)
|
||||
struct device *device = &dev->device;
|
||||
struct pci_dev *port = dev->port;
|
||||
|
||||
/* Limit to Root Ports or Root Complex Event Collectors */
|
||||
if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
|
||||
(pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
|
||||
return -ENODEV;
|
||||
|
||||
rpc = devm_kzalloc(device, sizeof(struct aer_rpc), GFP_KERNEL);
|
||||
if (!rpc)
|
||||
return -ENOMEM;
|
||||
@ -1350,41 +1366,74 @@ static int aer_probe(struct pcie_device *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* aer_root_reset - reset link on Root Port
|
||||
* @dev: pointer to Root Port's pci_dev data structure
|
||||
* aer_root_reset - reset Root Port hierarchy, RCEC, or RCiEP
|
||||
* @dev: pointer to Root Port, RCEC, or RCiEP
|
||||
*
|
||||
* Invoked by Port Bus driver when performing link reset at Root Port.
|
||||
* Invoked by Port Bus driver when performing reset.
|
||||
*/
|
||||
static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
||||
{
|
||||
int aer = dev->aer_cap;
|
||||
int type = pci_pcie_type(dev);
|
||||
struct pci_dev *root;
|
||||
int aer;
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
||||
u32 reg32;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Only Root Ports and RCECs have AER Root Command and Root Status
|
||||
* registers. If "dev" is an RCiEP, the relevant registers are in
|
||||
* the RCEC.
|
||||
*/
|
||||
if (type == PCI_EXP_TYPE_RC_END)
|
||||
root = dev->rcec;
|
||||
else
|
||||
root = dev;
|
||||
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
/*
|
||||
* If the platform retained control of AER, an RCiEP may not have
|
||||
* an RCEC visible to us, so dev->rcec ("root") may be NULL. In
|
||||
* that case, firmware is responsible for these registers.
|
||||
*/
|
||||
aer = root ? root->aer_cap : 0;
|
||||
|
||||
rc = pci_bus_error_reset(dev);
|
||||
pci_info(dev, "Root Port link has been reset\n");
|
||||
if ((host->native_aer || pcie_ports_native) && aer) {
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
/* Clear Root Error Status */
|
||||
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, ®32);
|
||||
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_STATUS, reg32);
|
||||
if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {
|
||||
if (pcie_has_flr(dev)) {
|
||||
rc = pcie_flr(dev);
|
||||
pci_info(dev, "has been reset (%d)\n", rc);
|
||||
} else {
|
||||
pci_info(dev, "not reset (no FLR support)\n");
|
||||
rc = -ENOTTY;
|
||||
}
|
||||
} else {
|
||||
rc = pci_bus_error_reset(dev);
|
||||
pci_info(dev, "Root Port link has been reset (%d)\n", rc);
|
||||
}
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(dev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
if ((host->native_aer || pcie_ports_native) && aer) {
|
||||
/* Clear Root Error Status */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, ®32);
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32);
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
||||
static struct pcie_port_service_driver aerdriver = {
|
||||
.name = "aer",
|
||||
.port_type = PCI_EXP_TYPE_ROOT_PORT,
|
||||
.port_type = PCIE_ANY_PORT,
|
||||
.service = PCIE_PORT_SERVICE_AER,
|
||||
|
||||
.probe = aer_probe,
|
||||
|
@ -333,8 +333,11 @@ static int aer_inject(struct aer_error_inj *einj)
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
rpdev = pcie_find_root_port(dev);
|
||||
/* If Root Port not found, try to find an RCEC */
|
||||
if (!rpdev)
|
||||
rpdev = dev->rcec;
|
||||
if (!rpdev) {
|
||||
pci_err(dev, "Root port not found\n");
|
||||
pci_err(dev, "Neither Root Port nor RCEC found\n");
|
||||
ret = -ENODEV;
|
||||
goto out_put;
|
||||
}
|
||||
|
@ -734,6 +734,50 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
PCI_L1SS_CTL1_L1SS_MASK, val);
|
||||
}
|
||||
|
||||
void pci_save_aspm_l1ss_state(struct pci_dev *dev)
|
||||
{
|
||||
int aspm_l1ss;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u32 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!aspm_l1ss)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
cap = (u32 *)&save_state->cap.data[0];
|
||||
pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, cap++);
|
||||
pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, cap++);
|
||||
}
|
||||
|
||||
void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
|
||||
{
|
||||
int aspm_l1ss;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u32 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!aspm_l1ss)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!save_state)
|
||||
return;
|
||||
|
||||
cap = (u32 *)&save_state->cap.data[0];
|
||||
pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, *cap++);
|
||||
pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, *cap++);
|
||||
}
|
||||
|
||||
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
|
||||
{
|
||||
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
|
||||
|
@ -146,38 +146,71 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
||||
pci_channel_state_t state,
|
||||
pci_ers_result_t (*reset_link)(struct pci_dev *pdev))
|
||||
/**
|
||||
* pci_walk_bridge - walk bridges potentially AER affected
|
||||
* @bridge: bridge which may be a Port, an RCEC, or an RCiEP
|
||||
* @cb: callback to be called for each device found
|
||||
* @userdata: arbitrary pointer to be passed to callback
|
||||
*
|
||||
* If the device provided is a bridge, walk the subordinate bus, including
|
||||
* any bridged devices on buses under this bus. Call the provided callback
|
||||
* on each device found.
|
||||
*
|
||||
* If the device provided has no subordinate bus, e.g., an RCEC or RCiEP,
|
||||
* call the callback on the device itself.
|
||||
*/
|
||||
static void pci_walk_bridge(struct pci_dev *bridge,
|
||||
int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata)
|
||||
{
|
||||
if (bridge->subordinate)
|
||||
pci_walk_bus(bridge->subordinate, cb, userdata);
|
||||
else
|
||||
cb(bridge, userdata);
|
||||
}
|
||||
|
||||
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
||||
pci_channel_state_t state,
|
||||
pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev))
|
||||
{
|
||||
int type = pci_pcie_type(dev);
|
||||
struct pci_dev *bridge;
|
||||
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
|
||||
struct pci_bus *bus;
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
||||
|
||||
/*
|
||||
* Error recovery runs on all subordinates of the first downstream port.
|
||||
* If the downstream port detected the error, it is cleared at the end.
|
||||
* If the error was detected by a Root Port, Downstream Port, RCEC,
|
||||
* or RCiEP, recovery runs on the device itself. For Ports, that
|
||||
* also includes any subordinate devices.
|
||||
*
|
||||
* If it was detected by another device (Endpoint, etc), recovery
|
||||
* runs on the device and anything else under the same Port, i.e.,
|
||||
* everything under "bridge".
|
||||
*/
|
||||
if (!(pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM))
|
||||
dev = dev->bus->self;
|
||||
bus = dev->subordinate;
|
||||
if (type == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
type == PCI_EXP_TYPE_DOWNSTREAM ||
|
||||
type == PCI_EXP_TYPE_RC_EC ||
|
||||
type == PCI_EXP_TYPE_RC_END)
|
||||
bridge = dev;
|
||||
else
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
|
||||
pci_dbg(dev, "broadcast error_detected message\n");
|
||||
pci_dbg(bridge, "broadcast error_detected message\n");
|
||||
if (state == pci_channel_io_frozen) {
|
||||
pci_walk_bus(bus, report_frozen_detected, &status);
|
||||
status = reset_link(dev);
|
||||
pci_walk_bridge(bridge, report_frozen_detected, &status);
|
||||
status = reset_subordinates(bridge);
|
||||
if (status != PCI_ERS_RESULT_RECOVERED) {
|
||||
pci_warn(dev, "link reset failed\n");
|
||||
pci_warn(bridge, "subordinate device reset failed\n");
|
||||
goto failed;
|
||||
}
|
||||
} else {
|
||||
pci_walk_bus(bus, report_normal_detected, &status);
|
||||
pci_walk_bridge(bridge, report_normal_detected, &status);
|
||||
}
|
||||
|
||||
if (status == PCI_ERS_RESULT_CAN_RECOVER) {
|
||||
status = PCI_ERS_RESULT_RECOVERED;
|
||||
pci_dbg(dev, "broadcast mmio_enabled message\n");
|
||||
pci_walk_bus(bus, report_mmio_enabled, &status);
|
||||
pci_dbg(bridge, "broadcast mmio_enabled message\n");
|
||||
pci_walk_bridge(bridge, report_mmio_enabled, &status);
|
||||
}
|
||||
|
||||
if (status == PCI_ERS_RESULT_NEED_RESET) {
|
||||
@ -187,27 +220,35 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
||||
* drivers' slot_reset callbacks?
|
||||
*/
|
||||
status = PCI_ERS_RESULT_RECOVERED;
|
||||
pci_dbg(dev, "broadcast slot_reset message\n");
|
||||
pci_walk_bus(bus, report_slot_reset, &status);
|
||||
pci_dbg(bridge, "broadcast slot_reset message\n");
|
||||
pci_walk_bridge(bridge, report_slot_reset, &status);
|
||||
}
|
||||
|
||||
if (status != PCI_ERS_RESULT_RECOVERED)
|
||||
goto failed;
|
||||
|
||||
pci_dbg(dev, "broadcast resume message\n");
|
||||
pci_walk_bus(bus, report_resume, &status);
|
||||
pci_dbg(bridge, "broadcast resume message\n");
|
||||
pci_walk_bridge(bridge, report_resume, &status);
|
||||
|
||||
if (pcie_aer_is_native(dev))
|
||||
pcie_clear_device_status(dev);
|
||||
pci_aer_clear_nonfatal_status(dev);
|
||||
pci_info(dev, "device recovery successful\n");
|
||||
/*
|
||||
* If we have native control of AER, clear error status in the Root
|
||||
* Port or Downstream Port that signaled the error. If the
|
||||
* platform retained control of AER, it is responsible for clearing
|
||||
* this status. In that case, the signaling device may not even be
|
||||
* visible to the OS.
|
||||
*/
|
||||
if (host->native_aer || pcie_ports_native) {
|
||||
pcie_clear_device_status(bridge);
|
||||
pci_aer_clear_nonfatal_status(bridge);
|
||||
}
|
||||
pci_info(bridge, "device recovery successful\n");
|
||||
return status;
|
||||
|
||||
failed:
|
||||
pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
|
||||
pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
|
||||
|
||||
/* TODO: Should kernel panic here? */
|
||||
pci_info(dev, "device recovery failed\n");
|
||||
pci_info(bridge, "device recovery failed\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -310,7 +310,10 @@ static int pcie_pme_can_wakeup(struct pci_dev *dev, void *ign)
|
||||
static void pcie_pme_mark_devices(struct pci_dev *port)
|
||||
{
|
||||
pcie_pme_can_wakeup(port, NULL);
|
||||
if (port->subordinate)
|
||||
|
||||
if (pci_pcie_type(port) == PCI_EXP_TYPE_RC_EC)
|
||||
pcie_walk_rcec(port, pcie_pme_can_wakeup, NULL);
|
||||
else if (port->subordinate)
|
||||
pci_walk_bus(port->subordinate, pcie_pme_can_wakeup, NULL);
|
||||
}
|
||||
|
||||
@ -320,10 +323,16 @@ static void pcie_pme_mark_devices(struct pci_dev *port)
|
||||
*/
|
||||
static int pcie_pme_probe(struct pcie_device *srv)
|
||||
{
|
||||
struct pci_dev *port;
|
||||
struct pci_dev *port = srv->port;
|
||||
struct pcie_pme_service_data *data;
|
||||
int type = pci_pcie_type(port);
|
||||
int ret;
|
||||
|
||||
/* Limit to Root Ports or Root Complex Event Collectors */
|
||||
if (type != PCI_EXP_TYPE_RC_EC &&
|
||||
type != PCI_EXP_TYPE_ROOT_PORT)
|
||||
return -ENODEV;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
@ -333,7 +342,6 @@ static int pcie_pme_probe(struct pcie_device *srv)
|
||||
data->srv = srv;
|
||||
set_service_data(srv, data);
|
||||
|
||||
port = srv->port;
|
||||
pcie_pme_interrupt_enable(port, false);
|
||||
pcie_clear_root_pme_status(port);
|
||||
|
||||
@ -445,7 +453,7 @@ static void pcie_pme_remove(struct pcie_device *srv)
|
||||
|
||||
static struct pcie_port_service_driver pcie_pme_driver = {
|
||||
.name = "pcie_pme",
|
||||
.port_type = PCI_EXP_TYPE_ROOT_PORT,
|
||||
.port_type = PCIE_ANY_PORT,
|
||||
.service = PCIE_PORT_SERVICE_PME,
|
||||
|
||||
.probe = pcie_pme_probe,
|
||||
|
@ -233,12 +233,9 @@ static int get_port_device_capability(struct pci_dev *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Root ports are capable of generating PME too. Root Complex
|
||||
* Event Collectors can also generate PMEs, but we don't handle
|
||||
* those yet.
|
||||
*/
|
||||
if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT &&
|
||||
/* Root Ports and Root Complex Event Collectors may generate PMEs */
|
||||
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
|
||||
pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC) &&
|
||||
(pcie_ports_native || host->native_pme)) {
|
||||
services |= PCIE_PORT_SERVICE_PME;
|
||||
|
||||
|
@ -101,14 +101,19 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
|
||||
static int pcie_portdrv_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int type = pci_pcie_type(dev);
|
||||
int status;
|
||||
|
||||
if (!pci_is_pcie(dev) ||
|
||||
((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
(pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM) &&
|
||||
(pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
|
||||
((type != PCI_EXP_TYPE_ROOT_PORT) &&
|
||||
(type != PCI_EXP_TYPE_UPSTREAM) &&
|
||||
(type != PCI_EXP_TYPE_DOWNSTREAM) &&
|
||||
(type != PCI_EXP_TYPE_RC_EC)))
|
||||
return -ENODEV;
|
||||
|
||||
if (type == PCI_EXP_TYPE_RC_EC)
|
||||
pcie_link_rcec(dev);
|
||||
|
||||
status = pcie_port_device_register(dev);
|
||||
if (status)
|
||||
return status;
|
||||
@ -195,6 +200,8 @@ static const struct pci_device_id port_pci_ids[] = {
|
||||
{ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0) },
|
||||
/* subtractive decode PCI-to-PCI bridge, class type is 060401h */
|
||||
{ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x01), ~0) },
|
||||
/* handle any Root Complex Event Collector */
|
||||
{ PCI_DEVICE_CLASS(((PCI_CLASS_SYSTEM_RCEC << 8) | 0x00), ~0) },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,64 @@ static void pci_ptm_info(struct pci_dev *dev)
|
||||
dev->ptm_root ? " (root)" : "", clock_desc);
|
||||
}
|
||||
|
||||
void pci_disable_ptm(struct pci_dev *dev)
|
||||
{
|
||||
int ptm;
|
||||
u16 ctrl;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
|
||||
if (!ptm)
|
||||
return;
|
||||
|
||||
pci_read_config_word(dev, ptm + PCI_PTM_CTRL, &ctrl);
|
||||
ctrl &= ~(PCI_PTM_CTRL_ENABLE | PCI_PTM_CTRL_ROOT);
|
||||
pci_write_config_word(dev, ptm + PCI_PTM_CTRL, ctrl);
|
||||
}
|
||||
|
||||
void pci_save_ptm_state(struct pci_dev *dev)
|
||||
{
|
||||
int ptm;
|
||||
struct pci_cap_saved_state *save_state;
|
||||
u16 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
|
||||
if (!ptm)
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
|
||||
if (!save_state) {
|
||||
pci_err(dev, "no suspend buffer for PTM\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cap = (u16 *)&save_state->cap.data[0];
|
||||
pci_read_config_word(dev, ptm + PCI_PTM_CTRL, cap);
|
||||
}
|
||||
|
||||
void pci_restore_ptm_state(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_cap_saved_state *save_state;
|
||||
int ptm;
|
||||
u16 *cap;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_PTM);
|
||||
ptm = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PTM);
|
||||
if (!save_state || !ptm)
|
||||
return;
|
||||
|
||||
cap = (u16 *)&save_state->cap.data[0];
|
||||
pci_write_config_word(dev, ptm + PCI_PTM_CTRL, *cap);
|
||||
}
|
||||
|
||||
void pci_ptm_init(struct pci_dev *dev)
|
||||
{
|
||||
int pos;
|
||||
@ -65,6 +123,8 @@ void pci_ptm_init(struct pci_dev *dev)
|
||||
if (!pos)
|
||||
return;
|
||||
|
||||
pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u16));
|
||||
|
||||
pci_read_config_dword(dev, pos + PCI_PTM_CAP, &cap);
|
||||
local_clock = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
|
||||
|
||||
|
190
drivers/pci/pcie/rcec.c
Normal file
190
drivers/pci/pcie/rcec.c
Normal file
@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Root Complex Event Collector Support
|
||||
*
|
||||
* Authors:
|
||||
* Sean V Kelley <sean.v.kelley@intel.com>
|
||||
* Qiuxu Zhuo <qiuxu.zhuo@intel.com>
|
||||
*
|
||||
* Copyright (C) 2020 Intel Corp.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_regs.h>
|
||||
|
||||
#include "../pci.h"
|
||||
|
||||
struct walk_rcec_data {
|
||||
struct pci_dev *rcec;
|
||||
int (*user_callback)(struct pci_dev *dev, void *data);
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
static bool rcec_assoc_rciep(struct pci_dev *rcec, struct pci_dev *rciep)
|
||||
{
|
||||
unsigned long bitmap = rcec->rcec_ea->bitmap;
|
||||
unsigned int devn;
|
||||
|
||||
/* An RCiEP found on a different bus in range */
|
||||
if (rcec->bus->number != rciep->bus->number)
|
||||
return true;
|
||||
|
||||
/* Same bus, so check bitmap */
|
||||
for_each_set_bit(devn, &bitmap, 32)
|
||||
if (devn == rciep->devfn)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int link_rcec_helper(struct pci_dev *dev, void *data)
|
||||
{
|
||||
struct walk_rcec_data *rcec_data = data;
|
||||
struct pci_dev *rcec = rcec_data->rcec;
|
||||
|
||||
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) &&
|
||||
rcec_assoc_rciep(rcec, dev)) {
|
||||
dev->rcec = rcec;
|
||||
pci_dbg(dev, "PME & error events signaled via %s\n",
|
||||
pci_name(rcec));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int walk_rcec_helper(struct pci_dev *dev, void *data)
|
||||
{
|
||||
struct walk_rcec_data *rcec_data = data;
|
||||
struct pci_dev *rcec = rcec_data->rcec;
|
||||
|
||||
if ((pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) &&
|
||||
rcec_assoc_rciep(rcec, dev))
|
||||
rcec_data->user_callback(dev, rcec_data->user_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void walk_rcec(int (*cb)(struct pci_dev *dev, void *data),
|
||||
void *userdata)
|
||||
{
|
||||
struct walk_rcec_data *rcec_data = userdata;
|
||||
struct pci_dev *rcec = rcec_data->rcec;
|
||||
u8 nextbusn, lastbusn;
|
||||
struct pci_bus *bus;
|
||||
unsigned int bnr;
|
||||
|
||||
if (!rcec->rcec_ea)
|
||||
return;
|
||||
|
||||
/* Walk own bus for bitmap based association */
|
||||
pci_walk_bus(rcec->bus, cb, rcec_data);
|
||||
|
||||
nextbusn = rcec->rcec_ea->nextbusn;
|
||||
lastbusn = rcec->rcec_ea->lastbusn;
|
||||
|
||||
/* All RCiEP devices are on the same bus as the RCEC */
|
||||
if (nextbusn == 0xff && lastbusn == 0x00)
|
||||
return;
|
||||
|
||||
for (bnr = nextbusn; bnr <= lastbusn; bnr++) {
|
||||
/* No association indicated (PCIe 5.0-1, 7.9.10.3) */
|
||||
if (bnr == rcec->bus->number)
|
||||
continue;
|
||||
|
||||
bus = pci_find_bus(pci_domain_nr(rcec->bus), bnr);
|
||||
if (!bus)
|
||||
continue;
|
||||
|
||||
/* Find RCiEP devices on the given bus ranges */
|
||||
pci_walk_bus(bus, cb, rcec_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pcie_link_rcec - Link RCiEP devices associated with RCEC.
|
||||
* @rcec: RCEC whose RCiEP devices should be linked.
|
||||
*
|
||||
* Link the given RCEC to each RCiEP device found.
|
||||
*/
|
||||
void pcie_link_rcec(struct pci_dev *rcec)
|
||||
{
|
||||
struct walk_rcec_data rcec_data;
|
||||
|
||||
if (!rcec->rcec_ea)
|
||||
return;
|
||||
|
||||
rcec_data.rcec = rcec;
|
||||
rcec_data.user_callback = NULL;
|
||||
rcec_data.user_data = NULL;
|
||||
|
||||
walk_rcec(link_rcec_helper, &rcec_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* pcie_walk_rcec - Walk RCiEP devices associating with RCEC and call callback.
|
||||
* @rcec: RCEC whose RCiEP devices should be walked
|
||||
* @cb: Callback to be called for each RCiEP device found
|
||||
* @userdata: Arbitrary pointer to be passed to callback
|
||||
*
|
||||
* Walk the given RCEC. Call the callback on each RCiEP found.
|
||||
*
|
||||
* If @cb returns anything other than 0, break out.
|
||||
*/
|
||||
void pcie_walk_rcec(struct pci_dev *rcec, int (*cb)(struct pci_dev *, void *),
|
||||
void *userdata)
|
||||
{
|
||||
struct walk_rcec_data rcec_data;
|
||||
|
||||
if (!rcec->rcec_ea)
|
||||
return;
|
||||
|
||||
rcec_data.rcec = rcec;
|
||||
rcec_data.user_callback = cb;
|
||||
rcec_data.user_data = userdata;
|
||||
|
||||
walk_rcec(walk_rcec_helper, &rcec_data);
|
||||
}
|
||||
|
||||
void pci_rcec_init(struct pci_dev *dev)
|
||||
{
|
||||
struct rcec_ea *rcec_ea;
|
||||
u32 rcec, hdr, busn;
|
||||
u8 ver;
|
||||
|
||||
/* Only for Root Complex Event Collectors */
|
||||
if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_EC)
|
||||
return;
|
||||
|
||||
rcec = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_RCEC);
|
||||
if (!rcec)
|
||||
return;
|
||||
|
||||
rcec_ea = kzalloc(sizeof(*rcec_ea), GFP_KERNEL);
|
||||
if (!rcec_ea)
|
||||
return;
|
||||
|
||||
pci_read_config_dword(dev, rcec + PCI_RCEC_RCIEP_BITMAP,
|
||||
&rcec_ea->bitmap);
|
||||
|
||||
/* Check whether RCEC BUSN register is present */
|
||||
pci_read_config_dword(dev, rcec, &hdr);
|
||||
ver = PCI_EXT_CAP_VER(hdr);
|
||||
if (ver >= PCI_RCEC_BUSN_REG_VER) {
|
||||
pci_read_config_dword(dev, rcec + PCI_RCEC_BUSN, &busn);
|
||||
rcec_ea->nextbusn = PCI_RCEC_BUSN_NEXT(busn);
|
||||
rcec_ea->lastbusn = PCI_RCEC_BUSN_LAST(busn);
|
||||
} else {
|
||||
/* Avoid later ver check by setting nextbusn */
|
||||
rcec_ea->nextbusn = 0xff;
|
||||
rcec_ea->lastbusn = 0x00;
|
||||
}
|
||||
|
||||
dev->rcec_ea = rcec_ea;
|
||||
}
|
||||
|
||||
void pci_rcec_exit(struct pci_dev *dev)
|
||||
{
|
||||
kfree(dev->rcec_ea);
|
||||
dev->rcec_ea = NULL;
|
||||
}
|
@ -165,7 +165,7 @@ static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)
|
||||
#define PCI_COMMAND_DECODE_ENABLE (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
|
||||
|
||||
/**
|
||||
* pci_read_base - Read a PCI BAR
|
||||
* __pci_read_base - Read a PCI BAR
|
||||
* @dev: the PCI device
|
||||
* @type: type of the BAR
|
||||
* @res: resource buffer to be filled in
|
||||
@ -677,7 +677,7 @@ const unsigned char pcie_link_speed[] = {
|
||||
PCIE_SPEED_8_0GT, /* 3 */
|
||||
PCIE_SPEED_16_0GT, /* 4 */
|
||||
PCIE_SPEED_32_0GT, /* 5 */
|
||||
PCI_SPEED_UNKNOWN, /* 6 */
|
||||
PCIE_SPEED_64_0GT, /* 6 */
|
||||
PCI_SPEED_UNKNOWN, /* 7 */
|
||||
PCI_SPEED_UNKNOWN, /* 8 */
|
||||
PCI_SPEED_UNKNOWN, /* 9 */
|
||||
@ -719,6 +719,7 @@ const char *pci_speed_string(enum pci_bus_speed speed)
|
||||
"8.0 GT/s PCIe", /* 0x16 */
|
||||
"16.0 GT/s PCIe", /* 0x17 */
|
||||
"32.0 GT/s PCIe", /* 0x18 */
|
||||
"64.0 GT/s PCIe", /* 0x19 */
|
||||
};
|
||||
|
||||
if (speed < ARRAY_SIZE(speed_strings))
|
||||
@ -1612,7 +1613,7 @@ static bool pci_ext_cfg_is_aliased(struct pci_dev *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_cfg_space_size - Get the configuration space size of the PCI device
|
||||
* pci_cfg_space_size_ext - Get the configuration space size of the PCI device
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Regular PCI devices have 256 bytes, but PCI-X 2 and PCI Express devices
|
||||
@ -1716,22 +1717,6 @@ static u8 pci_hdr_type(struct pci_dev *dev)
|
||||
|
||||
#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
|
||||
|
||||
static void pci_msi_setup_pci_dev(struct pci_dev *dev)
|
||||
{
|
||||
/*
|
||||
* Disable the MSI hardware to avoid screaming interrupts
|
||||
* during boot. This is the power on reset default so
|
||||
* usually this should be a noop.
|
||||
*/
|
||||
dev->msi_cap = pci_find_capability(dev, PCI_CAP_ID_MSI);
|
||||
if (dev->msi_cap)
|
||||
pci_msi_set_enable(dev, 0);
|
||||
|
||||
dev->msix_cap = pci_find_capability(dev, PCI_CAP_ID_MSIX);
|
||||
if (dev->msix_cap)
|
||||
pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_intx_mask_broken - Test PCI_COMMAND_INTX_DISABLE writability
|
||||
* @dev: PCI device
|
||||
@ -2216,6 +2201,7 @@ static void pci_configure_device(struct pci_dev *dev)
|
||||
static void pci_release_capabilities(struct pci_dev *dev)
|
||||
{
|
||||
pci_aer_exit(dev);
|
||||
pci_rcec_exit(dev);
|
||||
pci_vpd_release(dev);
|
||||
pci_iov_release(dev);
|
||||
pci_free_cap_save_buffers(dev);
|
||||
@ -2397,9 +2383,8 @@ void pcie_report_downtraining(struct pci_dev *dev)
|
||||
static void pci_init_capabilities(struct pci_dev *dev)
|
||||
{
|
||||
pci_ea_init(dev); /* Enhanced Allocation */
|
||||
|
||||
/* Setup MSI caps & disable MSI/MSI-X interrupts */
|
||||
pci_msi_setup_pci_dev(dev);
|
||||
pci_msi_init(dev); /* Disable MSI */
|
||||
pci_msix_init(dev); /* Disable MSI-X */
|
||||
|
||||
/* Buffers for saving PCIe and PCI-X capabilities */
|
||||
pci_allocate_cap_save_buffers(dev);
|
||||
@ -2415,6 +2400,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
|
||||
pci_ptm_init(dev); /* Precision Time Measurement */
|
||||
pci_aer_init(dev); /* Advanced Error Reporting */
|
||||
pci_dpc_init(dev); /* Downstream Port Containment */
|
||||
pci_rcec_init(dev); /* Root Complex Event Collector */
|
||||
|
||||
pcie_report_downtraining(dev);
|
||||
|
||||
|
@ -2356,9 +2356,9 @@ static void quirk_enable_clear_retrain_link(struct pci_dev *dev)
|
||||
dev->clear_retrain_link = 1;
|
||||
pci_info(dev, "Enable PCIe Retrain Link quirk\n");
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe110, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe111, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe130, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe110, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe111, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PERICOM, 0xe130, quirk_enable_clear_retrain_link);
|
||||
|
||||
static void fixup_rev1_53c810(struct pci_dev *dev)
|
||||
{
|
||||
@ -2522,6 +2522,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SAMSUNG, 0xa5e3, quirk_disable_all_msi);
|
||||
|
||||
/* Disable MSI on chipsets that are known to not support it */
|
||||
static void quirk_disable_msi(struct pci_dev *dev)
|
||||
@ -3998,6 +3999,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9183,
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c46 */
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x91a0,
|
||||
quirk_dma_func1_alias);
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c135 */
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9215,
|
||||
quirk_dma_func1_alias);
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=42679#c127 */
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9220,
|
||||
quirk_dma_func1_alias);
|
||||
@ -5164,6 +5168,18 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
|
||||
(pdev->device == 0x7340 && pdev->revision != 0xc5))
|
||||
return;
|
||||
|
||||
if (pdev->device == 0x15d8) {
|
||||
if (pdev->revision == 0xcf &&
|
||||
pdev->subsystem_vendor == 0xea50 &&
|
||||
(pdev->subsystem_device == 0xce19 ||
|
||||
pdev->subsystem_device == 0xcc10 ||
|
||||
pdev->subsystem_device == 0xcc08))
|
||||
goto no_ats;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
no_ats:
|
||||
pci_info(pdev, "disabling ATS\n");
|
||||
pdev->ats_cap = 0;
|
||||
}
|
||||
@ -5176,6 +5192,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
|
||||
/* AMD Navi14 dGPU */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
|
||||
/* AMD Raven platform iGPU */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
|
||||
#endif /* CONFIG_PCI_ATS */
|
||||
|
||||
/* Freescale PCIe doesn't support MSI in RC mode */
|
||||
@ -5567,17 +5585,26 @@ static void pci_fixup_no_d0_pme(struct pci_dev *dev)
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASMEDIA, 0x2142, pci_fixup_no_d0_pme);
|
||||
|
||||
/*
|
||||
* Device [12d8:0x400e] and [12d8:0x400f]
|
||||
* Device 12d8:0x400e [OHCI] and 12d8:0x400f [EHCI]
|
||||
*
|
||||
* These devices advertise PME# support in all power states but don't
|
||||
* reliably assert it.
|
||||
*
|
||||
* These devices also advertise MSI, but documentation (PI7C9X440SL.pdf)
|
||||
* says "The MSI Function is not implemented on this device" in chapters
|
||||
* 7.3.27, 7.3.29-7.3.31.
|
||||
*/
|
||||
static void pci_fixup_no_pme(struct pci_dev *dev)
|
||||
static void pci_fixup_no_msi_no_pme(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
pci_info(dev, "MSI is not implemented on this device, disabling it\n");
|
||||
dev->no_msi = 1;
|
||||
#endif
|
||||
pci_info(dev, "PME# is unreliable, disabling it\n");
|
||||
dev->pme_support = 0;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400e, pci_fixup_no_pme);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400f, pci_fixup_no_pme);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400e, pci_fixup_no_msi_no_pme);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_PERICOM, 0x400f, pci_fixup_no_msi_no_pme);
|
||||
|
||||
static void apex_pci_fixup_class(struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -272,6 +272,9 @@ placeholder:
|
||||
goto err;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&slot->list);
|
||||
list_add(&slot->list, &parent->slots);
|
||||
|
||||
err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL,
|
||||
"%s", slot_name);
|
||||
if (err) {
|
||||
@ -279,9 +282,6 @@ placeholder:
|
||||
goto err;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&slot->list);
|
||||
list_add(&slot->list, &parent->slots);
|
||||
|
||||
down_read(&pci_bus_sem);
|
||||
list_for_each_entry(dev, &parent->devices, bus_list)
|
||||
if (PCI_SLOT(dev->devfn) == slot_nr)
|
||||
@ -323,7 +323,7 @@ EXPORT_SYMBOL_GPL(pci_destroy_slot);
|
||||
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
|
||||
#include <linux/pci_hotplug.h>
|
||||
/**
|
||||
* pci_hp_create_link - create symbolic link to the hotplug driver module.
|
||||
* pci_hp_create_module_link - create symbolic link to hotplug driver module
|
||||
* @pci_slot: struct pci_slot
|
||||
*
|
||||
* Helper function for pci_hotplug_core.c to create symbolic link to
|
||||
@ -349,7 +349,8 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
|
||||
EXPORT_SYMBOL_GPL(pci_hp_create_module_link);
|
||||
|
||||
/**
|
||||
* pci_hp_remove_link - remove symbolic link to the hotplug driver module.
|
||||
* pci_hp_remove_module_link - remove symbolic link to the hotplug driver
|
||||
* module.
|
||||
* @pci_slot: struct pci_slot
|
||||
*
|
||||
* Helper function for pci_hotplug_core.c to remove symbolic link to
|
||||
|
@ -9,6 +9,33 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* Memory address shift values for the byte-level address that
|
||||
* can be used when accessing the PCI Express Configuration Space.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enhanced Configuration Access Mechanism (ECAM)
|
||||
*
|
||||
* See PCI Express Base Specification, Revision 5.0, Version 1.0,
|
||||
* Section 7.2.2, Table 7-1, p. 677.
|
||||
*/
|
||||
#define PCIE_ECAM_BUS_SHIFT 20 /* Bus number */
|
||||
#define PCIE_ECAM_DEVFN_SHIFT 12 /* Device and Function number */
|
||||
|
||||
#define PCIE_ECAM_BUS_MASK 0xff
|
||||
#define PCIE_ECAM_DEVFN_MASK 0xff
|
||||
#define PCIE_ECAM_REG_MASK 0xfff /* Limit offset to a maximum of 4K */
|
||||
|
||||
#define PCIE_ECAM_BUS(x) (((x) & PCIE_ECAM_BUS_MASK) << PCIE_ECAM_BUS_SHIFT)
|
||||
#define PCIE_ECAM_DEVFN(x) (((x) & PCIE_ECAM_DEVFN_MASK) << PCIE_ECAM_DEVFN_SHIFT)
|
||||
#define PCIE_ECAM_REG(x) ((x) & PCIE_ECAM_REG_MASK)
|
||||
|
||||
#define PCIE_ECAM_OFFSET(bus, devfn, where) \
|
||||
(PCIE_ECAM_BUS(bus) | \
|
||||
PCIE_ECAM_DEVFN(devfn) | \
|
||||
PCIE_ECAM_REG(where))
|
||||
|
||||
/*
|
||||
* struct to hold pci ops and bus shift of the config window
|
||||
* for a PCI controller.
|
||||
|
@ -281,6 +281,7 @@ enum pci_bus_speed {
|
||||
PCIE_SPEED_8_0GT = 0x16,
|
||||
PCIE_SPEED_16_0GT = 0x17,
|
||||
PCIE_SPEED_32_0GT = 0x18,
|
||||
PCIE_SPEED_64_0GT = 0x19,
|
||||
PCI_SPEED_UNKNOWN = 0xff,
|
||||
};
|
||||
|
||||
@ -304,6 +305,7 @@ struct pcie_link_state;
|
||||
struct pci_vpd;
|
||||
struct pci_sriov;
|
||||
struct pci_p2pdma;
|
||||
struct rcec_ea;
|
||||
|
||||
/* The pci_dev structure describes PCI devices */
|
||||
struct pci_dev {
|
||||
@ -326,6 +328,10 @@ struct pci_dev {
|
||||
#ifdef CONFIG_PCIEAER
|
||||
u16 aer_cap; /* AER capability offset */
|
||||
struct aer_stats *aer_stats; /* AER stats for this device */
|
||||
#endif
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
struct rcec_ea *rcec_ea; /* RCEC cached endpoint association */
|
||||
struct pci_dev *rcec; /* Associated RCEC device */
|
||||
#endif
|
||||
u8 pcie_cap; /* PCIe capability offset */
|
||||
u8 msi_cap; /* MSI capability offset */
|
||||
@ -380,7 +386,7 @@ struct pci_dev {
|
||||
struct pcie_link_state *link_state; /* ASPM link state */
|
||||
unsigned int ltr_path:1; /* Latency Tolerance Reporting
|
||||
supported from root to here */
|
||||
int l1ss; /* L1SS Capability pointer */
|
||||
u16 l1ss; /* L1SS Capability pointer */
|
||||
#endif
|
||||
unsigned int eetlp_prefix_path:1; /* End-to-End TLP Prefix */
|
||||
|
||||
@ -1063,12 +1069,13 @@ void pci_sort_breadthfirst(void);
|
||||
|
||||
/* Generic PCI functions exported to card drivers */
|
||||
|
||||
int pci_find_capability(struct pci_dev *dev, int cap);
|
||||
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
|
||||
int pci_find_ext_capability(struct pci_dev *dev, int cap);
|
||||
int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap);
|
||||
int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
|
||||
int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
|
||||
u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
|
||||
u8 pci_find_capability(struct pci_dev *dev, int cap);
|
||||
u8 pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap);
|
||||
u8 pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
|
||||
u8 pci_find_next_ht_capability(struct pci_dev *dev, u8 pos, int ht_cap);
|
||||
u16 pci_find_ext_capability(struct pci_dev *dev, int cap);
|
||||
u16 pci_find_next_ext_capability(struct pci_dev *dev, u16 pos, int cap);
|
||||
struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
|
||||
|
||||
u64 pci_get_dsn(struct pci_dev *dev);
|
||||
@ -1190,7 +1197,6 @@ void pci_clear_master(struct pci_dev *dev);
|
||||
|
||||
int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
|
||||
int pci_set_cacheline_size(struct pci_dev *dev);
|
||||
#define HAVE_PCI_SET_MWI
|
||||
int __must_check pci_set_mwi(struct pci_dev *dev);
|
||||
int __must_check pcim_set_mwi(struct pci_dev *dev);
|
||||
int pci_try_set_mwi(struct pci_dev *dev);
|
||||
@ -1271,7 +1277,7 @@ bool pci_dev_run_wake(struct pci_dev *dev);
|
||||
void pci_d3cold_enable(struct pci_dev *dev);
|
||||
void pci_d3cold_disable(struct pci_dev *dev);
|
||||
bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
|
||||
void pci_wakeup_bus(struct pci_bus *bus);
|
||||
void pci_resume_bus(struct pci_bus *bus);
|
||||
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
|
||||
|
||||
/* For use by arch with custom probe code */
|
||||
@ -1279,7 +1285,6 @@ void set_pcie_port_type(struct pci_dev *pdev);
|
||||
void set_pcie_hotplug_bridge(struct pci_dev *pdev);
|
||||
|
||||
/* Functions for PCI Hotplug drivers to use */
|
||||
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap);
|
||||
unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge);
|
||||
unsigned int pci_rescan_bus(struct pci_bus *bus);
|
||||
void pci_lock_rescan_remove(void);
|
||||
@ -1719,7 +1724,7 @@ static inline int __pci_register_driver(struct pci_driver *drv,
|
||||
static inline int pci_register_driver(struct pci_driver *drv)
|
||||
{ return 0; }
|
||||
static inline void pci_unregister_driver(struct pci_driver *drv) { }
|
||||
static inline int pci_find_capability(struct pci_dev *dev, int cap)
|
||||
static inline u8 pci_find_capability(struct pci_dev *dev, int cap)
|
||||
{ return 0; }
|
||||
static inline int pci_find_next_capability(struct pci_dev *dev, u8 post,
|
||||
int cap)
|
||||
|
@ -81,6 +81,7 @@
|
||||
#define PCI_CLASS_SYSTEM_RTC 0x0803
|
||||
#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804
|
||||
#define PCI_CLASS_SYSTEM_SDHCI 0x0805
|
||||
#define PCI_CLASS_SYSTEM_RCEC 0x0807
|
||||
#define PCI_CLASS_SYSTEM_OTHER 0x0880
|
||||
|
||||
#define PCI_BASE_CLASS_INPUT 0x09
|
||||
|
@ -531,6 +531,7 @@
|
||||
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
|
||||
#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
|
||||
#define PCI_EXP_LNKCAP_SLS_32_0GB 0x00000005 /* LNKCAP2 SLS Vector bit 4 */
|
||||
#define PCI_EXP_LNKCAP_SLS_64_0GB 0x00000006 /* LNKCAP2 SLS Vector bit 5 */
|
||||
#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */
|
||||
#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */
|
||||
#define PCI_EXP_LNKCAP_ASPM_L0S 0x00000400 /* ASPM L0s Support */
|
||||
@ -562,6 +563,7 @@
|
||||
#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
|
||||
#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
|
||||
#define PCI_EXP_LNKSTA_CLS_32_0GB 0x0005 /* Current Link Speed 32.0GT/s */
|
||||
#define PCI_EXP_LNKSTA_CLS_64_0GB 0x0006 /* Current Link Speed 64.0GT/s */
|
||||
#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */
|
||||
#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */
|
||||
#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */
|
||||
@ -670,6 +672,7 @@
|
||||
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
|
||||
#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
|
||||
#define PCI_EXP_LNKCAP2_SLS_32_0GB 0x00000020 /* Supported Speed 32GT/s */
|
||||
#define PCI_EXP_LNKCAP2_SLS_64_0GB 0x00000040 /* Supported Speed 64GT/s */
|
||||
#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */
|
||||
#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */
|
||||
#define PCI_EXP_LNKCTL2_TLS 0x000f
|
||||
@ -678,6 +681,7 @@
|
||||
#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */
|
||||
#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */
|
||||
#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
|
||||
#define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */
|
||||
#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */
|
||||
#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
|
||||
#define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */
|
||||
@ -832,6 +836,13 @@
|
||||
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
|
||||
#define PCI_EXT_CAP_PWR_SIZEOF 16
|
||||
|
||||
/* Root Complex Event Collector Endpoint Association */
|
||||
#define PCI_RCEC_RCIEP_BITMAP 4 /* Associated Bitmap for RCiEPs */
|
||||
#define PCI_RCEC_BUSN 8 /* RCEC Associated Bus Numbers */
|
||||
#define PCI_RCEC_BUSN_REG_VER 0x02 /* Least version with BUSN present */
|
||||
#define PCI_RCEC_BUSN_NEXT(x) (((x) >> 8) & 0xff)
|
||||
#define PCI_RCEC_BUSN_LAST(x) (((x) >> 16) & 0xff)
|
||||
|
||||
/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */
|
||||
#define PCI_VNDR_HEADER 4 /* Vendor-Specific Header */
|
||||
#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff)
|
||||
|
Loading…
Reference in New Issue
Block a user