提交 3925c3bb 编写于 作者: L Linus Torvalds

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

Pull PCI updates from Bjorn Helgaas:
 "Enumeration:

   - Program MPS for RCiEP devices (Ashok Raj)

   - Fix pci_register_host_bridge() device_register() error handling
     (Rob Herring)

   - Fix pci_host_bridge struct device release/free handling (Rob
     Herring)

  Resource management:

   - Allow resizing BARs for devices on root bus (Ard Biesheuvel)

  Power management:

   - Reduce Thunderbolt resume time by working around devices that don't
     support DLL Link Active reporting (Mika Westerberg)

   - Work around a Pericom USB controller OHCI/EHCI PME# defect
     (Kai-Heng Feng)

  Virtualization:

   - Add ACS quirk for Intel Root Complex Integrated Endpoints (Ashok
     Raj)

   - Avoid FLR for AMD Starship USB 3.0 (Kevin Buettner)

   - Avoid FLR for AMD Matisse HD Audio & USB 3.0 (Marcos Scriven)

  Error handling:

   - Use only _OSC (not HEST FIRMWARE_FIRST) to determine AER ownership
     (Alexandru Gagniuc, Kuppuswamy Sathyanarayanan)

   - Reduce verbosity by logging only ACPI_NOTIFY_DISCONNECT_RECOVER
     events (Kuppuswamy Sathyanarayanan)

   - Don't enable AER by default in Kconfig (Bjorn Helgaas)

  Peer-to-peer DMA:

   - Add AMD Zen Raven and Renoir Root Ports to whitelist (Alex Deucher)

  ASPM:

   - Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges (Kai-Heng Feng)

  Endpoint framework:

   - Fix DMA channel release in test (Kunihiko Hayashi)

   - Add page size as argument to pci_epc_mem_init() (Lad Prabhakar)

   - Add support to handle multiple base for mapping outbound memory
     (Lad Prabhakar)

  Generic host bridge driver:

   - Support building as module (Rob Herring)

   - Eliminate pci_host_common_probe wrappers (Rob Herring)

  Amlogic Meson PCIe controller driver:

   - Don't use FAST_LINK_MODE to set up link (Marc Zyngier)

  Broadcom STB PCIe controller driver:

   - Disable ASPM L0s if 'aspm-no-l0s' in DT (Jim Quinlan)

   - Fix clk_put() error (Jim Quinlan)

   - Fix window register offset (Jim Quinlan)

   - Assert fundamental reset on initialization (Nicolas Saenz Julienne)

   - Add notify xHCI reset property (Nicolas Saenz Julienne)

   - Add init routine for Raspberry Pi 4 VL805 USB controller (Nicolas
     Saenz Julienne)

   - Sync with Raspberry Pi 4 firmware for VL805 initialization (Nicolas
     Saenz Julienne)

  Cadence PCIe controller driver:

   - Remove "cdns,max-outbound-regions" DT property (replaced by
     "ranges") (Kishon Vijay Abraham I)

   - Read 32-bit (not 16-bit) Vendor ID/Device ID property from DT
     (Kishon Vijay Abraham I)

  Marvell Aardvark PCIe controller driver:

   - Improve link training (Marek Behún)

   - Add PHY support (Marek Behún)

   - Add "phys", "max-link-speed", "reset-gpios" to dt-binding (Marek
     Behún)

   - Train link immediately after enabling training to work around
     detection issues with some cards (Pali Rohár)

   - Issue PERST via GPIO to work around detection issues (Pali Rohár)

   - Don't blindly enable ASPM L0s (Pali Rohár)

   - Replace custom macros by standard linux/pci_regs.h macros (Pali
     Rohár)

  Microsoft Hyper-V host bridge driver:

   - Fix probe failure path to release resource (Wei Hu)

   - Retry PCI bus D0 entry on invalid device state for kdump (Wei Hu)

  Renesas R-Car PCIe controller driver:

   - Fix incorrect programming of OB windows (Andrew Murray)

   - Add suspend/resume (Kazufumi Ikeda)

   - Rename pcie-rcar.c to pcie-rcar-host.c (Lad Prabhakar)

   - Add endpoint controller driver (Lad Prabhakar)

   - Fix PCIEPAMR mask calculation (Lad Prabhakar)

   - Add r8a77961 to DT binding (Yoshihiro Shimoda)

  Socionext UniPhier Pro5 controller driver:

   - Add endpoint controller driver (Kunihiko Hayashi)

  Synopsys DesignWare PCIe controller driver:

   - Program outbound ATU upper limit register (Alan Mikhak)

   - Fix inner MSI IRQ domain registration (Marc Zyngier)

  Miscellaneous:

   - Check for platform_get_irq() failure consistently (negative return
     means failure) (Aman Sharma)

   - Fix several runtime PM get/put imbalances (Dinghao Liu)

   - Use flexible-array and struct_size() helpers for code cleanup
     (Gustavo A. R. Silva)

   - Update & fix issues in bridge emulation of PCIe registers (Jon
     Derrick)

   - Add macros for bridge window names (PCI_BRIDGE_IO_WINDOW, etc)
     (Krzysztof Wilczyński)

   - Work around Intel PCH MROMs that have invalid BARs (Xiaochun Lee)"

* tag 'pci-v5.8-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (100 commits)
  PCI: uniphier: Add Socionext UniPhier Pro5 PCIe endpoint controller driver
  PCI: Add ACS quirk for Intel Root Complex Integrated Endpoints
  PCI/DPC: Print IRQ number used by port
  PCI/AER: Use "aer" variable for capability offset
  PCI/AER: Remove redundant dev->aer_cap checks
  PCI/AER: Remove redundant pci_is_pcie() checks
  PCI/AER: Remove HEST/FIRMWARE_FIRST parsing for AER ownership
  PCI: tegra: Fix runtime PM imbalance on error
  PCI: vmd: Filter resource type bits from shadow register
  PCI: tegra194: Fix runtime PM imbalance on error
  dt-bindings: PCI: Add UniPhier PCIe endpoint controller description
  PCI: hv: Use struct_size() helper
  PCI: Rename _DSM constants to align with spec
  PCI: Avoid FLR for AMD Starship USB 3.0
  PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0
  x86/PCI: Drop unused xen_register_pirq() gsi_override parameter
  PCI: dwc: Use private data pointer of "struct irq_domain" to get pcie_port
  PCI: amlogic: meson: Don't use FAST_LINK_MODE to set up link
  PCI: dwc: Fix inner MSI IRQ domain registration
  PCI: dwc: pci-dra7xx: Use devm_platform_ioremap_resource_byname()
  ...
...@@ -78,8 +78,8 @@ by the PCI controller driver. ...@@ -78,8 +78,8 @@ by the PCI controller driver.
Cleanup the pci_epc_mem structure allocated during pci_epc_mem_init(). Cleanup the pci_epc_mem structure allocated during pci_epc_mem_init().
APIs for the PCI Endpoint Function Driver EPC APIs for the PCI Endpoint Function Driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section lists the APIs that the PCI Endpoint core provides to be used This section lists the APIs that the PCI Endpoint core provides to be used
by the PCI endpoint function driver. by the PCI endpoint function driver.
...@@ -117,8 +117,8 @@ by the PCI endpoint function driver. ...@@ -117,8 +117,8 @@ by the PCI endpoint function driver.
The PCI endpoint function driver should use pci_epc_mem_free_addr() to The PCI endpoint function driver should use pci_epc_mem_free_addr() to
free the memory space allocated using pci_epc_mem_alloc_addr(). free the memory space allocated using pci_epc_mem_alloc_addr().
Other APIs Other EPC APIs
~~~~~~~~~~ ~~~~~~~~~~~~~~
There are other APIs provided by the EPC library. These are used for binding There are other APIs provided by the EPC library. These are used for binding
the EPF device with EPC device. pci-ep-cfs.c can be used as reference for the EPF device with EPC device. pci-ep-cfs.c can be used as reference for
...@@ -160,8 +160,8 @@ PCI Endpoint Function(EPF) Library ...@@ -160,8 +160,8 @@ PCI Endpoint Function(EPF) Library
The EPF library provides APIs to be used by the function driver and the EPC The EPF library provides APIs to be used by the function driver and the EPC
library to provide endpoint mode functionality. library to provide endpoint mode functionality.
APIs for the PCI Endpoint Function Driver EPF APIs for the PCI Endpoint Function Driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This section lists the APIs that the PCI Endpoint core provides to be used This section lists the APIs that the PCI Endpoint core provides to be used
by the PCI endpoint function driver. by the PCI endpoint function driver.
...@@ -204,8 +204,8 @@ by the PCI endpoint controller library. ...@@ -204,8 +204,8 @@ by the PCI endpoint controller library.
The PCI endpoint controller library invokes pci_epf_linkup() when the The PCI endpoint controller library invokes pci_epf_linkup() when the
EPC device has established the connection to the host. EPC device has established the connection to the host.
Other APIs Other EPF APIs
~~~~~~~~~~ ~~~~~~~~~~~~~~
There are other APIs provided by the EPF library. These are used to notify There are other APIs provided by the EPF library. These are used to notify
the function driver when the EPF device is bound to the EPC device. the function driver when the EPF device is bound to the EPC device.
......
...@@ -19,6 +19,9 @@ contain the following properties: ...@@ -19,6 +19,9 @@ contain the following properties:
- interrupt-map-mask and interrupt-map: standard PCI properties to - interrupt-map-mask and interrupt-map: standard PCI properties to
define the mapping of the PCIe interface to interrupt numbers. define the mapping of the PCIe interface to interrupt numbers.
- bus-range: PCI bus numbers covered - bus-range: PCI bus numbers covered
- phys: the PCIe PHY handle
- max-link-speed: see pci.txt
- reset-gpios: see pci.txt
In addition, the Device Tree describing an Aardvark PCIe controller In addition, the Device Tree describing an Aardvark PCIe controller
must include a sub-node that describes the legacy interrupt controller must include a sub-node that describes the legacy interrupt controller
...@@ -48,6 +51,7 @@ Example: ...@@ -48,6 +51,7 @@ Example:
<0 0 0 2 &pcie_intc 1>, <0 0 0 2 &pcie_intc 1>,
<0 0 0 3 &pcie_intc 2>, <0 0 0 3 &pcie_intc 2>,
<0 0 0 4 &pcie_intc 3>; <0 0 0 4 &pcie_intc 3>;
phys = <&comphy1 0>;
pcie_intc: interrupt-controller { pcie_intc: interrupt-controller {
interrupt-controller; interrupt-controller;
#interrupt-cells = <1>; #interrupt-cells = <1>;
......
...@@ -56,6 +56,8 @@ properties: ...@@ -56,6 +56,8 @@ properties:
description: Indicates usage of spread-spectrum clocking. description: Indicates usage of spread-spectrum clocking.
type: boolean type: boolean
aspm-no-l0s: true
required: required:
- reg - reg
- dma-ranges - dma-ranges
......
...@@ -10,7 +10,7 @@ maintainers: ...@@ -10,7 +10,7 @@ maintainers:
- Tom Joseph <tjoseph@cadence.com> - Tom Joseph <tjoseph@cadence.com>
allOf: allOf:
- $ref: "cdns-pcie.yaml#" - $ref: "cdns-pcie-ep.yaml#"
- $ref: "pci-ep.yaml#" - $ref: "pci-ep.yaml#"
properties: properties:
......
...@@ -45,8 +45,6 @@ examples: ...@@ -45,8 +45,6 @@ examples:
#size-cells = <2>; #size-cells = <2>;
bus-range = <0x0 0xff>; bus-range = <0x0 0xff>;
linux,pci-domain = <0>; linux,pci-domain = <0>;
cdns,max-outbound-regions = <16>;
cdns,no-bar-match-nbits = <32>;
vendor-id = <0x17cd>; vendor-id = <0x17cd>;
device-id = <0x0200>; device-id = <0x0200>;
...@@ -57,6 +55,7 @@ examples: ...@@ -57,6 +55,7 @@ examples:
ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>, ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>,
<0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>; <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>;
dma-ranges = <0x02000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
#interrupt-cells = <0x1>; #interrupt-cells = <0x1>;
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/pci/cdns-pcie-ep.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Cadence PCIe Device
maintainers:
- Tom Joseph <tjoseph@cadence.com>
allOf:
- $ref: "cdns-pcie.yaml#"
properties:
cdns,max-outbound-regions:
description: maximum number of outbound regions
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 32
default: 32
required:
- cdns,max-outbound-regions
...@@ -14,6 +14,15 @@ allOf: ...@@ -14,6 +14,15 @@ allOf:
- $ref: "cdns-pcie.yaml#" - $ref: "cdns-pcie.yaml#"
properties: properties:
cdns,max-outbound-regions:
description: maximum number of outbound regions
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 32
default: 32
deprecated: true
cdns,no-bar-match-nbits: cdns,no-bar-match-nbits:
description: description:
Set into the no BAR match register to configure the number of least Set into the no BAR match register to configure the number of least
...@@ -22,5 +31,6 @@ properties: ...@@ -22,5 +31,6 @@ properties:
minimum: 0 minimum: 0
maximum: 64 maximum: 64
default: 32 default: 32
deprecated: true
msi-parent: true msi-parent: true
...@@ -10,13 +10,6 @@ maintainers: ...@@ -10,13 +10,6 @@ maintainers:
- Tom Joseph <tjoseph@cadence.com> - Tom Joseph <tjoseph@cadence.com>
properties: properties:
cdns,max-outbound-regions:
description: maximum number of outbound regions
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 32
default: 32
phys: phys:
description: description:
One per lane if more than one in the list. If only one PHY listed it must One per lane if more than one in the list. If only one PHY listed it must
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 Renesas Electronics Europe GmbH - https://www.renesas.com/eu/en/
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/rcar-pci-ep.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car PCIe Endpoint
maintainers:
- Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
properties:
compatible:
items:
- const: renesas,r8a774c0-pcie-ep
- const: renesas,rcar-gen3-pcie-ep
reg:
maxItems: 5
reg-names:
items:
- const: apb-base
- const: memory0
- const: memory1
- const: memory2
- const: memory3
power-domains:
maxItems: 1
resets:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: pcie
max-functions:
minimum: 1
maximum: 1
required:
- compatible
- reg
- reg-names
- resets
- power-domains
- clocks
- clock-names
- max-functions
examples:
- |
#include <dt-bindings/clock/r8a774c0-cpg-mssr.h>
#include <dt-bindings/power/r8a774c0-sysc.h>
pcie0_ep: pcie-ep@fe000000 {
compatible = "renesas,r8a774c0-pcie-ep",
"renesas,rcar-gen3-pcie-ep";
reg = <0xfe000000 0x80000>,
<0xfe100000 0x100000>,
<0xfe200000 0x200000>,
<0x30000000 0x8000000>,
<0x38000000 0x8000000>;
reg-names = "apb-base", "memory0", "memory1", "memory2", "memory3";
resets = <&cpg 319>;
power-domains = <&sysc R8A774C0_PD_ALWAYS_ON>;
clocks = <&cpg CPG_MOD 319>;
clock-names = "pcie";
max-functions = /bits/ 8 <1>;
};
...@@ -11,7 +11,8 @@ compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC; ...@@ -11,7 +11,8 @@ compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC;
"renesas,pcie-r8a7791" for the R8A7791 SoC; "renesas,pcie-r8a7791" for the R8A7791 SoC;
"renesas,pcie-r8a7793" for the R8A7793 SoC; "renesas,pcie-r8a7793" for the R8A7793 SoC;
"renesas,pcie-r8a7795" for the R8A7795 SoC; "renesas,pcie-r8a7795" for the R8A7795 SoC;
"renesas,pcie-r8a7796" for the R8A7796 SoC; "renesas,pcie-r8a7796" for the R8A77960 SoC;
"renesas,pcie-r8a77961" for the R8A77961 SoC;
"renesas,pcie-r8a77980" for the R8A77980 SoC; "renesas,pcie-r8a77980" for the R8A77980 SoC;
"renesas,pcie-r8a77990" for the R8A77990 SoC; "renesas,pcie-r8a77990" for the R8A77990 SoC;
"renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/socionext,uniphier-pcie-ep.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Socionext UniPhier PCIe endpoint controller
description: |
UniPhier PCIe endpoint controller is based on the Synopsys DesignWare
PCI core. It shares common features with the PCIe DesignWare core and
inherits common properties defined in
Documentation/devicetree/bindings/pci/designware-pcie.txt.
maintainers:
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
allOf:
- $ref: "pci-ep.yaml#"
properties:
compatible:
const: socionext,uniphier-pro5-pcie-ep
reg:
maxItems: 4
reg-names:
items:
- const: dbi
- const: dbi2
- const: link
- const: addr_space
clocks:
maxItems: 2
clock-names:
items:
- const: gio
- const: link
resets:
maxItems: 2
reset-names:
items:
- const: gio
- const: link
num-ib-windows:
const: 16
num-ob-windows:
const: 16
num-lanes: true
phys:
maxItems: 1
phy-names:
const: pcie-phy
required:
- compatible
- reg
- reg-names
- clocks
- clock-names
- resets
- reset-names
additionalProperties: false
examples:
- |
pcie_ep: pcie-ep@66000000 {
compatible = "socionext,uniphier-pro5-pcie-ep";
reg-names = "dbi", "dbi2", "link", "addr_space";
reg = <0x66000000 0x1000>, <0x66001000 0x1000>,
<0x66010000 0x10000>, <0x67000000 0x400000>;
clock-names = "gio", "link";
clocks = <&sys_clk 12>, <&sys_clk 24>;
reset-names = "gio", "link";
resets = <&sys_rst 12>, <&sys_rst 24>;
num-ib-windows = <16>;
num-ob-windows = <16>;
num-lanes = <4>;
phy-names = "pcie-phy";
phys = <&pcie_phy>;
};
...@@ -13074,7 +13074,7 @@ L: linux-pci@vger.kernel.org ...@@ -13074,7 +13074,7 @@ L: linux-pci@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org L: linux-arm-kernel@lists.infradead.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt F: Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
F: drivers/pci/controller/mobibeil/pcie-layerscape-gen4.c F: drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
PCI DRIVER FOR RENESAS R-CAR PCI DRIVER FOR RENESAS R-CAR
M: Marek Vasut <marek.vasut+renesas@gmail.com> M: Marek Vasut <marek.vasut+renesas@gmail.com>
...@@ -13082,6 +13082,7 @@ M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> ...@@ -13082,6 +13082,7 @@ M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-pci@vger.kernel.org L: linux-pci@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org L: linux-renesas-soc@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/pci/*rcar*
F: drivers/pci/controller/*rcar* F: drivers/pci/controller/*rcar*
PCI DRIVER FOR SAMSUNG EXYNOS PCI DRIVER FOR SAMSUNG EXYNOS
...@@ -13275,8 +13276,8 @@ PCIE DRIVER FOR SOCIONEXT UNIPHIER ...@@ -13275,8 +13276,8 @@ PCIE DRIVER FOR SOCIONEXT UNIPHIER
M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> M: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
L: linux-pci@vger.kernel.org L: linux-pci@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/pci/uniphier-pcie.txt F: Documentation/devicetree/bindings/pci/uniphier-pcie*
F: drivers/pci/controller/dwc/pcie-uniphier.c F: drivers/pci/controller/dwc/pcie-uniphier*
PCIE DRIVER FOR ST SPEAR13XX PCIE DRIVER FOR ST SPEAR13XX
M: Pratyush Anand <pratyush.anand@gmail.com> M: Pratyush Anand <pratyush.anand@gmail.com>
......
...@@ -117,7 +117,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) ...@@ -117,7 +117,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)
struct device *dev = &root->device->dev; struct device *dev = &root->device->dev;
struct resource *bus_res = &root->secondary; struct resource *bus_res = &root->secondary;
u16 seg = root->segment; u16 seg = root->segment;
struct pci_ecam_ops *ecam_ops; const struct pci_ecam_ops *ecam_ops;
struct resource cfgres; struct resource cfgres;
struct acpi_device *adev; struct acpi_device *adev;
struct pci_config_window *cfg; struct pci_config_window *cfg;
...@@ -185,7 +185,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) ...@@ -185,7 +185,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
root_ops->release_info = pci_acpi_generic_release_info; root_ops->release_info = pci_acpi_generic_release_info;
root_ops->prepare_resources = pci_acpi_root_prepare_resources; root_ops->prepare_resources = pci_acpi_root_prepare_resources;
root_ops->pci_ops = &ri->cfg->ops->pci_ops; root_ops->pci_ops = (struct pci_ops *)&ri->cfg->ops->pci_ops;
bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg); bus = acpi_pci_root_create(root, root_ops, &ri->common, ri->cfg);
if (!bus) if (!bus)
return NULL; return NULL;
......
...@@ -572,6 +572,10 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, pci_invalid_bar); ...@@ -572,6 +572,10 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6f60, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fa0, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa1ec, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa1ed, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26c, pci_invalid_bar);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0xa26d, pci_invalid_bar);
/* /*
* Device [1022:7808] * Device [1022:7808]
......
...@@ -60,8 +60,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) ...@@ -60,8 +60,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev)
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static int xen_register_pirq(u32 gsi, int gsi_override, int triggering, static int xen_register_pirq(u32 gsi, int triggering, bool set_pirq)
bool set_pirq)
{ {
int rc, pirq = -1, irq = -1; int rc, pirq = -1, irq = -1;
struct physdev_map_pirq map_irq; struct physdev_map_pirq map_irq;
...@@ -94,9 +93,6 @@ static int xen_register_pirq(u32 gsi, int gsi_override, int triggering, ...@@ -94,9 +93,6 @@ static int xen_register_pirq(u32 gsi, int gsi_override, int triggering,
name = "ioapic-level"; name = "ioapic-level";
} }
if (gsi_override >= 0)
gsi = gsi_override;
irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name); irq = xen_bind_pirq_gsi_to_irq(gsi, map_irq.pirq, shareable, name);
if (irq < 0) if (irq < 0)
goto out; goto out;
...@@ -112,12 +108,12 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi, ...@@ -112,12 +108,12 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
if (!xen_hvm_domain()) if (!xen_hvm_domain())
return -1; return -1;
return xen_register_pirq(gsi, -1 /* no GSI override */, trigger, return xen_register_pirq(gsi, trigger,
false /* no mapping of GSI to PIRQ */); false /* no mapping of GSI to PIRQ */);
} }
#ifdef CONFIG_XEN_DOM0 #ifdef CONFIG_XEN_DOM0
static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polarity) static int xen_register_gsi(u32 gsi, int triggering, int polarity)
{ {
int rc, irq; int rc, irq;
struct physdev_setup_gsi setup_gsi; struct physdev_setup_gsi setup_gsi;
...@@ -128,7 +124,7 @@ static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polar ...@@ -128,7 +124,7 @@ static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polar
printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n", printk(KERN_DEBUG "xen: registering gsi %u triggering %d polarity %d\n",
gsi, triggering, polarity); gsi, triggering, polarity);
irq = xen_register_pirq(gsi, gsi_override, triggering, true); irq = xen_register_pirq(gsi, triggering, true);
setup_gsi.gsi = gsi; setup_gsi.gsi = gsi;
setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1); setup_gsi.triggering = (triggering == ACPI_EDGE_SENSITIVE ? 0 : 1);
...@@ -148,7 +144,7 @@ static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polar ...@@ -148,7 +144,7 @@ static int xen_register_gsi(u32 gsi, int gsi_override, int triggering, int polar
static int acpi_register_gsi_xen(struct device *dev, u32 gsi, static int acpi_register_gsi_xen(struct device *dev, u32 gsi,
int trigger, int polarity) int trigger, int polarity)
{ {
return xen_register_gsi(gsi, -1 /* no GSI override */, trigger, polarity); return xen_register_gsi(gsi, trigger, polarity);
} }
#endif #endif
#endif #endif
...@@ -491,7 +487,7 @@ int __init pci_xen_initial_domain(void) ...@@ -491,7 +487,7 @@ int __init pci_xen_initial_domain(void)
if (acpi_get_override_irq(irq, &trigger, &polarity) == -1) if (acpi_get_override_irq(irq, &trigger, &polarity) == -1)
continue; continue;
xen_register_pirq(irq, -1 /* no GSI override */, xen_register_pirq(irq,
trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE, trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE,
true /* Map GSI to PIRQ */); true /* Map GSI to PIRQ */);
} }
......
...@@ -29,7 +29,7 @@ struct mcfg_fixup { ...@@ -29,7 +29,7 @@ struct mcfg_fixup {
u32 oem_revision; u32 oem_revision;
u16 segment; u16 segment;
struct resource bus_range; struct resource bus_range;
struct pci_ecam_ops *ops; const struct pci_ecam_ops *ops;
struct resource cfgres; struct resource cfgres;
}; };
...@@ -165,7 +165,7 @@ static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment, ...@@ -165,7 +165,7 @@ static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment,
static void pci_mcfg_apply_quirks(struct acpi_pci_root *root, static void pci_mcfg_apply_quirks(struct acpi_pci_root *root,
struct resource *cfgres, struct resource *cfgres,
struct pci_ecam_ops **ecam_ops) const struct pci_ecam_ops **ecam_ops)
{ {
#ifdef CONFIG_PCI_QUIRKS #ifdef CONFIG_PCI_QUIRKS
u16 segment = root->segment; u16 segment = root->segment;
...@@ -191,9 +191,9 @@ static void pci_mcfg_apply_quirks(struct acpi_pci_root *root, ...@@ -191,9 +191,9 @@ static void pci_mcfg_apply_quirks(struct acpi_pci_root *root,
static LIST_HEAD(pci_mcfg_list); static LIST_HEAD(pci_mcfg_list);
int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres,
struct pci_ecam_ops **ecam_ops) const struct pci_ecam_ops **ecam_ops)
{ {
struct pci_ecam_ops *ops = &pci_generic_ecam_ops; const struct pci_ecam_ops *ops = &pci_generic_ecam_ops;
struct resource *bus_res = &root->secondary; struct resource *bus_res = &root->secondary;
u16 seg = root->segment; u16 seg = root->segment;
struct mcfg_entry *e; struct mcfg_entry *e;
......
...@@ -483,13 +483,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, ...@@ -483,13 +483,8 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC)) if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC))
control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL; control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL;
if (pci_aer_available()) { if (pci_aer_available())
if (aer_acpi_firmware_first()) control |= OSC_PCI_EXPRESS_AER_CONTROL;
dev_info(&device->dev,
"PCIe AER handled by firmware\n");
else
control |= OSC_PCI_EXPRESS_AER_CONTROL;
}
/* /*
* Per the Downstream Port Containment Related Enhancements ECN to * Per the Downstream Port Containment Related Enhancements ECN to
...@@ -938,7 +933,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root, ...@@ -938,7 +933,7 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
* assignments made by firmware for this host bridge. * assignments made by firmware for this host bridge.
*/ */
obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1, obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 1,
IGNORE_PCI_BOOT_CONFIG_DSM, NULL); DSM_PCI_PRESERVE_BOOT_CONFIG, NULL);
if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0) if (obj && obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 0)
host_bridge->preserve_config = 1; host_bridge->preserve_config = 1;
ACPI_FREE(obj); ACPI_FREE(obj);
......
...@@ -153,23 +153,24 @@ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname); ...@@ -153,23 +153,24 @@ EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
* if (irq < 0) * if (irq < 0)
* return irq; * return irq;
* *
* Return: IRQ number on success, negative error number on failure. * Return: non-zero IRQ number on success, negative error number on failure.
*/ */
int platform_get_irq_optional(struct platform_device *dev, unsigned int num) int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
{ {
int ret;
#ifdef CONFIG_SPARC #ifdef CONFIG_SPARC
/* sparc does not have irqs represented as IORESOURCE_IRQ resources */ /* sparc does not have irqs represented as IORESOURCE_IRQ resources */
if (!dev || num >= dev->archdata.num_irqs) if (!dev || num >= dev->archdata.num_irqs)
return -ENXIO; return -ENXIO;
return dev->archdata.irqs[num]; ret = dev->archdata.irqs[num];
goto out;
#else #else
struct resource *r; struct resource *r;
int ret;
if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
ret = of_irq_get(dev->dev.of_node, num); ret = of_irq_get(dev->dev.of_node, num);
if (ret > 0 || ret == -EPROBE_DEFER) if (ret > 0 || ret == -EPROBE_DEFER)
return ret; goto out;
} }
r = platform_get_resource(dev, IORESOURCE_IRQ, num); r = platform_get_resource(dev, IORESOURCE_IRQ, num);
...@@ -177,7 +178,7 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) ...@@ -177,7 +178,7 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
if (r && r->flags & IORESOURCE_DISABLED) { if (r && r->flags & IORESOURCE_DISABLED) {
ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r); ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r);
if (ret) if (ret)
return ret; goto out;
} }
} }
...@@ -191,13 +192,17 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) ...@@ -191,13 +192,17 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
struct irq_data *irqd; struct irq_data *irqd;
irqd = irq_get_irq_data(r->start); irqd = irq_get_irq_data(r->start);
if (!irqd) if (!irqd) {
return -ENXIO; ret = -ENXIO;
goto out;
}
irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS);
} }
if (r) if (r) {
return r->start; ret = r->start;
goto out;
}
/* /*
* For the index 0 interrupt, allow falling back to GpioInt * For the index 0 interrupt, allow falling back to GpioInt
...@@ -210,11 +215,14 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num) ...@@ -210,11 +215,14 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num); ret = acpi_dev_gpio_irq_get(ACPI_COMPANION(&dev->dev), num);
/* Our callers expect -ENXIO for missing IRQs. */ /* Our callers expect -ENXIO for missing IRQs. */
if (ret >= 0 || ret == -EPROBE_DEFER) if (ret >= 0 || ret == -EPROBE_DEFER)
return ret; goto out;
} }
return -ENXIO; ret = -ENXIO;
#endif #endif
out:
WARN(ret == 0, "0 is an invalid IRQ number\n");
return ret;
} }
EXPORT_SYMBOL_GPL(platform_get_irq_optional); EXPORT_SYMBOL_GPL(platform_get_irq_optional);
...@@ -233,7 +241,7 @@ EXPORT_SYMBOL_GPL(platform_get_irq_optional); ...@@ -233,7 +241,7 @@ EXPORT_SYMBOL_GPL(platform_get_irq_optional);
* if (irq < 0) * if (irq < 0)
* return irq; * return irq;
* *
* Return: IRQ number on success, negative error number on failure. * Return: non-zero IRQ number on success, negative error number on failure.
*/ */
int platform_get_irq(struct platform_device *dev, unsigned int num) int platform_get_irq(struct platform_device *dev, unsigned int num)
{ {
...@@ -305,8 +313,10 @@ static int __platform_get_irq_byname(struct platform_device *dev, ...@@ -305,8 +313,10 @@ static int __platform_get_irq_byname(struct platform_device *dev,
} }
r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
if (r) if (r) {
WARN(r->start == 0, "0 is an invalid IRQ number\n");
return r->start; return r->start;
}
return -ENXIO; return -ENXIO;
} }
...@@ -318,7 +328,7 @@ static int __platform_get_irq_byname(struct platform_device *dev, ...@@ -318,7 +328,7 @@ static int __platform_get_irq_byname(struct platform_device *dev,
* *
* Get an IRQ like platform_get_irq(), but then by name rather then by index. * Get an IRQ like platform_get_irq(), but then by name rather then by index.
* *
* Return: IRQ number on success, negative error number on failure. * Return: non-zero IRQ number on success, negative error number on failure.
*/ */
int platform_get_irq_byname(struct platform_device *dev, const char *name) int platform_get_irq_byname(struct platform_device *dev, const char *name)
{ {
...@@ -340,7 +350,7 @@ EXPORT_SYMBOL_GPL(platform_get_irq_byname); ...@@ -340,7 +350,7 @@ EXPORT_SYMBOL_GPL(platform_get_irq_byname);
* Get an optional IRQ by name like platform_get_irq_byname(). Except that it * Get an optional IRQ by name like platform_get_irq_byname(). Except that it
* does not print an error message if an IRQ can not be obtained. * does not print an error message if an IRQ can not be obtained.
* *
* Return: IRQ number on success, negative error number on failure. * Return: non-zero IRQ number on success, negative error number on failure.
*/ */
int platform_get_irq_byname_optional(struct platform_device *dev, int platform_get_irq_byname_optional(struct platform_device *dev,
const char *name) const char *name)
......
...@@ -178,8 +178,9 @@ config ISCSI_IBFT ...@@ -178,8 +178,9 @@ config ISCSI_IBFT
Otherwise, say N. Otherwise, say N.
config RASPBERRYPI_FIRMWARE config RASPBERRYPI_FIRMWARE
tristate "Raspberry Pi Firmware Driver" bool "Raspberry Pi Firmware Driver"
depends on BCM2835_MBOX depends on BCM2835_MBOX
default USB_PCI
help help
This option enables support for communicating with the firmware on the This option enables support for communicating with the firmware on the
Raspberry Pi. Raspberry Pi.
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <soc/bcm2835/raspberrypi-firmware.h> #include <soc/bcm2835/raspberrypi-firmware.h>
#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
...@@ -19,6 +21,8 @@ ...@@ -19,6 +21,8 @@
#define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_DATA28(msg) ((msg) & ~0xf)
#define MBOX_CHAN_PROPERTY 8 #define MBOX_CHAN_PROPERTY 8
#define VL805_PCI_CONFIG_VERSION_OFFSET 0x50
static struct platform_device *rpi_hwmon; static struct platform_device *rpi_hwmon;
static struct platform_device *rpi_clk; static struct platform_device *rpi_clk;
...@@ -280,6 +284,63 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) ...@@ -280,6 +284,63 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
} }
EXPORT_SYMBOL_GPL(rpi_firmware_get); EXPORT_SYMBOL_GPL(rpi_firmware_get);
/*
* The Raspberry Pi 4 gets its USB functionality from VL805, a PCIe chip that
* implements xHCI. After a PCI reset, VL805's firmware may either be loaded
* directly from an EEPROM or, if not present, by the SoC's co-processor,
* VideoCore. RPi4's VideoCore OS contains both the non public firmware load
* logic and the VL805 firmware blob. This function triggers the aforementioned
* process.
*/
int rpi_firmware_init_vl805(struct pci_dev *pdev)
{
struct device_node *fw_np;
struct rpi_firmware *fw;
u32 dev_addr, version;
int ret;
fw_np = of_find_compatible_node(NULL, NULL,
"raspberrypi,bcm2835-firmware");
if (!fw_np)
return 0;
fw = rpi_firmware_get(fw_np);
of_node_put(fw_np);
if (!fw)
return -ENODEV;
/*
* Make sure we don't trigger a firmware load unnecessarily.
*
* If something went wrong with PCI, this whole exercise would be
* futile as VideoCore expects from us a configured PCI bus. Just take
* the faulty version (likely ~0) and let xHCI's registration fail
* further down the line.
*/
pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET, &version);
if (version)
goto exit;
dev_addr = pdev->bus->number << 20 | PCI_SLOT(pdev->devfn) << 15 |
PCI_FUNC(pdev->devfn) << 12;
ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
&dev_addr, sizeof(dev_addr));
if (ret)
return ret;
/* Wait for vl805 to startup */
usleep_range(200, 1000);
pci_read_config_dword(pdev, VL805_PCI_CONFIG_VERSION_OFFSET,
&version);
exit:
pci_info(pdev, "VL805 firmware version %08x\n", version);
return 0;
}
EXPORT_SYMBOL_GPL(rpi_firmware_init_vl805);
static const struct of_device_id rpi_firmware_of_match[] = { static const struct of_device_id rpi_firmware_of_match[] = {
{ .compatible = "raspberrypi,bcm2835-firmware", }, { .compatible = "raspberrypi,bcm2835-firmware", },
{}, {},
......
...@@ -58,15 +58,33 @@ config PCIE_RCAR ...@@ -58,15 +58,33 @@ config PCIE_RCAR
bool "Renesas R-Car PCIe controller" bool "Renesas R-Car PCIe controller"
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_RCAR_HOST
help help
Say Y here if you want PCIe controller support on R-Car SoCs. Say Y here if you want PCIe controller support on R-Car SoCs.
This option will be removed after arm64 defconfig is updated.
config PCIE_RCAR_HOST
bool "Renesas R-Car PCIe host controller"
depends on ARCH_RENESAS || COMPILE_TEST
depends on PCI_MSI_IRQ_DOMAIN
help
Say Y here if you want PCIe controller support on R-Car SoCs in host
mode.
config PCIE_RCAR_EP
bool "Renesas R-Car PCIe endpoint controller"
depends on ARCH_RENESAS || COMPILE_TEST
depends on PCI_ENDPOINT
help
Say Y here if you want PCIe controller support on R-Car SoCs in
endpoint mode.
config PCI_HOST_COMMON config PCI_HOST_COMMON
bool tristate
select PCI_ECAM select PCI_ECAM
config PCI_HOST_GENERIC config PCI_HOST_GENERIC
bool "Generic PCI host controller" tristate "Generic PCI host controller"
depends on OF depends on OF
select PCI_HOST_COMMON select PCI_HOST_COMMON
select IRQ_DOMAIN select IRQ_DOMAIN
......
...@@ -7,7 +7,8 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o ...@@ -7,7 +7,8 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
obj-$(CONFIG_PCIE_RCAR) += pcie-rcar.o obj-$(CONFIG_PCIE_RCAR_HOST) += pcie-rcar.o pcie-rcar-host.o
obj-$(CONFIG_PCIE_RCAR_EP) += pcie-rcar.o pcie-rcar-ep.o
obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
......
...@@ -450,7 +450,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep) ...@@ -450,7 +450,7 @@ int cdns_pcie_ep_setup(struct cdns_pcie_ep *ep)
epc->max_functions = 1; epc->max_functions = 1;
ret = pci_epc_mem_init(epc, pcie->mem_res->start, ret = pci_epc_mem_init(epc, pcie->mem_res->start,
resource_size(pcie->mem_res)); resource_size(pcie->mem_res), PAGE_SIZE);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "failed to initialize the memory space\n"); dev_err(dev, "failed to initialize the memory space\n");
goto err_init; goto err_init;
......
...@@ -140,9 +140,6 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc) ...@@ -140,9 +140,6 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
for_each_of_pci_range(&parser, &range) { for_each_of_pci_range(&parser, &range) {
bool is_io; bool is_io;
if (r >= rc->max_regions)
break;
if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
is_io = false; is_io = false;
else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
...@@ -219,17 +216,14 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc) ...@@ -219,17 +216,14 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
pcie = &rc->pcie; pcie = &rc->pcie;
pcie->is_rc = true; pcie->is_rc = true;
rc->max_regions = 32;
of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
rc->no_bar_nbits = 32; rc->no_bar_nbits = 32;
of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits); of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
rc->vendor_id = 0xffff; rc->vendor_id = 0xffff;
of_property_read_u16(np, "vendor-id", &rc->vendor_id); of_property_read_u32(np, "vendor-id", &rc->vendor_id);
rc->device_id = 0xffff; rc->device_id = 0xffff;
of_property_read_u16(np, "device-id", &rc->device_id); of_property_read_u32(np, "device-id", &rc->device_id);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
pcie->reg_base = devm_ioremap_resource(dev, res); pcie->reg_base = devm_ioremap_resource(dev, res);
......
...@@ -251,7 +251,6 @@ struct cdns_pcie { ...@@ -251,7 +251,6 @@ struct cdns_pcie {
* @bus_range: first/last buses behind the PCIe host controller * @bus_range: first/last buses behind the PCIe host controller
* @cfg_base: IO mapped window to access the PCI configuration space of a * @cfg_base: IO mapped window to access the PCI configuration space of a
* single function at a time * single function at a time
* @max_regions: maximum number of regions supported by the hardware
* @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
* translation (nbits sets into the "no BAR match" register) * translation (nbits sets into the "no BAR match" register)
* @vendor_id: PCI vendor ID * @vendor_id: PCI vendor ID
...@@ -262,10 +261,9 @@ struct cdns_pcie_rc { ...@@ -262,10 +261,9 @@ struct cdns_pcie_rc {
struct resource *cfg_res; struct resource *cfg_res;
struct resource *bus_range; struct resource *bus_range;
void __iomem *cfg_base; void __iomem *cfg_base;
u32 max_regions;
u32 no_bar_nbits; u32 no_bar_nbits;
u16 vendor_id; u32 vendor_id;
u16 device_id; u32 device_id;
}; };
/** /**
......
...@@ -26,7 +26,7 @@ config PCI_DRA7XX_HOST ...@@ -26,7 +26,7 @@ config PCI_DRA7XX_HOST
depends on OF && HAS_IOMEM && TI_PIPE3 depends on OF && HAS_IOMEM && TI_PIPE3
select PCIE_DW_HOST select PCIE_DW_HOST
select PCI_DRA7XX select PCI_DRA7XX
default y default y if SOC_DRA7XX
help help
Enables support for the PCIe controller in the DRA7xx SoC to work in Enables support for the PCIe controller in the DRA7xx SoC to work in
host mode. There are two instances of PCIe controller in DRA7xx. host mode. There are two instances of PCIe controller in DRA7xx.
...@@ -111,7 +111,6 @@ config PCI_KEYSTONE_HOST ...@@ -111,7 +111,6 @@ config PCI_KEYSTONE_HOST
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST select PCIE_DW_HOST
select PCI_KEYSTONE select PCI_KEYSTONE
default y
help help
Enables support for the PCIe controller in the Keystone SoC to Enables support for the PCIe controller in the Keystone SoC to
work in host mode. The PCI controller on Keystone is based on work in host mode. The PCI controller on Keystone is based on
...@@ -281,15 +280,25 @@ config PCIE_TEGRA194_EP ...@@ -281,15 +280,25 @@ config PCIE_TEGRA194_EP
selected. This uses the DesignWare core. selected. This uses the DesignWare core.
config PCIE_UNIPHIER config PCIE_UNIPHIER
bool "Socionext UniPhier PCIe controllers" bool "Socionext UniPhier PCIe host controllers"
depends on ARCH_UNIPHIER || COMPILE_TEST depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && HAS_IOMEM depends on OF && HAS_IOMEM
depends on PCI_MSI_IRQ_DOMAIN depends on PCI_MSI_IRQ_DOMAIN
select PCIE_DW_HOST select PCIE_DW_HOST
help help
Say Y here if you want PCIe controller support on UniPhier SoCs. Say Y here if you want PCIe host controller support on UniPhier SoCs.
This driver supports LD20 and PXs3 SoCs. This driver supports LD20 and PXs3 SoCs.
config PCIE_UNIPHIER_EP
bool "Socionext UniPhier PCIe endpoint controllers"
depends on ARCH_UNIPHIER || COMPILE_TEST
depends on OF && HAS_IOMEM
depends on PCI_ENDPOINT
select PCIE_DW_EP
help
Say Y here if you want PCIe endpoint controller support on
UniPhier SoCs. This driver supports Pro5 SoC.
config PCIE_AL config PCIE_AL
bool "Amazon Annapurna Labs PCIe controller" bool "Amazon Annapurna Labs PCIe controller"
depends on OF && (ARM64 || COMPILE_TEST) depends on OF && (ARM64 || COMPILE_TEST)
......
...@@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o ...@@ -19,6 +19,7 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
obj-$(CONFIG_PCI_MESON) += pci-meson.o obj-$(CONFIG_PCI_MESON) += pci-meson.o
obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
# The following drivers are for devices that use the generic ACPI # The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access. # pci_root.c driver but don't support standard ECAM config access.
......
...@@ -840,7 +840,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) ...@@ -840,7 +840,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
struct phy **phy; struct phy **phy;
struct device_link **link; struct device_link **link;
void __iomem *base; void __iomem *base;
struct resource *res;
struct dw_pcie *pci; struct dw_pcie *pci;
struct dra7xx_pcie *dra7xx; struct dra7xx_pcie *dra7xx;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -877,10 +876,9 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev) ...@@ -877,10 +876,9 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
return irq; return irq;
} }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf"); base = devm_platform_ioremap_resource_byname(pdev, "ti_conf");
base = devm_ioremap(dev, res->start, resource_size(res)); if (IS_ERR(base))
if (!base) return PTR_ERR(base);
return -ENOMEM;
phy_count = of_property_count_strings(np, "phy-names"); phy_count = of_property_count_strings(np, "phy-names");
if (phy_count < 0) { if (phy_count < 0) {
......
...@@ -868,9 +868,9 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie, ...@@ -868,9 +868,9 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
if (IS_ENABLED(CONFIG_PCI_MSI)) { if (IS_ENABLED(CONFIG_PCI_MSI)) {
pp->msi_irq = platform_get_irq_byname(pdev, "msi"); pp->msi_irq = platform_get_irq_byname(pdev, "msi");
if (pp->msi_irq <= 0) { if (pp->msi_irq < 0) {
dev_err(dev, "failed to get MSI irq\n"); dev_err(dev, "failed to get MSI irq\n");
return -ENODEV; return pp->msi_irq;
} }
} }
......
...@@ -289,11 +289,11 @@ static void meson_pcie_init_dw(struct meson_pcie *mp) ...@@ -289,11 +289,11 @@ static void meson_pcie_init_dw(struct meson_pcie *mp)
meson_cfg_writel(mp, val, PCIE_CFG0); meson_cfg_writel(mp, val, PCIE_CFG0);
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
val &= ~LINK_CAPABLE_MASK; val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE);
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF); val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
val |= LINK_CAPABLE_X1 | FAST_LINK_MODE; val |= LINK_CAPABLE_X1;
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF); meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF); val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
......
...@@ -80,7 +80,7 @@ static int al_pcie_init(struct pci_config_window *cfg) ...@@ -80,7 +80,7 @@ static int al_pcie_init(struct pci_config_window *cfg)
return 0; return 0;
} }
struct pci_ecam_ops al_pcie_ops = { const struct pci_ecam_ops al_pcie_ops = {
.bus_shift = 20, .bus_shift = 20,
.init = al_pcie_init, .init = al_pcie_init,
.pci_ops = { .pci_ops = {
......
...@@ -412,11 +412,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -412,11 +412,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
reg = ep->msi_cap + PCI_MSI_DATA_32; reg = ep->msi_cap + PCI_MSI_DATA_32;
msg_data = dw_pcie_readw_dbi(pci, reg); msg_data = dw_pcie_readw_dbi(pci, reg);
} }
aligned_offset = msg_addr_lower & (epc->mem->page_size - 1); aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
msg_addr = ((u64)msg_addr_upper) << 32 | msg_addr = ((u64)msg_addr_upper) << 32 |
(msg_addr_lower & ~aligned_offset); (msg_addr_lower & ~aligned_offset);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
epc->mem->page_size); epc->mem->window.page_size);
if (ret) if (ret)
return ret; return ret;
...@@ -433,7 +433,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -433,7 +433,6 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
struct dw_pcie *pci = to_dw_pcie_from_ep(ep); struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct pci_epf_msix_tbl *msix_tbl; struct pci_epf_msix_tbl *msix_tbl;
struct pci_epc *epc = ep->epc; struct pci_epc *epc = ep->epc;
struct pci_epf_bar *epf_bar;
u32 reg, msg_data, vec_ctrl; u32 reg, msg_data, vec_ctrl;
unsigned int aligned_offset; unsigned int aligned_offset;
u32 tbl_offset; u32 tbl_offset;
...@@ -446,10 +445,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -446,10 +445,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
bir = (tbl_offset & PCI_MSIX_TABLE_BIR); bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
tbl_offset &= PCI_MSIX_TABLE_OFFSET; tbl_offset &= PCI_MSIX_TABLE_OFFSET;
epf_bar = ep->epf_bar[bir]; msix_tbl = ep->epf_bar[bir]->addr + tbl_offset;
msix_tbl = epf_bar->addr;
msix_tbl = (struct pci_epf_msix_tbl *)((char *)msix_tbl + tbl_offset);
msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr; msg_addr = msix_tbl[(interrupt_num - 1)].msg_addr;
msg_data = msix_tbl[(interrupt_num - 1)].msg_data; msg_data = msix_tbl[(interrupt_num - 1)].msg_data;
vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl; vec_ctrl = msix_tbl[(interrupt_num - 1)].vector_ctrl;
...@@ -459,9 +455,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no, ...@@ -459,9 +455,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
return -EPERM; return -EPERM;
} }
aligned_offset = msg_addr & (epc->mem->page_size - 1); aligned_offset = msg_addr & (epc->mem->window.page_size - 1);
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr, ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
epc->mem->page_size); epc->mem->window.page_size);
if (ret) if (ret)
return ret; return ret;
...@@ -477,7 +473,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep) ...@@ -477,7 +473,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
struct pci_epc *epc = ep->epc; struct pci_epc *epc = ep->epc;
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem, pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
epc->mem->page_size); epc->mem->window.page_size);
pci_epc_mem_exit(epc); pci_epc_mem_exit(epc);
} }
...@@ -610,15 +606,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ...@@ -610,15 +606,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
if (ret < 0) if (ret < 0)
epc->max_functions = 1; epc->max_functions = 1;
ret = __pci_epc_mem_init(epc, ep->phys_base, ep->addr_size, ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
ep->page_size); ep->page_size);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to initialize address space\n"); dev_err(dev, "Failed to initialize address space\n");
return ret; return ret;
} }
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys, ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
epc->mem->page_size); epc->mem->window.page_size);
if (!ep->msi_mem) { if (!ep->msi_mem) {
dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n"); dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
return -ENOMEM; return -ENOMEM;
......
...@@ -236,7 +236,7 @@ static void dw_pcie_irq_domain_free(struct irq_domain *domain, ...@@ -236,7 +236,7 @@ static void dw_pcie_irq_domain_free(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs) unsigned int virq, unsigned int nr_irqs)
{ {
struct irq_data *d = irq_domain_get_irq_data(domain, virq); struct irq_data *d = irq_domain_get_irq_data(domain, virq);
struct pcie_port *pp = irq_data_get_irq_chip_data(d); struct pcie_port *pp = domain->host_data;
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&pp->lock, flags); raw_spin_lock_irqsave(&pp->lock, flags);
...@@ -264,6 +264,8 @@ int dw_pcie_allocate_domains(struct pcie_port *pp) ...@@ -264,6 +264,8 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
return -ENOMEM; return -ENOMEM;
} }
irq_domain_update_bus_token(pp->irq_domain, DOMAIN_BUS_NEXUS);
pp->msi_domain = pci_msi_create_irq_domain(fwnode, pp->msi_domain = pci_msi_create_irq_domain(fwnode,
&dw_pcie_msi_domain_info, &dw_pcie_msi_domain_info,
pp->irq_domain); pp->irq_domain);
......
...@@ -244,13 +244,16 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index, ...@@ -244,13 +244,16 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
u64 pci_addr, u32 size) u64 pci_addr, u32 size)
{ {
u32 retries, val; u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
lower_32_bits(cpu_addr)); lower_32_bits(cpu_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
upper_32_bits(cpu_addr)); upper_32_bits(cpu_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
lower_32_bits(cpu_addr + size - 1)); lower_32_bits(limit_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
upper_32_bits(limit_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
lower_32_bits(pci_addr)); lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
......
...@@ -112,9 +112,10 @@ ...@@ -112,9 +112,10 @@
#define PCIE_ATU_UNR_REGION_CTRL2 0x04 #define PCIE_ATU_UNR_REGION_CTRL2 0x04
#define PCIE_ATU_UNR_LOWER_BASE 0x08 #define PCIE_ATU_UNR_LOWER_BASE 0x08
#define PCIE_ATU_UNR_UPPER_BASE 0x0C #define PCIE_ATU_UNR_UPPER_BASE 0x0C
#define PCIE_ATU_UNR_LIMIT 0x10 #define PCIE_ATU_UNR_LOWER_LIMIT 0x10
#define PCIE_ATU_UNR_LOWER_TARGET 0x14 #define PCIE_ATU_UNR_LOWER_TARGET 0x14
#define PCIE_ATU_UNR_UPPER_TARGET 0x18 #define PCIE_ATU_UNR_UPPER_TARGET 0x18
#define PCIE_ATU_UNR_UPPER_LIMIT 0x20
/* /*
* The default address offset between dbi_base and atu_base. Root controller * The default address offset between dbi_base and atu_base. Root controller
......
...@@ -104,7 +104,7 @@ static int hisi_pcie_init(struct pci_config_window *cfg) ...@@ -104,7 +104,7 @@ static int hisi_pcie_init(struct pci_config_window *cfg)
return 0; return 0;
} }
struct pci_ecam_ops hisi_pcie_ops = { const struct pci_ecam_ops hisi_pcie_ops = {
.bus_shift = 20, .bus_shift = 20,
.init = hisi_pcie_init, .init = hisi_pcie_init,
.pci_ops = { .pci_ops = {
...@@ -332,15 +332,6 @@ static struct platform_driver hisi_pcie_driver = { ...@@ -332,15 +332,6 @@ static struct platform_driver hisi_pcie_driver = {
}; };
builtin_platform_driver(hisi_pcie_driver); builtin_platform_driver(hisi_pcie_driver);
static int hisi_pcie_almost_ecam_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pci_ecam_ops *ops;
ops = (struct pci_ecam_ops *)of_device_get_match_data(dev);
return pci_host_common_probe(pdev, ops);
}
static int hisi_pcie_platform_init(struct pci_config_window *cfg) static int hisi_pcie_platform_init(struct pci_config_window *cfg)
{ {
struct device *dev = cfg->parent; struct device *dev = cfg->parent;
...@@ -362,7 +353,7 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg) ...@@ -362,7 +353,7 @@ static int hisi_pcie_platform_init(struct pci_config_window *cfg)
return 0; return 0;
} }
struct pci_ecam_ops hisi_pcie_platform_ops = { static const struct pci_ecam_ops hisi_pcie_platform_ops = {
.bus_shift = 20, .bus_shift = 20,
.init = hisi_pcie_platform_init, .init = hisi_pcie_platform_init,
.pci_ops = { .pci_ops = {
...@@ -375,17 +366,17 @@ struct pci_ecam_ops hisi_pcie_platform_ops = { ...@@ -375,17 +366,17 @@ struct pci_ecam_ops hisi_pcie_platform_ops = {
static const struct of_device_id hisi_pcie_almost_ecam_of_match[] = { static const struct of_device_id hisi_pcie_almost_ecam_of_match[] = {
{ {
.compatible = "hisilicon,hip06-pcie-ecam", .compatible = "hisilicon,hip06-pcie-ecam",
.data = (void *) &hisi_pcie_platform_ops, .data = &hisi_pcie_platform_ops,
}, },
{ {
.compatible = "hisilicon,hip07-pcie-ecam", .compatible = "hisilicon,hip07-pcie-ecam",
.data = (void *) &hisi_pcie_platform_ops, .data = &hisi_pcie_platform_ops,
}, },
{}, {},
}; };
static struct platform_driver hisi_pcie_almost_ecam_driver = { static struct platform_driver hisi_pcie_almost_ecam_driver = {
.probe = hisi_pcie_almost_ecam_probe, .probe = pci_host_common_probe,
.driver = { .driver = {
.name = "hisi-pcie-almost-ecam", .name = "hisi-pcie-almost-ecam",
.of_match_table = hisi_pcie_almost_ecam_of_match, .of_match_table = hisi_pcie_almost_ecam_of_match,
......
...@@ -453,7 +453,7 @@ static int intel_pcie_msi_init(struct pcie_port *pp) ...@@ -453,7 +453,7 @@ static int intel_pcie_msi_init(struct pcie_port *pp)
return 0; return 0;
} }
u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr) static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
{ {
return cpu_addr + BUS_IATU_OFFSET; return cpu_addr + BUS_IATU_OFFSET;
} }
......
...@@ -1623,7 +1623,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) ...@@ -1623,7 +1623,7 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
ret = pinctrl_pm_select_default_state(dev); ret = pinctrl_pm_select_default_state(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to configure sideband pins: %d\n", ret); dev_err(dev, "Failed to configure sideband pins: %d\n", ret);
goto fail_pinctrl; goto fail_pm_get_sync;
} }
tegra_pcie_init_controller(pcie); tegra_pcie_init_controller(pcie);
...@@ -1650,9 +1650,8 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie) ...@@ -1650,9 +1650,8 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
fail_host_init: fail_host_init:
tegra_pcie_deinit_controller(pcie); tegra_pcie_deinit_controller(pcie);
fail_pinctrl:
pm_runtime_put_sync(dev);
fail_pm_get_sync: fail_pm_get_sync:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
return ret; return ret;
} }
...@@ -2190,9 +2189,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev) ...@@ -2190,9 +2189,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
} }
pp->irq = platform_get_irq_byname(pdev, "intr"); pp->irq = platform_get_irq_byname(pdev, "intr");
if (!pp->irq) { if (pp->irq < 0) {
dev_err(dev, "Failed to get \"intr\" interrupt\n"); dev_err(dev, "Failed to get \"intr\" interrupt\n");
return -ENODEV; return pp->irq;
} }
pcie->bpmp = tegra_bpmp_get(dev); pcie->bpmp = tegra_bpmp_get(dev);
......
// SPDX-License-Identifier: GPL-2.0
/*
* PCIe endpoint controller driver for UniPhier SoCs
* Copyright 2018 Socionext Inc.
* Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
*/
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include "pcie-designware.h"
/* Link Glue registers */
#define PCL_RSTCTRL0 0x0010
#define PCL_RSTCTRL_AXI_REG BIT(3)
#define PCL_RSTCTRL_AXI_SLAVE BIT(2)
#define PCL_RSTCTRL_AXI_MASTER BIT(1)
#define PCL_RSTCTRL_PIPE3 BIT(0)
#define PCL_RSTCTRL1 0x0020
#define PCL_RSTCTRL_PERST BIT(0)
#define PCL_RSTCTRL2 0x0024
#define PCL_RSTCTRL_PHY_RESET BIT(0)
#define PCL_MODE 0x8000
#define PCL_MODE_REGEN BIT(8)
#define PCL_MODE_REGVAL BIT(0)
#define PCL_APP_CLK_CTRL 0x8004
#define PCL_APP_CLK_REQ BIT(0)
#define PCL_APP_READY_CTRL 0x8008
#define PCL_APP_LTSSM_ENABLE BIT(0)
#define PCL_APP_MSI0 0x8040
#define PCL_APP_VEN_MSI_TC_MASK GENMASK(10, 8)
#define PCL_APP_VEN_MSI_VECTOR_MASK GENMASK(4, 0)
#define PCL_APP_MSI1 0x8044
#define PCL_APP_MSI_REQ BIT(0)
#define PCL_APP_INTX 0x8074
#define PCL_APP_INTX_SYS_INT BIT(0)
/* assertion time of INTx in usec */
#define PCL_INTX_WIDTH_USEC 30
struct uniphier_pcie_ep_priv {
void __iomem *base;
struct dw_pcie pci;
struct clk *clk, *clk_gio;
struct reset_control *rst, *rst_gio;
struct phy *phy;
const struct pci_epc_features *features;
};
#define to_uniphier_pcie(x) dev_get_drvdata((x)->dev)
static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_ep_priv *priv,
bool enable)
{
u32 val;
val = readl(priv->base + PCL_APP_READY_CTRL);
if (enable)
val |= PCL_APP_LTSSM_ENABLE;
else
val &= ~PCL_APP_LTSSM_ENABLE;
writel(val, priv->base + PCL_APP_READY_CTRL);
}
static void uniphier_pcie_phy_reset(struct uniphier_pcie_ep_priv *priv,
bool assert)
{
u32 val;
val = readl(priv->base + PCL_RSTCTRL2);
if (assert)
val |= PCL_RSTCTRL_PHY_RESET;
else
val &= ~PCL_RSTCTRL_PHY_RESET;
writel(val, priv->base + PCL_RSTCTRL2);
}
static void uniphier_pcie_init_ep(struct uniphier_pcie_ep_priv *priv)
{
u32 val;
/* set EP mode */
val = readl(priv->base + PCL_MODE);
val |= PCL_MODE_REGEN | PCL_MODE_REGVAL;
writel(val, priv->base + PCL_MODE);
/* clock request */
val = readl(priv->base + PCL_APP_CLK_CTRL);
val &= ~PCL_APP_CLK_REQ;
writel(val, priv->base + PCL_APP_CLK_CTRL);
/* deassert PIPE3 and AXI reset */
val = readl(priv->base + PCL_RSTCTRL0);
val |= PCL_RSTCTRL_AXI_REG | PCL_RSTCTRL_AXI_SLAVE
| PCL_RSTCTRL_AXI_MASTER | PCL_RSTCTRL_PIPE3;
writel(val, priv->base + PCL_RSTCTRL0);
uniphier_pcie_ltssm_enable(priv, false);
msleep(100);
}
static int uniphier_pcie_start_link(struct dw_pcie *pci)
{
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
uniphier_pcie_ltssm_enable(priv, true);
return 0;
}
static void uniphier_pcie_stop_link(struct dw_pcie *pci)
{
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
uniphier_pcie_ltssm_enable(priv, false);
}
static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
enum pci_barno bar;
for (bar = BAR_0; bar <= BAR_5; bar++)
dw_pcie_ep_reset_bar(pci, bar);
}
static int uniphier_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
u32 val;
/*
* This makes pulse signal to send INTx to the RC, so this should
* be cleared as soon as possible. This sequence is covered with
* mutex in pci_epc_raise_irq().
*/
/* assert INTx */
val = readl(priv->base + PCL_APP_INTX);
val |= PCL_APP_INTX_SYS_INT;
writel(val, priv->base + PCL_APP_INTX);
udelay(PCL_INTX_WIDTH_USEC);
/* deassert INTx */
val &= ~PCL_APP_INTX_SYS_INT;
writel(val, priv->base + PCL_APP_INTX);
return 0;
}
static int uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep,
u8 func_no, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
u32 val;
val = FIELD_PREP(PCL_APP_VEN_MSI_TC_MASK, func_no)
| FIELD_PREP(PCL_APP_VEN_MSI_VECTOR_MASK, interrupt_num - 1);
writel(val, priv->base + PCL_APP_MSI0);
val = readl(priv->base + PCL_APP_MSI1);
val |= PCL_APP_MSI_REQ;
writel(val, priv->base + PCL_APP_MSI1);
return 0;
}
static int uniphier_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
enum pci_epc_irq_type type,
u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
case PCI_EPC_IRQ_LEGACY:
return uniphier_pcie_ep_raise_legacy_irq(ep);
case PCI_EPC_IRQ_MSI:
return uniphier_pcie_ep_raise_msi_irq(ep, func_no,
interrupt_num);
default:
dev_err(pci->dev, "UNKNOWN IRQ type (%d)\n", type);
}
return 0;
}
static const struct pci_epc_features*
uniphier_pcie_get_features(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
return priv->features;
}
static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
.ep_init = uniphier_pcie_ep_init,
.raise_irq = uniphier_pcie_ep_raise_irq,
.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;
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
ret = clk_prepare_enable(priv->clk_gio);
if (ret)
goto out_clk_disable;
ret = reset_control_deassert(priv->rst);
if (ret)
goto out_clk_gio_disable;
ret = reset_control_deassert(priv->rst_gio);
if (ret)
goto out_rst_assert;
uniphier_pcie_init_ep(priv);
uniphier_pcie_phy_reset(priv, true);
ret = phy_init(priv->phy);
if (ret)
goto out_rst_gio_assert;
uniphier_pcie_phy_reset(priv, false);
return 0;
out_rst_gio_assert:
reset_control_assert(priv->rst_gio);
out_rst_assert:
reset_control_assert(priv->rst);
out_clk_gio_disable:
clk_disable_unprepare(priv->clk_gio);
out_clk_disable:
clk_disable_unprepare(priv->clk);
return ret;
}
static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = uniphier_pcie_start_link,
.stop_link = uniphier_pcie_stop_link,
};
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);
if (!priv)
return -ENOMEM;
priv->features = of_device_get_match_data(dev);
if (WARN_ON(!priv->features))
return -EINVAL;
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);
priv->clk_gio = devm_clk_get(dev, "gio");
if (IS_ERR(priv->clk_gio))
return PTR_ERR(priv->clk_gio);
priv->rst_gio = devm_reset_control_get_shared(dev, "gio");
if (IS_ERR(priv->rst_gio))
return PTR_ERR(priv->rst_gio);
priv->clk = devm_clk_get(dev, "link");
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
priv->rst = devm_reset_control_get_shared(dev, "link");
if (IS_ERR(priv->rst))
return PTR_ERR(priv->rst);
priv->phy = devm_phy_optional_get(dev, "pcie-phy");
if (IS_ERR(priv->phy)) {
ret = PTR_ERR(priv->phy);
dev_err(dev, "Failed to get phy (%d)\n", ret);
return ret;
}
platform_set_drvdata(pdev, priv);
ret = uniphier_pcie_ep_enable(priv);
if (ret)
return ret;
return uniphier_add_pcie_ep(priv, pdev);
}
static const struct pci_epc_features uniphier_pro5_data = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = false,
.align = 1 << 16,
.bar_fixed_64bit = BIT(BAR_0) | BIT(BAR_2) | BIT(BAR_4),
.reserved_bar = BIT(BAR_4),
};
static const struct of_device_id uniphier_pcie_ep_match[] = {
{
.compatible = "socionext,uniphier-pro5-pcie-ep",
.data = &uniphier_pro5_data,
},
{ /* sentinel */ },
};
static struct platform_driver uniphier_pcie_ep_driver = {
.probe = uniphier_pcie_ep_probe,
.driver = {
.name = "uniphier-pcie-ep",
.of_match_table = uniphier_pcie_ep_match,
.suppress_bind_attrs = true,
},
};
builtin_platform_driver(uniphier_pcie_ep_driver);
...@@ -522,9 +522,9 @@ static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie) ...@@ -522,9 +522,9 @@ static int mobiveil_pcie_integrated_interrupt_init(struct mobiveil_pcie *pcie)
mobiveil_pcie_enable_msi(pcie); mobiveil_pcie_enable_msi(pcie);
rp->irq = platform_get_irq(pdev, 0); rp->irq = platform_get_irq(pdev, 0);
if (rp->irq <= 0) { if (rp->irq < 0) {
dev_err(dev, "failed to map IRQ: %d\n", rp->irq); dev_err(dev, "failed to map IRQ: %d\n", rp->irq);
return -ENODEV; return rp->irq;
} }
/* initialize the IRQ domains */ /* initialize the IRQ domains */
......
...@@ -9,15 +9,18 @@ ...@@ -9,15 +9,18 @@
*/ */
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_pci.h> #include <linux/of_pci.h>
#include "../pci.h" #include "../pci.h"
...@@ -31,16 +34,6 @@ ...@@ -31,16 +34,6 @@
#define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2)
#define PCIE_CORE_DEV_REV_REG 0x8 #define PCIE_CORE_DEV_REV_REG 0x8
#define PCIE_CORE_PCIEXP_CAP 0xc0 #define PCIE_CORE_PCIEXP_CAP 0xc0
#define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8
#define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4)
#define PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT 5
#define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11)
#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT 12
#define PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ 0x2
#define PCIE_CORE_LINK_CTRL_STAT_REG 0xd0
#define PCIE_CORE_LINK_L0S_ENTRY BIT(0)
#define PCIE_CORE_LINK_TRAINING BIT(5)
#define PCIE_CORE_LINK_WIDTH_SHIFT 20
#define PCIE_CORE_ERR_CAPCTL_REG 0x118 #define PCIE_CORE_ERR_CAPCTL_REG 0x118
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX BIT(5) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX BIT(5)
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6) #define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
...@@ -101,6 +94,8 @@ ...@@ -101,6 +94,8 @@
#define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5) #define PCIE_CORE_CTRL2_STRICT_ORDER_ENABLE BIT(5)
#define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6) #define PCIE_CORE_CTRL2_OB_WIN_ENABLE BIT(6)
#define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10) #define PCIE_CORE_CTRL2_MSI_ENABLE BIT(10)
#define PCIE_CORE_REF_CLK_REG (CONTROL_BASE_ADDR + 0x14)
#define PCIE_CORE_REF_CLK_TX_ENABLE BIT(1)
#define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30) #define PCIE_MSG_LOG_REG (CONTROL_BASE_ADDR + 0x30)
#define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40) #define PCIE_ISR0_REG (CONTROL_BASE_ADDR + 0x40)
#define PCIE_MSG_PM_PME_MASK BIT(7) #define PCIE_MSG_PM_PME_MASK BIT(7)
...@@ -201,7 +196,10 @@ struct advk_pcie { ...@@ -201,7 +196,10 @@ struct advk_pcie {
struct mutex msi_used_lock; struct mutex msi_used_lock;
u16 msi_msg; u16 msi_msg;
int root_bus_nr; int root_bus_nr;
int link_gen;
struct pci_bridge_emul bridge; struct pci_bridge_emul bridge;
struct gpio_desc *reset_gpio;
struct phy *phy;
}; };
static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg) static inline void advk_writel(struct advk_pcie *pcie, u32 val, u64 reg)
...@@ -214,6 +212,11 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg) ...@@ -214,6 +212,11 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg)
return readl(pcie->base + reg); return readl(pcie->base + reg);
} }
static inline u16 advk_read16(struct advk_pcie *pcie, u64 reg)
{
return advk_readl(pcie, (reg & ~0x3)) >> ((reg & 0x3) * 8);
}
static int advk_pcie_link_up(struct advk_pcie *pcie) static int advk_pcie_link_up(struct advk_pcie *pcie)
{ {
u32 val, ltssm_state; u32 val, ltssm_state;
...@@ -225,20 +228,16 @@ static int advk_pcie_link_up(struct advk_pcie *pcie) ...@@ -225,20 +228,16 @@ static int advk_pcie_link_up(struct advk_pcie *pcie)
static int advk_pcie_wait_for_link(struct advk_pcie *pcie) static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
{ {
struct device *dev = &pcie->pdev->dev;
int retries; int retries;
/* check if the link is up or not */ /* check if the link is up or not */
for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) { for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
if (advk_pcie_link_up(pcie)) { if (advk_pcie_link_up(pcie))
dev_info(dev, "link up\n");
return 0; return 0;
}
usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX); usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
} }
dev_err(dev, "link never came up\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -253,10 +252,115 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie) ...@@ -253,10 +252,115 @@ static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
} }
} }
static int advk_pcie_train_at_gen(struct advk_pcie *pcie, int gen)
{
int ret, neg_gen;
u32 reg;
/* Setup link speed */
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~PCIE_GEN_SEL_MSK;
if (gen == 3)
reg |= SPEED_GEN_3;
else if (gen == 2)
reg |= SPEED_GEN_2;
else
reg |= SPEED_GEN_1;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/*
* Enable link training. This is not needed in every call to this
* function, just once suffices, but it does not break anything either.
*/
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg |= LINK_TRAINING_EN;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/*
* Start link training immediately after enabling it.
* This solves problems for some buggy cards.
*/
reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL);
reg |= PCI_EXP_LNKCTL_RL;
advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKCTL);
ret = advk_pcie_wait_for_link(pcie);
if (ret)
return ret;
reg = advk_read16(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_LNKSTA);
neg_gen = reg & PCI_EXP_LNKSTA_CLS;
return neg_gen;
}
static void advk_pcie_train_link(struct advk_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
int neg_gen = -1, gen;
/*
* Try link training at link gen specified by device tree property
* 'max-link-speed'. If this fails, iteratively train at lower gen.
*/
for (gen = pcie->link_gen; gen > 0; --gen) {
neg_gen = advk_pcie_train_at_gen(pcie, gen);
if (neg_gen > 0)
break;
}
if (neg_gen < 0)
goto err;
/*
* After successful training if negotiated gen is lower than requested,
* train again on negotiated gen. This solves some stability issues for
* some buggy gen1 cards.
*/
if (neg_gen < gen) {
gen = neg_gen;
neg_gen = advk_pcie_train_at_gen(pcie, gen);
}
if (neg_gen == gen) {
dev_info(dev, "link up at gen %i\n", gen);
return;
}
err:
dev_err(dev, "link never came up\n");
}
static void advk_pcie_issue_perst(struct advk_pcie *pcie)
{
u32 reg;
if (!pcie->reset_gpio)
return;
/* PERST does not work for some cards when link training is enabled */
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~LINK_TRAINING_EN;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/* 10ms delay is needed for some cards */
dev_info(&pcie->pdev->dev, "issuing PERST via reset GPIO for 10ms\n");
gpiod_set_value_cansleep(pcie->reset_gpio, 1);
usleep_range(10000, 11000);
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
}
static void advk_pcie_setup_hw(struct advk_pcie *pcie) static void advk_pcie_setup_hw(struct advk_pcie *pcie)
{ {
u32 reg; u32 reg;
advk_pcie_issue_perst(pcie);
/* Enable TX */
reg = advk_readl(pcie, PCIE_CORE_REF_CLK_REG);
reg |= PCIE_CORE_REF_CLK_TX_ENABLE;
advk_writel(pcie, reg, PCIE_CORE_REF_CLK_REG);
/* Set to Direct mode */ /* Set to Direct mode */
reg = advk_readl(pcie, CTRL_CONFIG_REG); reg = advk_readl(pcie, CTRL_CONFIG_REG);
reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT); reg &= ~(CTRL_MODE_MASK << CTRL_MODE_SHIFT);
...@@ -275,36 +379,26 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) ...@@ -275,36 +379,26 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV; PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV;
advk_writel(pcie, reg, PCIE_CORE_ERR_CAPCTL_REG); advk_writel(pcie, reg, PCIE_CORE_ERR_CAPCTL_REG);
/* Set PCIe Device Control and Status 1 PF0 register */ /* Set PCIe Device Control register */
reg = PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE | reg = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL);
(7 << PCIE_CORE_DEV_CTRL_STATS_MAX_PAYLOAD_SZ_SHIFT) | reg &= ~PCI_EXP_DEVCTL_RELAX_EN;
PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE | reg &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
(PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SZ << reg &= ~PCI_EXP_DEVCTL_READRQ;
PCIE_CORE_DEV_CTRL_STATS_MAX_RD_REQ_SIZE_SHIFT); reg |= PCI_EXP_DEVCTL_PAYLOAD; /* Set max payload size */
advk_writel(pcie, reg, PCIE_CORE_DEV_CTRL_STATS_REG); reg |= PCI_EXP_DEVCTL_READRQ_512B;
advk_writel(pcie, reg, PCIE_CORE_PCIEXP_CAP + PCI_EXP_DEVCTL);
/* Program PCIe Control 2 to disable strict ordering */ /* Program PCIe Control 2 to disable strict ordering */
reg = PCIE_CORE_CTRL2_RESERVED | reg = PCIE_CORE_CTRL2_RESERVED |
PCIE_CORE_CTRL2_TD_ENABLE; PCIE_CORE_CTRL2_TD_ENABLE;
advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG); advk_writel(pcie, reg, PCIE_CORE_CTRL2_REG);
/* Set GEN2 */
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~PCIE_GEN_SEL_MSK;
reg |= SPEED_GEN_2;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/* Set lane X1 */ /* Set lane X1 */
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG); reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg &= ~LANE_CNT_MSK; reg &= ~LANE_CNT_MSK;
reg |= LANE_COUNT_1; reg |= LANE_COUNT_1;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG); advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/* Enable link training */
reg = advk_readl(pcie, PCIE_CORE_CTRL0_REG);
reg |= LINK_TRAINING_EN;
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
/* Enable MSI */ /* Enable MSI */
reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG); reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
reg |= PCIE_CORE_CTRL2_MSI_ENABLE; reg |= PCIE_CORE_CTRL2_MSI_ENABLE;
...@@ -340,23 +434,22 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie) ...@@ -340,23 +434,22 @@ static void advk_pcie_setup_hw(struct advk_pcie *pcie)
/* /*
* PERST# signal could have been asserted by pinctrl subsystem before * PERST# signal could have been asserted by pinctrl subsystem before
* probe() callback has been called, making the endpoint going into * probe() callback has been called or issued explicitly by reset gpio
* function advk_pcie_issue_perst(), making the endpoint going into
* fundamental reset. As required by PCI Express spec a delay for at * fundamental reset. As required by PCI Express spec a delay for at
* least 100ms after such a reset before link training is needed. * least 100ms after such a reset before link training is needed.
*/ */
msleep(PCI_PM_D3COLD_WAIT); msleep(PCI_PM_D3COLD_WAIT);
/* Start link training */ advk_pcie_train_link(pcie);
reg = advk_readl(pcie, PCIE_CORE_LINK_CTRL_STAT_REG);
reg |= PCIE_CORE_LINK_TRAINING;
advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
advk_pcie_wait_for_link(pcie);
reg = PCIE_CORE_LINK_L0S_ENTRY |
(1 << PCIE_CORE_LINK_WIDTH_SHIFT);
advk_writel(pcie, reg, PCIE_CORE_LINK_CTRL_STAT_REG);
/*
* FIXME: The following register update is suspicious. This register is
* applicable only when the PCI controller is configured for Endpoint
* mode, not as a Root Complex. But apparently when this code is
* removed, some cards stop working. This should be investigated and
* a comment explaining this should be put here.
*/
reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG); reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG);
reg |= PCIE_CORE_CMD_MEM_ACCESS_EN | reg |= PCIE_CORE_CMD_MEM_ACCESS_EN |
PCIE_CORE_CMD_IO_ACCESS_EN | PCIE_CORE_CMD_IO_ACCESS_EN |
...@@ -952,6 +1045,62 @@ static irqreturn_t advk_pcie_irq_handler(int irq, void *arg) ...@@ -952,6 +1045,62 @@ static irqreturn_t advk_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
{
phy_power_off(pcie->phy);
phy_exit(pcie->phy);
}
static int advk_pcie_enable_phy(struct advk_pcie *pcie)
{
int ret;
if (!pcie->phy)
return 0;
ret = phy_init(pcie->phy);
if (ret)
return ret;
ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE);
if (ret) {
phy_exit(pcie->phy);
return ret;
}
ret = phy_power_on(pcie->phy);
if (ret) {
phy_exit(pcie->phy);
return ret;
}
return 0;
}
static int advk_pcie_setup_phy(struct advk_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
struct device_node *node = dev->of_node;
int ret = 0;
pcie->phy = devm_of_phy_get(dev, node, NULL);
if (IS_ERR(pcie->phy) && (PTR_ERR(pcie->phy) == -EPROBE_DEFER))
return PTR_ERR(pcie->phy);
/* Old bindings miss the PHY handle */
if (IS_ERR(pcie->phy)) {
dev_warn(dev, "PHY unavailable (%ld)\n", PTR_ERR(pcie->phy));
pcie->phy = NULL;
return 0;
}
ret = advk_pcie_enable_phy(pcie);
if (ret)
dev_err(dev, "Failed to initialize PHY (%d)\n", ret);
return ret;
}
static int advk_pcie_probe(struct platform_device *pdev) static int advk_pcie_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -973,6 +1122,9 @@ static int advk_pcie_probe(struct platform_device *pdev) ...@@ -973,6 +1122,9 @@ static int advk_pcie_probe(struct platform_device *pdev)
return PTR_ERR(pcie->base); return PTR_ERR(pcie->base);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_irq(dev, irq, advk_pcie_irq_handler, ret = devm_request_irq(dev, irq, advk_pcie_irq_handler,
IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie", IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie",
pcie); pcie);
...@@ -989,6 +1141,32 @@ static int advk_pcie_probe(struct platform_device *pdev) ...@@ -989,6 +1141,32 @@ static int advk_pcie_probe(struct platform_device *pdev)
} }
pcie->root_bus_nr = bus->start; pcie->root_bus_nr = bus->start;
pcie->reset_gpio = devm_gpiod_get_from_of_node(dev, dev->of_node,
"reset-gpios", 0,
GPIOD_OUT_LOW,
"pcie1-reset");
ret = PTR_ERR_OR_ZERO(pcie->reset_gpio);
if (ret) {
if (ret == -ENOENT) {
pcie->reset_gpio = NULL;
} else {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to get reset-gpio: %i\n",
ret);
return ret;
}
}
ret = of_pci_get_max_link_speed(dev->of_node);
if (ret <= 0 || ret > 3)
pcie->link_gen = 3;
else
pcie->link_gen = ret;
ret = advk_pcie_setup_phy(pcie);
if (ret)
return ret;
advk_pcie_setup_hw(pcie); advk_pcie_setup_hw(pcie);
advk_sw_pci_bridge_init(pcie); advk_sw_pci_bridge_init(pcie);
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_pci.h> #include <linux/of_pci.h>
#include <linux/pci-ecam.h> #include <linux/pci-ecam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -19,7 +21,7 @@ static void gen_pci_unmap_cfg(void *ptr) ...@@ -19,7 +21,7 @@ static void gen_pci_unmap_cfg(void *ptr)
} }
static struct pci_config_window *gen_pci_init(struct device *dev, static struct pci_config_window *gen_pci_init(struct device *dev,
struct list_head *resources, struct pci_ecam_ops *ops) struct list_head *resources, const struct pci_ecam_ops *ops)
{ {
int err; int err;
struct resource cfgres; struct resource cfgres;
...@@ -54,15 +56,19 @@ static struct pci_config_window *gen_pci_init(struct device *dev, ...@@ -54,15 +56,19 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
return ERR_PTR(err); return ERR_PTR(err);
} }
int pci_host_common_probe(struct platform_device *pdev, int pci_host_common_probe(struct platform_device *pdev)
struct pci_ecam_ops *ops)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
struct pci_config_window *cfg; struct pci_config_window *cfg;
struct list_head resources; struct list_head resources;
const struct pci_ecam_ops *ops;
int ret; int ret;
ops = of_device_get_match_data(&pdev->dev);
if (!ops)
return -ENODEV;
bridge = devm_pci_alloc_host_bridge(dev, 0); bridge = devm_pci_alloc_host_bridge(dev, 0);
if (!bridge) if (!bridge)
return -ENOMEM; return -ENOMEM;
...@@ -82,7 +88,7 @@ int pci_host_common_probe(struct platform_device *pdev, ...@@ -82,7 +88,7 @@ int pci_host_common_probe(struct platform_device *pdev,
bridge->dev.parent = dev; bridge->dev.parent = dev;
bridge->sysdata = cfg; bridge->sysdata = cfg;
bridge->busnr = cfg->busr.start; bridge->busnr = cfg->busr.start;
bridge->ops = &ops->pci_ops; bridge->ops = (struct pci_ops *)&ops->pci_ops;
bridge->map_irq = of_irq_parse_and_map_pci; bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle; bridge->swizzle_irq = pci_common_swizzle;
...@@ -95,6 +101,7 @@ int pci_host_common_probe(struct platform_device *pdev, ...@@ -95,6 +101,7 @@ int pci_host_common_probe(struct platform_device *pdev,
platform_set_drvdata(pdev, bridge->bus); platform_set_drvdata(pdev, bridge->bus);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_host_common_probe);
int pci_host_common_remove(struct platform_device *pdev) int pci_host_common_remove(struct platform_device *pdev)
{ {
...@@ -107,3 +114,6 @@ int pci_host_common_remove(struct platform_device *pdev) ...@@ -107,3 +114,6 @@ int pci_host_common_remove(struct platform_device *pdev)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_host_common_remove);
MODULE_LICENSE("GPL v2");
...@@ -10,12 +10,11 @@ ...@@ -10,12 +10,11 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_address.h> #include <linux/module.h>
#include <linux/of_pci.h>
#include <linux/pci-ecam.h> #include <linux/pci-ecam.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = { static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
.bus_shift = 16, .bus_shift = 16,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
...@@ -49,7 +48,7 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus, ...@@ -49,7 +48,7 @@ static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
return pci_ecam_map_bus(bus, devfn, where); return pci_ecam_map_bus(bus, devfn, where);
} }
static struct pci_ecam_ops pci_dw_ecam_bus_ops = { static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
.bus_shift = 20, .bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_dw_ecam_map_bus, .map_bus = pci_dw_ecam_map_bus,
...@@ -76,25 +75,16 @@ static const struct of_device_id gen_pci_of_match[] = { ...@@ -76,25 +75,16 @@ static const struct of_device_id gen_pci_of_match[] = {
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, gen_pci_of_match);
static int gen_pci_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct pci_ecam_ops *ops;
of_id = of_match_node(gen_pci_of_match, pdev->dev.of_node);
ops = (struct pci_ecam_ops *)of_id->data;
return pci_host_common_probe(pdev, ops);
}
static struct platform_driver gen_pci_driver = { static struct platform_driver gen_pci_driver = {
.driver = { .driver = {
.name = "pci-host-generic", .name = "pci-host-generic",
.of_match_table = gen_pci_of_match, .of_match_table = gen_pci_of_match,
.suppress_bind_attrs = true,
}, },
.probe = gen_pci_probe, .probe = pci_host_common_probe,
.remove = pci_host_common_remove, .remove = pci_host_common_remove,
}; };
builtin_platform_driver(gen_pci_driver); module_platform_driver(gen_pci_driver);
MODULE_LICENSE("GPL v2");
...@@ -480,6 +480,9 @@ struct hv_pcibus_device { ...@@ -480,6 +480,9 @@ struct hv_pcibus_device {
struct workqueue_struct *wq; struct workqueue_struct *wq;
/* Highest slot of child device with resources allocated */
int wslot_res_allocated;
/* hypercall arg, must not cross page boundary */ /* hypercall arg, must not cross page boundary */
struct hv_retarget_device_interrupt retarget_msi_interrupt_params; struct hv_retarget_device_interrupt retarget_msi_interrupt_params;
...@@ -2210,10 +2213,8 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus, ...@@ -2210,10 +2213,8 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
struct hv_dr_state *dr; struct hv_dr_state *dr;
int i; int i;
dr = kzalloc(offsetof(struct hv_dr_state, func) + dr = kzalloc(struct_size(dr, func, relations->device_count),
(sizeof(struct hv_pcidev_description) * GFP_NOWAIT);
(relations->device_count)), GFP_NOWAIT);
if (!dr) if (!dr)
return; return;
...@@ -2247,10 +2248,8 @@ static void hv_pci_devices_present2(struct hv_pcibus_device *hbus, ...@@ -2247,10 +2248,8 @@ static void hv_pci_devices_present2(struct hv_pcibus_device *hbus,
struct hv_dr_state *dr; struct hv_dr_state *dr;
int i; int i;
dr = kzalloc(offsetof(struct hv_dr_state, func) + dr = kzalloc(struct_size(dr, func, relations->device_count),
(sizeof(struct hv_pcidev_description) * GFP_NOWAIT);
(relations->device_count)), GFP_NOWAIT);
if (!dr) if (!dr)
return; return;
...@@ -2444,9 +2443,8 @@ static void hv_pci_onchannelcallback(void *context) ...@@ -2444,9 +2443,8 @@ static void hv_pci_onchannelcallback(void *context)
bus_rel = (struct pci_bus_relations *)buffer; bus_rel = (struct pci_bus_relations *)buffer;
if (bytes_recvd < if (bytes_recvd <
offsetof(struct pci_bus_relations, func) + struct_size(bus_rel, func,
(sizeof(struct pci_function_description) * bus_rel->device_count)) {
(bus_rel->device_count))) {
dev_err(&hbus->hdev->device, dev_err(&hbus->hdev->device,
"bus relations too small\n"); "bus relations too small\n");
break; break;
...@@ -2459,9 +2457,8 @@ static void hv_pci_onchannelcallback(void *context) ...@@ -2459,9 +2457,8 @@ static void hv_pci_onchannelcallback(void *context)
bus_rel2 = (struct pci_bus_relations2 *)buffer; bus_rel2 = (struct pci_bus_relations2 *)buffer;
if (bytes_recvd < if (bytes_recvd <
offsetof(struct pci_bus_relations2, func) + struct_size(bus_rel2, func,
(sizeof(struct pci_function_description2) * bus_rel2->device_count)) {
(bus_rel2->device_count))) {
dev_err(&hbus->hdev->device, dev_err(&hbus->hdev->device,
"bus relations v2 too small\n"); "bus relations v2 too small\n");
break; break;
...@@ -2748,6 +2745,8 @@ static void hv_free_config_window(struct hv_pcibus_device *hbus) ...@@ -2748,6 +2745,8 @@ static void hv_free_config_window(struct hv_pcibus_device *hbus)
vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH); vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
} }
static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs);
/** /**
* hv_pci_enter_d0() - Bring the "bus" into the D0 power state * hv_pci_enter_d0() - Bring the "bus" into the D0 power state
* @hdev: VMBus's tracking struct for this root PCI bus * @hdev: VMBus's tracking struct for this root PCI bus
...@@ -2760,8 +2759,10 @@ static int hv_pci_enter_d0(struct hv_device *hdev) ...@@ -2760,8 +2759,10 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
struct pci_bus_d0_entry *d0_entry; struct pci_bus_d0_entry *d0_entry;
struct hv_pci_compl comp_pkt; struct hv_pci_compl comp_pkt;
struct pci_packet *pkt; struct pci_packet *pkt;
bool retry = true;
int ret; int ret;
enter_d0_retry:
/* /*
* Tell the host that the bus is ready to use, and moved into the * Tell the host that the bus is ready to use, and moved into the
* powered-on state. This includes telling the host which region * powered-on state. This includes telling the host which region
...@@ -2788,6 +2789,38 @@ static int hv_pci_enter_d0(struct hv_device *hdev) ...@@ -2788,6 +2789,38 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
if (ret) if (ret)
goto exit; goto exit;
/*
* In certain case (Kdump) the pci device of interest was
* not cleanly shut down and resource is still held on host
* side, the host could return invalid device status.
* We need to explicitly request host to release the resource
* and try to enter D0 again.
*/
if (comp_pkt.completion_status < 0 && retry) {
retry = false;
dev_err(&hdev->device, "Retrying D0 Entry\n");
/*
* Hv_pci_bus_exit() calls hv_send_resource_released()
* to free up resources of its child devices.
* In the kdump kernel we need to set the
* wslot_res_allocated to 255 so it scans all child
* devices to release resources allocated in the
* normal kernel before panic happened.
*/
hbus->wslot_res_allocated = 255;
ret = hv_pci_bus_exit(hdev, true);
if (ret == 0) {
kfree(pkt);
goto enter_d0_retry;
}
dev_err(&hdev->device,
"Retrying D0 failed with ret %d\n", ret);
}
if (comp_pkt.completion_status < 0) { if (comp_pkt.completion_status < 0) {
dev_err(&hdev->device, dev_err(&hdev->device,
"PCI Pass-through VSP failed D0 Entry with status %x\n", "PCI Pass-through VSP failed D0 Entry with status %x\n",
...@@ -2859,7 +2892,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev) ...@@ -2859,7 +2892,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
struct hv_pci_dev *hpdev; struct hv_pci_dev *hpdev;
struct pci_packet *pkt; struct pci_packet *pkt;
size_t size_res; size_t size_res;
u32 wslot; int wslot;
int ret; int ret;
size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2) size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2)
...@@ -2912,6 +2945,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev) ...@@ -2912,6 +2945,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
comp_pkt.completion_status); comp_pkt.completion_status);
break; break;
} }
hbus->wslot_res_allocated = wslot;
} }
kfree(pkt); kfree(pkt);
...@@ -2930,10 +2965,10 @@ static int hv_send_resources_released(struct hv_device *hdev) ...@@ -2930,10 +2965,10 @@ static int hv_send_resources_released(struct hv_device *hdev)
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev); struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
struct pci_child_message pkt; struct pci_child_message pkt;
struct hv_pci_dev *hpdev; struct hv_pci_dev *hpdev;
u32 wslot; int wslot;
int ret; int ret;
for (wslot = 0; wslot < 256; wslot++) { for (wslot = hbus->wslot_res_allocated; wslot >= 0; wslot--) {
hpdev = get_pcichild_wslot(hbus, wslot); hpdev = get_pcichild_wslot(hbus, wslot);
if (!hpdev) if (!hpdev)
continue; continue;
...@@ -2948,8 +2983,12 @@ static int hv_send_resources_released(struct hv_device *hdev) ...@@ -2948,8 +2983,12 @@ static int hv_send_resources_released(struct hv_device *hdev)
VM_PKT_DATA_INBAND, 0); VM_PKT_DATA_INBAND, 0);
if (ret) if (ret)
return ret; return ret;
hbus->wslot_res_allocated = wslot - 1;
} }
hbus->wslot_res_allocated = -1;
return 0; return 0;
} }
...@@ -3049,6 +3088,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -3049,6 +3088,7 @@ static int hv_pci_probe(struct hv_device *hdev,
if (!hbus) if (!hbus)
return -ENOMEM; return -ENOMEM;
hbus->state = hv_pcibus_init; hbus->state = hv_pcibus_init;
hbus->wslot_res_allocated = -1;
/* /*
* The PCI bus "domain" is what is called "segment" in ACPI and other * The PCI bus "domain" is what is called "segment" in ACPI and other
...@@ -3148,7 +3188,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -3148,7 +3188,7 @@ static int hv_pci_probe(struct hv_device *hdev,
ret = hv_pci_allocate_bridge_windows(hbus); ret = hv_pci_allocate_bridge_windows(hbus);
if (ret) if (ret)
goto free_irq_domain; goto exit_d0;
ret = hv_send_resources_allocated(hdev); ret = hv_send_resources_allocated(hdev);
if (ret) if (ret)
...@@ -3166,6 +3206,8 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -3166,6 +3206,8 @@ static int hv_pci_probe(struct hv_device *hdev,
free_windows: free_windows:
hv_pci_free_bridge_windows(hbus); hv_pci_free_bridge_windows(hbus);
exit_d0:
(void) hv_pci_bus_exit(hdev, true);
free_irq_domain: free_irq_domain:
irq_domain_remove(hbus->irq_domain); irq_domain_remove(hbus->irq_domain);
free_fwnode: free_fwnode:
...@@ -3185,7 +3227,7 @@ static int hv_pci_probe(struct hv_device *hdev, ...@@ -3185,7 +3227,7 @@ static int hv_pci_probe(struct hv_device *hdev,
return ret; return ret;
} }
static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating) static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
{ {
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev); struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
struct { struct {
...@@ -3203,7 +3245,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating) ...@@ -3203,7 +3245,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
if (hdev->channel->rescind) if (hdev->channel->rescind)
return 0; return 0;
if (!hibernating) { if (!keep_devs) {
/* Delete any children which might still exist. */ /* Delete any children which might still exist. */
dr = kzalloc(sizeof(*dr), GFP_KERNEL); dr = kzalloc(sizeof(*dr), GFP_KERNEL);
if (dr && hv_pci_start_relations_work(hbus, dr)) if (dr && hv_pci_start_relations_work(hbus, dr))
......
...@@ -2219,8 +2219,8 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) ...@@ -2219,8 +2219,8 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
if (PTR_ERR(rp->reset_gpio) == -ENOENT) { if (PTR_ERR(rp->reset_gpio) == -ENOENT) {
rp->reset_gpio = NULL; rp->reset_gpio = NULL;
} else { } else {
dev_err(dev, "failed to get reset GPIO: %d\n", dev_err(dev, "failed to get reset GPIO: %ld\n",
err); PTR_ERR(rp->reset_gpio));
return PTR_ERR(rp->reset_gpio); return PTR_ERR(rp->reset_gpio);
} }
} }
...@@ -2712,7 +2712,7 @@ static int tegra_pcie_probe(struct platform_device *pdev) ...@@ -2712,7 +2712,7 @@ static int tegra_pcie_probe(struct platform_device *pdev)
err = pm_runtime_get_sync(pcie->dev); err = pm_runtime_get_sync(pcie->dev);
if (err < 0) { if (err < 0) {
dev_err(dev, "fail to enable pcie controller: %d\n", err); dev_err(dev, "fail to enable pcie controller: %d\n", err);
goto teardown_msi; goto pm_runtime_put;
} }
host->busnr = bus->start; host->busnr = bus->start;
...@@ -2746,7 +2746,6 @@ static int tegra_pcie_probe(struct platform_device *pdev) ...@@ -2746,7 +2746,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
pm_runtime_put: pm_runtime_put:
pm_runtime_put_sync(pcie->dev); pm_runtime_put_sync(pcie->dev);
pm_runtime_disable(pcie->dev); pm_runtime_disable(pcie->dev);
teardown_msi:
tegra_pcie_msi_teardown(pcie); tegra_pcie_msi_teardown(pcie);
put_resources: put_resources:
tegra_pcie_put_resources(pcie); tegra_pcie_put_resources(pcie);
......
...@@ -345,7 +345,7 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn, ...@@ -345,7 +345,7 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,
return pci_generic_config_write(bus, devfn, where, size, val); return pci_generic_config_write(bus, devfn, where, size, val);
} }
struct pci_ecam_ops pci_thunder_ecam_ops = { const struct pci_ecam_ops pci_thunder_ecam_ops = {
.bus_shift = 20, .bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
...@@ -357,22 +357,20 @@ struct pci_ecam_ops pci_thunder_ecam_ops = { ...@@ -357,22 +357,20 @@ struct pci_ecam_ops pci_thunder_ecam_ops = {
#ifdef CONFIG_PCI_HOST_THUNDER_ECAM #ifdef CONFIG_PCI_HOST_THUNDER_ECAM
static const struct of_device_id thunder_ecam_of_match[] = { static const struct of_device_id thunder_ecam_of_match[] = {
{ .compatible = "cavium,pci-host-thunder-ecam" }, {
.compatible = "cavium,pci-host-thunder-ecam",
.data = &pci_thunder_ecam_ops,
},
{ }, { },
}; };
static int thunder_ecam_probe(struct platform_device *pdev)
{
return pci_host_common_probe(pdev, &pci_thunder_ecam_ops);
}
static struct platform_driver thunder_ecam_driver = { static struct platform_driver thunder_ecam_driver = {
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.of_match_table = thunder_ecam_of_match, .of_match_table = thunder_ecam_of_match,
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
}, },
.probe = thunder_ecam_probe, .probe = pci_host_common_probe,
}; };
builtin_platform_driver(thunder_ecam_driver); builtin_platform_driver(thunder_ecam_driver);
......
...@@ -403,7 +403,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg) ...@@ -403,7 +403,7 @@ static int thunder_pem_acpi_init(struct pci_config_window *cfg)
return thunder_pem_init(dev, cfg, res_pem); return thunder_pem_init(dev, cfg, res_pem);
} }
struct pci_ecam_ops thunder_pem_ecam_ops = { const struct pci_ecam_ops thunder_pem_ecam_ops = {
.bus_shift = 24, .bus_shift = 24,
.init = thunder_pem_acpi_init, .init = thunder_pem_acpi_init,
.pci_ops = { .pci_ops = {
...@@ -440,7 +440,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg) ...@@ -440,7 +440,7 @@ static int thunder_pem_platform_init(struct pci_config_window *cfg)
return thunder_pem_init(dev, cfg, res_pem); return thunder_pem_init(dev, cfg, res_pem);
} }
static struct pci_ecam_ops pci_thunder_pem_ops = { static const struct pci_ecam_ops pci_thunder_pem_ops = {
.bus_shift = 24, .bus_shift = 24,
.init = thunder_pem_platform_init, .init = thunder_pem_platform_init,
.pci_ops = { .pci_ops = {
...@@ -451,22 +451,20 @@ static struct pci_ecam_ops pci_thunder_pem_ops = { ...@@ -451,22 +451,20 @@ static struct pci_ecam_ops pci_thunder_pem_ops = {
}; };
static const struct of_device_id thunder_pem_of_match[] = { static const struct of_device_id thunder_pem_of_match[] = {
{ .compatible = "cavium,pci-host-thunder-pem" }, {
.compatible = "cavium,pci-host-thunder-pem",
.data = &pci_thunder_pem_ops,
},
{ }, { },
}; };
static int thunder_pem_probe(struct platform_device *pdev)
{
return pci_host_common_probe(pdev, &pci_thunder_pem_ops);
}
static struct platform_driver thunder_pem_driver = { static struct platform_driver thunder_pem_driver = {
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.of_match_table = thunder_pem_of_match, .of_match_table = thunder_pem_of_match,
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
}, },
.probe = thunder_pem_probe, .probe = pci_host_common_probe,
}; };
builtin_platform_driver(thunder_pem_driver); builtin_platform_driver(thunder_pem_driver);
......
...@@ -720,7 +720,7 @@ static int v3_pci_probe(struct platform_device *pdev) ...@@ -720,7 +720,7 @@ static int v3_pci_probe(struct platform_device *pdev)
int irq; int irq;
int ret; int ret;
host = pci_alloc_host_bridge(sizeof(*v3)); host = devm_pci_alloc_host_bridge(dev, sizeof(*v3));
if (!host) if (!host)
return -ENOMEM; return -ENOMEM;
...@@ -777,9 +777,9 @@ static int v3_pci_probe(struct platform_device *pdev) ...@@ -777,9 +777,9 @@ static int v3_pci_probe(struct platform_device *pdev)
/* Get and request error IRQ resource */ /* Get and request error IRQ resource */
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq <= 0) { if (irq < 0) {
dev_err(dev, "unable to obtain PCIv3 error IRQ\n"); dev_err(dev, "unable to obtain PCIv3 error IRQ\n");
return -ENODEV; return irq;
} }
ret = devm_request_irq(dev, irq, v3_irq, 0, ret = devm_request_irq(dev, irq, v3_irq, 0,
"PCIv3 error", v3); "PCIv3 error", v3);
......
...@@ -256,7 +256,7 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) ...@@ -256,7 +256,7 @@ static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg)
return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_1); return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_1);
} }
struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { const struct pci_ecam_ops xgene_v1_pcie_ecam_ops = {
.bus_shift = 16, .bus_shift = 16,
.init = xgene_v1_pcie_ecam_init, .init = xgene_v1_pcie_ecam_init,
.pci_ops = { .pci_ops = {
...@@ -271,7 +271,7 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg) ...@@ -271,7 +271,7 @@ static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg)
return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_2); return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_2);
} }
struct pci_ecam_ops xgene_v2_pcie_ecam_ops = { const struct pci_ecam_ops xgene_v2_pcie_ecam_ops = {
.bus_shift = 16, .bus_shift = 16,
.init = xgene_v2_pcie_ecam_init, .init = xgene_v2_pcie_ecam_init,
.pci_ops = { .pci_ops = {
......
...@@ -193,7 +193,7 @@ static bool altera_pcie_valid_device(struct altera_pcie *pcie, ...@@ -193,7 +193,7 @@ static bool altera_pcie_valid_device(struct altera_pcie *pcie,
if (bus->number == pcie->root_bus_nr && dev > 0) if (bus->number == pcie->root_bus_nr && dev > 0)
return false; return false;
return true; return true;
} }
static int tlp_read_packet(struct altera_pcie *pcie, u32 *value) static int tlp_read_packet(struct altera_pcie *pcie, u32 *value)
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <soc/bcm2835/raspberrypi-firmware.h>
#include "../pci.h" #include "../pci.h"
/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ /* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */
...@@ -41,6 +43,9 @@ ...@@ -41,6 +43,9 @@
#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c #define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c
#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff #define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
#define PCIE_RC_DL_MDIO_ADDR 0x1100 #define PCIE_RC_DL_MDIO_ADDR 0x1100
#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 #define PCIE_RC_DL_MDIO_WR_DATA 0x1104
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 #define PCIE_RC_DL_MDIO_RD_DATA 0x1108
...@@ -54,11 +59,11 @@ ...@@ -54,11 +59,11 @@
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c
#define PCIE_MEM_WIN0_LO(win) \ #define PCIE_MEM_WIN0_LO(win) \
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 8)
#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 #define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010
#define PCIE_MEM_WIN0_HI(win) \ #define PCIE_MEM_WIN0_HI(win) \
PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 8)
#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c #define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c
#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f #define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f
...@@ -693,10 +698,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) ...@@ -693,10 +698,11 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
int num_out_wins = 0; int num_out_wins = 0;
u16 nlw, cls, lnksta; u16 nlw, cls, lnksta;
int i, ret; int i, ret;
u32 tmp; u32 tmp, aspm_support;
/* Reset the bridge */ /* Reset the bridge */
brcm_pcie_bridge_sw_init_set(pcie, 1); brcm_pcie_bridge_sw_init_set(pcie, 1);
brcm_pcie_perst_set(pcie, 1);
usleep_range(100, 200); usleep_range(100, 200);
...@@ -803,6 +809,15 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie) ...@@ -803,6 +809,15 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
num_out_wins++; num_out_wins++;
} }
/* Don't advertise L0s capability if 'aspm-no-l0s' */
aspm_support = PCIE_LINK_STATE_L1;
if (!of_property_read_bool(pcie->np, "aspm-no-l0s"))
aspm_support |= PCIE_LINK_STATE_L0S;
tmp = readl(base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
u32p_replace_bits(&tmp, aspm_support,
PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK);
writel(tmp, base + PCIE_RC_CFG_PRIV1_LINK_CAPABILITY);
/* /*
* For config space accesses on the RC, show the right class for * For config space accesses on the RC, show the right class for
* a PCIe-PCIe bridge (the default setting is to be EP mode). * a PCIe-PCIe bridge (the default setting is to be EP mode).
...@@ -899,7 +914,6 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie) ...@@ -899,7 +914,6 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
brcm_msi_remove(pcie); brcm_msi_remove(pcie);
brcm_pcie_turn_off(pcie); brcm_pcie_turn_off(pcie);
clk_disable_unprepare(pcie->clk); clk_disable_unprepare(pcie->clk);
clk_put(pcie->clk);
} }
static int brcm_pcie_remove(struct platform_device *pdev) static int brcm_pcie_remove(struct platform_device *pdev)
...@@ -917,11 +931,26 @@ static int brcm_pcie_probe(struct platform_device *pdev) ...@@ -917,11 +931,26 @@ static int brcm_pcie_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node, *msi_np; struct device_node *np = pdev->dev.of_node, *msi_np;
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
struct device_node *fw_np;
struct brcm_pcie *pcie; struct brcm_pcie *pcie;
struct pci_bus *child; struct pci_bus *child;
struct resource *res; struct resource *res;
int ret; int ret;
/*
* We have to wait for Raspberry Pi's firmware interface to be up as a
* PCI fixup, rpi_firmware_init_vl805(), depends on it. This driver's
* probe can race with the firmware interface's (see
* drivers/firmware/raspberrypi.c) and potentially break the PCI fixup.
*/
fw_np = of_find_compatible_node(NULL, NULL,
"raspberrypi,bcm2835-firmware");
if (fw_np && !rpi_firmware_get(fw_np)) {
of_node_put(fw_np);
return -EPROBE_DEFER;
}
of_node_put(fw_np);
bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie));
if (!bridge) if (!bridge)
return -ENOMEM; return -ENOMEM;
......
...@@ -651,6 +651,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port, ...@@ -651,6 +651,9 @@ static int mtk_pcie_setup_irq(struct mtk_pcie_port *port,
} }
port->irq = platform_get_irq(pdev, port->slot); port->irq = platform_get_irq(pdev, port->slot);
if (port->irq < 0)
return port->irq;
irq_set_chained_handler_and_data(port->irq, irq_set_chained_handler_and_data(port->irq,
mtk_pcie_intr_handler, port); mtk_pcie_intr_handler, port);
......
// SPDX-License-Identifier: GPL-2.0
/*
* PCIe endpoint driver for Renesas R-Car SoCs
* Copyright (c) 2020 Renesas Electronics Europe GmbH
*
* Author: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/pci-epc.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include "pcie-rcar.h"
#define RCAR_EPC_MAX_FUNCTIONS 1
/* Structure representing the PCIe interface */
struct rcar_pcie_endpoint {
struct rcar_pcie pcie;
phys_addr_t *ob_mapped_addr;
struct pci_epc_mem_window *ob_window;
u8 max_functions;
unsigned int bar_to_atu[MAX_NR_INBOUND_MAPS];
unsigned long *ib_window_map;
u32 num_ib_windows;
u32 num_ob_windows;
};
static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
{
u32 val;
rcar_pci_write_reg(pcie, 0, PCIETCTLR);
/* Set endpoint mode */
rcar_pci_write_reg(pcie, 0, PCIEMSR);
/* Initialize default capabilities. */
rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP);
rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ENDPOINT << 4);
rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
PCI_HEADER_TYPE_NORMAL);
/* Write out the physical slot number = 0 */
rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
val = rcar_pci_read_reg(pcie, EXPCAP(1));
/* device supports fixed 128 bytes MPSS */
val &= ~GENMASK(2, 0);
rcar_pci_write_reg(pcie, val, EXPCAP(1));
val = rcar_pci_read_reg(pcie, EXPCAP(2));
/* read requests size 128 bytes */
val &= ~GENMASK(14, 12);
/* payload size 128 bytes */
val &= ~GENMASK(7, 5);
rcar_pci_write_reg(pcie, val, EXPCAP(2));
/* Set target link speed to 5.0 GT/s */
rcar_rmw32(pcie, EXPCAP(12), PCI_EXP_LNKSTA_CLS,
PCI_EXP_LNKSTA_CLS_5_0GB);
/* Set the completion timer timeout to the maximum 50ms. */
rcar_rmw32(pcie, TLCTLR + 1, 0x3f, 50);
/* Terminate list of capabilities (Next Capability Offset=0) */
rcar_rmw32(pcie, RVCCAP(0), 0xfff00000, 0);
/* flush modifications */
wmb();
}
static int rcar_pcie_ep_get_window(struct rcar_pcie_endpoint *ep,
phys_addr_t addr)
{
int i;
for (i = 0; i < ep->num_ob_windows; i++)
if (ep->ob_window[i].phys_base == addr)
return i;
return -EINVAL;
}
static int rcar_pcie_parse_outbound_ranges(struct rcar_pcie_endpoint *ep,
struct platform_device *pdev)
{
struct rcar_pcie *pcie = &ep->pcie;
char outbound_name[10];
struct resource *res;
unsigned int i = 0;
ep->num_ob_windows = 0;
for (i = 0; i < RCAR_PCI_MAX_RESOURCES; i++) {
sprintf(outbound_name, "memory%u", i);
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM,
outbound_name);
if (!res) {
dev_err(pcie->dev, "missing outbound window %u\n", i);
return -EINVAL;
}
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res),
outbound_name)) {
dev_err(pcie->dev, "Cannot request memory region %s.\n",
outbound_name);
return -EIO;
}
ep->ob_window[i].phys_base = res->start;
ep->ob_window[i].size = resource_size(res);
/* controller doesn't support multiple allocation
* from same window, so set page_size to window size
*/
ep->ob_window[i].page_size = resource_size(res);
}
ep->num_ob_windows = i;
return 0;
}
static int rcar_pcie_ep_get_pdata(struct rcar_pcie_endpoint *ep,
struct platform_device *pdev)
{
struct rcar_pcie *pcie = &ep->pcie;
struct pci_epc_mem_window *window;
struct device *dev = pcie->dev;
struct resource res;
int err;
err = of_address_to_resource(dev->of_node, 0, &res);
if (err)
return err;
pcie->base = devm_ioremap_resource(dev, &res);
if (IS_ERR(pcie->base))
return PTR_ERR(pcie->base);
ep->ob_window = devm_kcalloc(dev, RCAR_PCI_MAX_RESOURCES,
sizeof(*window), GFP_KERNEL);
if (!ep->ob_window)
return -ENOMEM;
rcar_pcie_parse_outbound_ranges(ep, pdev);
err = of_property_read_u8(dev->of_node, "max-functions",
&ep->max_functions);
if (err < 0 || ep->max_functions > RCAR_EPC_MAX_FUNCTIONS)
ep->max_functions = RCAR_EPC_MAX_FUNCTIONS;
return 0;
}
static int rcar_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
struct pci_epf_header *hdr)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
struct rcar_pcie *pcie = &ep->pcie;
u32 val;
if (!fn)
val = hdr->vendorid;
else
val = rcar_pci_read_reg(pcie, IDSETR0);
val |= hdr->deviceid << 16;
rcar_pci_write_reg(pcie, val, IDSETR0);
val = hdr->revid;
val |= hdr->progif_code << 8;
val |= hdr->subclass_code << 16;
val |= hdr->baseclass_code << 24;
rcar_pci_write_reg(pcie, val, IDSETR1);
if (!fn)
val = hdr->subsys_vendor_id;
else
val = rcar_pci_read_reg(pcie, SUBIDSETR);
val |= hdr->subsys_id << 16;
rcar_pci_write_reg(pcie, val, SUBIDSETR);
if (hdr->interrupt_pin > PCI_INTERRUPT_INTA)
return -EINVAL;
val = rcar_pci_read_reg(pcie, PCICONF(15));
val |= (hdr->interrupt_pin << 8);
rcar_pci_write_reg(pcie, val, PCICONF(15));
return 0;
}
static int rcar_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
struct pci_epf_bar *epf_bar)
{
int flags = epf_bar->flags | LAR_ENABLE | LAM_64BIT;
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
u64 size = 1ULL << fls64(epf_bar->size - 1);
dma_addr_t cpu_addr = epf_bar->phys_addr;
enum pci_barno bar = epf_bar->barno;
struct rcar_pcie *pcie = &ep->pcie;
u32 mask;
int idx;
int err;
idx = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
if (idx >= ep->num_ib_windows) {
dev_err(pcie->dev, "no free inbound window\n");
return -EINVAL;
}
if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
flags |= IO_SPACE;
ep->bar_to_atu[bar] = idx;
/* use 64-bit BARs */
set_bit(idx, ep->ib_window_map);
set_bit(idx + 1, ep->ib_window_map);
if (cpu_addr > 0) {
unsigned long nr_zeros = __ffs64(cpu_addr);
u64 alignment = 1ULL << nr_zeros;
size = min(size, alignment);
}
size = min(size, 1ULL << 32);
mask = roundup_pow_of_two(size) - 1;
mask &= ~0xf;
rcar_pcie_set_inbound(pcie, cpu_addr,
0x0, mask | flags, idx, false);
err = rcar_pcie_wait_for_phyrdy(pcie);
if (err) {
dev_err(pcie->dev, "phy not ready\n");
return -EINVAL;
}
return 0;
}
static void rcar_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
struct pci_epf_bar *epf_bar)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
enum pci_barno bar = epf_bar->barno;
u32 atu_index = ep->bar_to_atu[bar];
rcar_pcie_set_inbound(&ep->pcie, 0x0, 0x0, 0x0, bar, false);
clear_bit(atu_index, ep->ib_window_map);
clear_bit(atu_index + 1, ep->ib_window_map);
}
static int rcar_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 interrupts)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
struct rcar_pcie *pcie = &ep->pcie;
u32 flags;
flags = rcar_pci_read_reg(pcie, MSICAP(fn));
flags |= interrupts << MSICAP0_MMESCAP_OFFSET;
rcar_pci_write_reg(pcie, flags, MSICAP(fn));
return 0;
}
static int rcar_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
struct rcar_pcie *pcie = &ep->pcie;
u32 flags;
flags = rcar_pci_read_reg(pcie, MSICAP(fn));
if (!(flags & MSICAP0_MSIE))
return -EINVAL;
return ((flags & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET);
}
static int rcar_pcie_ep_map_addr(struct pci_epc *epc, u8 fn,
phys_addr_t addr, u64 pci_addr, size_t size)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
struct rcar_pcie *pcie = &ep->pcie;
struct resource_entry win;
struct resource res;
int window;
int err;
/* check if we have a link. */
err = rcar_pcie_wait_for_dl(pcie);
if (err) {
dev_err(pcie->dev, "link not up\n");
return err;
}
window = rcar_pcie_ep_get_window(ep, addr);
if (window < 0) {
dev_err(pcie->dev, "failed to get corresponding window\n");
return -EINVAL;
}
memset(&win, 0x0, sizeof(win));
memset(&res, 0x0, sizeof(res));
res.start = pci_addr;
res.end = pci_addr + size - 1;
res.flags = IORESOURCE_MEM;
win.res = &res;
rcar_pcie_set_outbound(pcie, window, &win);
ep->ob_mapped_addr[window] = addr;
return 0;
}
static void rcar_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
phys_addr_t addr)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
struct resource_entry win;
struct resource res;
int idx;
for (idx = 0; idx < ep->num_ob_windows; idx++)
if (ep->ob_mapped_addr[idx] == addr)
break;
if (idx >= ep->num_ob_windows)
return;
memset(&win, 0x0, sizeof(win));
memset(&res, 0x0, sizeof(res));
win.res = &res;
rcar_pcie_set_outbound(&ep->pcie, idx, &win);
ep->ob_mapped_addr[idx] = 0;
}
static int rcar_pcie_ep_assert_intx(struct rcar_pcie_endpoint *ep,
u8 fn, u8 intx)
{
struct rcar_pcie *pcie = &ep->pcie;
u32 val;
val = rcar_pci_read_reg(pcie, PCIEMSITXR);
if ((val & PCI_MSI_FLAGS_ENABLE)) {
dev_err(pcie->dev, "MSI is enabled, cannot assert INTx\n");
return -EINVAL;
}
val = rcar_pci_read_reg(pcie, PCICONF(1));
if ((val & INTDIS)) {
dev_err(pcie->dev, "INTx message transmission is disabled\n");
return -EINVAL;
}
val = rcar_pci_read_reg(pcie, PCIEINTXR);
if ((val & ASTINTX)) {
dev_err(pcie->dev, "INTx is already asserted\n");
return -EINVAL;
}
val |= ASTINTX;
rcar_pci_write_reg(pcie, val, PCIEINTXR);
usleep_range(1000, 1001);
val = rcar_pci_read_reg(pcie, PCIEINTXR);
val &= ~ASTINTX;
rcar_pci_write_reg(pcie, val, PCIEINTXR);
return 0;
}
static int rcar_pcie_ep_assert_msi(struct rcar_pcie *pcie,
u8 fn, u8 interrupt_num)
{
u16 msi_count;
u32 val;
/* Check MSI enable bit */
val = rcar_pci_read_reg(pcie, MSICAP(fn));
if (!(val & MSICAP0_MSIE))
return -EINVAL;
/* Get MSI numbers from MME */
msi_count = ((val & MSICAP0_MMESE_MASK) >> MSICAP0_MMESE_OFFSET);
msi_count = 1 << msi_count;
if (!interrupt_num || interrupt_num > msi_count)
return -EINVAL;
val = rcar_pci_read_reg(pcie, PCIEMSITXR);
rcar_pci_write_reg(pcie, val | (interrupt_num - 1), PCIEMSITXR);
return 0;
}
static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
enum pci_epc_irq_type type,
u16 interrupt_num)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
switch (type) {
case PCI_EPC_IRQ_LEGACY:
return rcar_pcie_ep_assert_intx(ep, fn, 0);
case PCI_EPC_IRQ_MSI:
return rcar_pcie_ep_assert_msi(&ep->pcie, fn, interrupt_num);
default:
return -EINVAL;
}
}
static int rcar_pcie_ep_start(struct pci_epc *epc)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
rcar_pci_write_reg(&ep->pcie, MACCTLR_INIT_VAL, MACCTLR);
rcar_pci_write_reg(&ep->pcie, CFINIT, PCIETCTLR);
return 0;
}
static void rcar_pcie_ep_stop(struct pci_epc *epc)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
rcar_pci_write_reg(&ep->pcie, 0, PCIETCTLR);
}
static const struct pci_epc_features rcar_pcie_epc_features = {
.linkup_notifier = false,
.msi_capable = true,
.msix_capable = false,
/* use 64-bit BARs so mark BAR[1,3,5] as reserved */
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
.bar_fixed_64bit = 1 << BAR_0 | 1 << BAR_2 | 1 << BAR_4,
.bar_fixed_size[0] = 128,
.bar_fixed_size[2] = 256,
.bar_fixed_size[4] = 256,
};
static const struct pci_epc_features*
rcar_pcie_ep_get_features(struct pci_epc *epc, u8 func_no)
{
return &rcar_pcie_epc_features;
}
static const struct pci_epc_ops rcar_pcie_epc_ops = {
.write_header = rcar_pcie_ep_write_header,
.set_bar = rcar_pcie_ep_set_bar,
.clear_bar = rcar_pcie_ep_clear_bar,
.set_msi = rcar_pcie_ep_set_msi,
.get_msi = rcar_pcie_ep_get_msi,
.map_addr = rcar_pcie_ep_map_addr,
.unmap_addr = rcar_pcie_ep_unmap_addr,
.raise_irq = rcar_pcie_ep_raise_irq,
.start = rcar_pcie_ep_start,
.stop = rcar_pcie_ep_stop,
.get_features = rcar_pcie_ep_get_features,
};
static const struct of_device_id rcar_pcie_ep_of_match[] = {
{ .compatible = "renesas,r8a774c0-pcie-ep", },
{ .compatible = "renesas,rcar-gen3-pcie-ep" },
{ },
};
static int rcar_pcie_ep_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rcar_pcie_endpoint *ep;
struct rcar_pcie *pcie;
struct pci_epc *epc;
int err;
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
if (!ep)
return -ENOMEM;
pcie = &ep->pcie;
pcie->dev = dev;
pm_runtime_enable(dev);
err = pm_runtime_get_sync(dev);
if (err < 0) {
dev_err(dev, "pm_runtime_get_sync failed\n");
goto err_pm_disable;
}
err = rcar_pcie_ep_get_pdata(ep, pdev);
if (err < 0) {
dev_err(dev, "failed to request resources: %d\n", err);
goto err_pm_put;
}
ep->num_ib_windows = MAX_NR_INBOUND_MAPS;
ep->ib_window_map =
devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows),
sizeof(long), GFP_KERNEL);
if (!ep->ib_window_map) {
err = -ENOMEM;
dev_err(dev, "failed to allocate memory for inbound map\n");
goto err_pm_put;
}
ep->ob_mapped_addr = devm_kcalloc(dev, ep->num_ob_windows,
sizeof(*ep->ob_mapped_addr),
GFP_KERNEL);
if (!ep->ob_mapped_addr) {
err = -ENOMEM;
dev_err(dev, "failed to allocate memory for outbound memory pointers\n");
goto err_pm_put;
}
epc = devm_pci_epc_create(dev, &rcar_pcie_epc_ops);
if (IS_ERR(epc)) {
dev_err(dev, "failed to create epc device\n");
err = PTR_ERR(epc);
goto err_pm_put;
}
epc->max_functions = ep->max_functions;
epc_set_drvdata(epc, ep);
rcar_pcie_ep_hw_init(pcie);
err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows);
if (err < 0) {
dev_err(dev, "failed to initialize the epc memory space\n");
goto err_pm_put;
}
return 0;
err_pm_put:
pm_runtime_put(dev);
err_pm_disable:
pm_runtime_disable(dev);
return err;
}
static struct platform_driver rcar_pcie_ep_driver = {
.driver = {
.name = "rcar-pcie-ep",
.of_match_table = rcar_pcie_ep_of_match,
.suppress_bind_attrs = true,
},
.probe = rcar_pcie_ep_probe,
};
builtin_platform_driver(rcar_pcie_ep_driver);
此差异已折叠。
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0 */
/*
* PCIe driver for Renesas R-Car SoCs
* Copyright (C) 2014-2020 Renesas Electronics Europe Ltd
*
* Author: Phil Edworthy <phil.edworthy@renesas.com>
*/
#ifndef _PCIE_RCAR_H
#define _PCIE_RCAR_H
#define PCIECAR 0x000010
#define PCIECCTLR 0x000018
#define CONFIG_SEND_ENABLE BIT(31)
#define TYPE0 (0 << 8)
#define TYPE1 BIT(8)
#define PCIECDR 0x000020
#define PCIEMSR 0x000028
#define PCIEINTXR 0x000400
#define ASTINTX BIT(16)
#define PCIEPHYSR 0x0007f0
#define PHYRDY BIT(0)
#define PCIEMSITXR 0x000840
/* Transfer control */
#define PCIETCTLR 0x02000
#define DL_DOWN BIT(3)
#define CFINIT BIT(0)
#define PCIETSTR 0x02004
#define DATA_LINK_ACTIVE BIT(0)
#define PCIEERRFR 0x02020
#define UNSUPPORTED_REQUEST BIT(4)
#define PCIEMSIFR 0x02044
#define PCIEMSIALR 0x02048
#define MSIFE BIT(0)
#define PCIEMSIAUR 0x0204c
#define PCIEMSIIER 0x02050
/* root port address */
#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
/* local address reg & mask */
#define PCIELAR(x) (0x02200 + ((x) * 0x20))
#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
#define LAM_PREFETCH BIT(3)
#define LAM_64BIT BIT(2)
#define LAR_ENABLE BIT(1)
/* PCIe address reg & mask */
#define PCIEPALR(x) (0x03400 + ((x) * 0x20))
#define PCIEPAUR(x) (0x03404 + ((x) * 0x20))
#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
#define PAR_ENABLE BIT(31)
#define IO_SPACE BIT(8)
/* Configuration */
#define PCICONF(x) (0x010000 + ((x) * 0x4))
#define INTDIS BIT(10)
#define PMCAP(x) (0x010040 + ((x) * 0x4))
#define MSICAP(x) (0x010050 + ((x) * 0x4))
#define MSICAP0_MSIE BIT(16)
#define MSICAP0_MMESCAP_OFFSET 17
#define MSICAP0_MMESE_OFFSET 20
#define MSICAP0_MMESE_MASK GENMASK(22, 20)
#define EXPCAP(x) (0x010070 + ((x) * 0x4))
#define VCCAP(x) (0x010100 + ((x) * 0x4))
/* link layer */
#define IDSETR0 0x011000
#define IDSETR1 0x011004
#define SUBIDSETR 0x011024
#define TLCTLR 0x011048
#define MACSR 0x011054
#define SPCHGFIN BIT(4)
#define SPCHGFAIL BIT(6)
#define SPCHGSUC BIT(7)
#define LINK_SPEED (0xf << 16)
#define LINK_SPEED_2_5GTS (1 << 16)
#define LINK_SPEED_5_0GTS (2 << 16)
#define MACCTLR 0x011058
#define MACCTLR_NFTS_MASK GENMASK(23, 16) /* The name is from SH7786 */
#define SPEED_CHANGE BIT(24)
#define SCRAMBLE_DISABLE BIT(27)
#define LTSMDIS BIT(31)
#define MACCTLR_INIT_VAL (LTSMDIS | MACCTLR_NFTS_MASK)
#define PMSR 0x01105c
#define MACS2R 0x011078
#define MACCGSPSETR 0x011084
#define SPCNGRSN BIT(31)
/* R-Car H1 PHY */
#define H1_PCIEPHYADRR 0x04000c
#define WRITE_CMD BIT(16)
#define PHY_ACK BIT(24)
#define RATE_POS 12
#define LANE_POS 8
#define ADR_POS 0
#define H1_PCIEPHYDOUTR 0x040014
/* R-Car Gen2 PHY */
#define GEN2_PCIEPHYADDR 0x780
#define GEN2_PCIEPHYDATA 0x784
#define GEN2_PCIEPHYCTRL 0x78c
#define INT_PCI_MSI_NR 32
#define RCONF(x) (PCICONF(0) + (x))
#define RPMCAP(x) (PMCAP(0) + (x))
#define REXPCAP(x) (EXPCAP(0) + (x))
#define RVCCAP(x) (VCCAP(0) + (x))
#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
#define RCAR_PCI_MAX_RESOURCES 4
#define MAX_NR_INBOUND_MAPS 6
struct rcar_pcie {
struct device *dev;
void __iomem *base;
};
enum {
RCAR_PCI_ACCESS_READ,
RCAR_PCI_ACCESS_WRITE,
};
void rcar_pci_write_reg(struct rcar_pcie *pcie, u32 val, unsigned int reg);
u32 rcar_pci_read_reg(struct rcar_pcie *pcie, unsigned int reg);
void rcar_rmw32(struct rcar_pcie *pcie, int where, u32 mask, u32 data);
int rcar_pcie_wait_for_phyrdy(struct rcar_pcie *pcie);
int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie);
void rcar_pcie_set_outbound(struct rcar_pcie *pcie, int win,
struct resource_entry *window);
void rcar_pcie_set_inbound(struct rcar_pcie *pcie, u64 cpu_addr,
u64 pci_addr, u64 flags, int idx, bool host);
#endif
...@@ -615,7 +615,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev) ...@@ -615,7 +615,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG); rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);
err = pci_epc_mem_init(epc, rockchip->mem_res->start, err = pci_epc_mem_init(epc, rockchip->mem_res->start,
resource_size(rockchip->mem_res)); resource_size(rockchip->mem_res), PAGE_SIZE);
if (err < 0) { if (err < 0) {
dev_err(dev, "failed to initialize the memory space\n"); dev_err(dev, "failed to initialize the memory space\n");
goto err_uninit_port; goto err_uninit_port;
......
...@@ -207,7 +207,7 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn, ...@@ -207,7 +207,7 @@ static int smp8759_config_write(struct pci_bus *bus, unsigned int devfn,
return ret; return ret;
} }
static struct pci_ecam_ops smp8759_ecam_ops = { static const struct pci_ecam_ops smp8759_ecam_ops = {
.bus_shift = 20, .bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
...@@ -273,9 +273,9 @@ static int tango_pcie_probe(struct platform_device *pdev) ...@@ -273,9 +273,9 @@ static int tango_pcie_probe(struct platform_device *pdev)
writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset); writel_relaxed(0, pcie->base + SMP8759_ENABLE + offset);
virq = platform_get_irq(pdev, 1); virq = platform_get_irq(pdev, 1);
if (virq <= 0) { if (virq < 0) {
dev_err(dev, "Failed to map IRQ\n"); dev_err(dev, "Failed to map IRQ\n");
return -ENXIO; return virq;
} }
irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie); irq_dom = irq_domain_create_linear(fwnode, MSI_MAX, &dom_ops, pcie);
...@@ -295,11 +295,14 @@ static int tango_pcie_probe(struct platform_device *pdev) ...@@ -295,11 +295,14 @@ static int tango_pcie_probe(struct platform_device *pdev)
spin_lock_init(&pcie->used_msi_lock); spin_lock_init(&pcie->used_msi_lock);
irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie); irq_set_chained_handler_and_data(virq, tango_msi_isr, pcie);
return pci_host_common_probe(pdev, &smp8759_ecam_ops); return pci_host_common_probe(pdev);
} }
static const struct of_device_id tango_pcie_ids[] = { static const struct of_device_id tango_pcie_ids[] = {
{ .compatible = "sigma,smp8759-pcie" }, {
.compatible = "sigma,smp8759-pcie",
.data = &smp8759_ecam_ops,
},
{ }, { },
}; };
......
...@@ -445,9 +445,11 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features) ...@@ -445,9 +445,11 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
if (!membar2) if (!membar2)
return -ENOMEM; return -ENOMEM;
offset[0] = vmd->dev->resource[VMD_MEMBAR1].start - offset[0] = vmd->dev->resource[VMD_MEMBAR1].start -
readq(membar2 + MB2_SHADOW_OFFSET); (readq(membar2 + MB2_SHADOW_OFFSET) &
PCI_BASE_ADDRESS_MEM_MASK);
offset[1] = vmd->dev->resource[VMD_MEMBAR2].start - offset[1] = vmd->dev->resource[VMD_MEMBAR2].start -
readq(membar2 + MB2_SHADOW_OFFSET + 8); (readq(membar2 + MB2_SHADOW_OFFSET + 8) &
PCI_BASE_ADDRESS_MEM_MASK);
pci_iounmap(vmd->dev, membar2); pci_iounmap(vmd->dev, membar2);
} }
} }
......
...@@ -26,7 +26,7 @@ static const bool per_bus_mapping = !IS_ENABLED(CONFIG_64BIT); ...@@ -26,7 +26,7 @@ static const bool per_bus_mapping = !IS_ENABLED(CONFIG_64BIT);
*/ */
struct pci_config_window *pci_ecam_create(struct device *dev, struct pci_config_window *pci_ecam_create(struct device *dev,
struct resource *cfgres, struct resource *busr, struct resource *cfgres, struct resource *busr,
struct pci_ecam_ops *ops) const struct pci_ecam_ops *ops)
{ {
struct pci_config_window *cfg; struct pci_config_window *cfg;
unsigned int bus_range, bus_range_max, bsz; unsigned int bus_range, bus_range_max, bsz;
...@@ -101,6 +101,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev, ...@@ -101,6 +101,7 @@ struct pci_config_window *pci_ecam_create(struct device *dev,
pci_ecam_free(cfg); pci_ecam_free(cfg);
return ERR_PTR(err); return ERR_PTR(err);
} }
EXPORT_SYMBOL_GPL(pci_ecam_create);
void pci_ecam_free(struct pci_config_window *cfg) void pci_ecam_free(struct pci_config_window *cfg)
{ {
...@@ -121,6 +122,7 @@ void pci_ecam_free(struct pci_config_window *cfg) ...@@ -121,6 +122,7 @@ void pci_ecam_free(struct pci_config_window *cfg)
release_resource(&cfg->res); release_resource(&cfg->res);
kfree(cfg); kfree(cfg);
} }
EXPORT_SYMBOL_GPL(pci_ecam_free);
/* /*
* Function to implement the pci_ops ->map_bus method * Function to implement the pci_ops ->map_bus method
...@@ -143,9 +145,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, ...@@ -143,9 +145,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn,
base = cfg->win + (busn << cfg->ops->bus_shift); base = cfg->win + (busn << cfg->ops->bus_shift);
return base + (devfn << devfn_shift) + where; return base + (devfn << devfn_shift) + where;
} }
EXPORT_SYMBOL_GPL(pci_ecam_map_bus);
/* ECAM ops */ /* ECAM ops */
struct pci_ecam_ops pci_generic_ecam_ops = { const struct pci_ecam_ops pci_generic_ecam_ops = {
.bus_shift = 20, .bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
...@@ -153,10 +156,11 @@ struct pci_ecam_ops pci_generic_ecam_ops = { ...@@ -153,10 +156,11 @@ struct pci_ecam_ops pci_generic_ecam_ops = {
.write = pci_generic_config_write, .write = pci_generic_config_write,
} }
}; };
EXPORT_SYMBOL_GPL(pci_generic_ecam_ops);
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
/* ECAM ops for 32-bit access only (non-compliant) */ /* ECAM ops for 32-bit access only (non-compliant) */
struct pci_ecam_ops pci_32b_ops = { const struct pci_ecam_ops pci_32b_ops = {
.bus_shift = 20, .bus_shift = 20,
.pci_ops = { .pci_ops = {
.map_bus = pci_ecam_map_bus, .map_bus = pci_ecam_map_bus,
......
...@@ -187,6 +187,9 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test) ...@@ -187,6 +187,9 @@ static int pci_epf_test_init_dma_chan(struct pci_epf_test *epf_test)
*/ */
static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test) static void pci_epf_test_clean_dma_chan(struct pci_epf_test *epf_test)
{ {
if (!epf_test->dma_supported)
return;
dma_release_channel(epf_test->dma_chan); dma_release_channel(epf_test->dma_chan);
epf_test->dma_chan = NULL; epf_test->dma_chan = NULL;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
{ {
int order; int order;
unsigned int page_shift = ilog2(mem->page_size); unsigned int page_shift = ilog2(mem->window.page_size);
size--; size--;
size >>= page_shift; size >>= page_shift;
...@@ -36,62 +36,97 @@ static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size) ...@@ -36,62 +36,97 @@ static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
} }
/** /**
* __pci_epc_mem_init() - initialize the pci_epc_mem structure * pci_epc_multi_mem_init() - initialize the pci_epc_mem structure
* @epc: the EPC device that invoked pci_epc_mem_init * @epc: the EPC device that invoked pci_epc_mem_init
* @phys_base: the physical address of the base * @windows: pointer to windows supported by the device
* @size: the size of the address space * @num_windows: number of windows device supports
* @page_size: size of each page
* *
* Invoke to initialize the pci_epc_mem structure used by the * Invoke to initialize the pci_epc_mem structure used by the
* endpoint functions to allocate mapped PCI address. * endpoint functions to allocate mapped PCI address.
*/ */
int __pci_epc_mem_init(struct pci_epc *epc, phys_addr_t phys_base, size_t size, int pci_epc_multi_mem_init(struct pci_epc *epc,
size_t page_size) struct pci_epc_mem_window *windows,
unsigned int num_windows)
{ {
int ret; struct pci_epc_mem *mem = NULL;
struct pci_epc_mem *mem; unsigned long *bitmap = NULL;
unsigned long *bitmap;
unsigned int page_shift; unsigned int page_shift;
int pages; size_t page_size;
int bitmap_size; int bitmap_size;
int pages;
int ret;
int i;
if (page_size < PAGE_SIZE) epc->num_windows = 0;
page_size = PAGE_SIZE;
page_shift = ilog2(page_size); if (!windows || !num_windows)
pages = size >> page_shift; return -EINVAL;
bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
mem = kzalloc(sizeof(*mem), GFP_KERNEL); epc->windows = kcalloc(num_windows, sizeof(*epc->windows), GFP_KERNEL);
if (!mem) { if (!epc->windows)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
bitmap = kzalloc(bitmap_size, GFP_KERNEL); for (i = 0; i < num_windows; i++) {
if (!bitmap) { page_size = windows[i].page_size;
ret = -ENOMEM; if (page_size < PAGE_SIZE)
goto err_mem; page_size = PAGE_SIZE;
} page_shift = ilog2(page_size);
pages = windows[i].size >> page_shift;
bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
mem->bitmap = bitmap; mem = kzalloc(sizeof(*mem), GFP_KERNEL);
mem->phys_base = phys_base; if (!mem) {
mem->page_size = page_size; ret = -ENOMEM;
mem->pages = pages; i--;
mem->size = size; goto err_mem;
mutex_init(&mem->lock); }
bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!bitmap) {
ret = -ENOMEM;
kfree(mem);
i--;
goto err_mem;
}
mem->window.phys_base = windows[i].phys_base;
mem->window.size = windows[i].size;
mem->window.page_size = page_size;
mem->bitmap = bitmap;
mem->pages = pages;
mutex_init(&mem->lock);
epc->windows[i] = mem;
}
epc->mem = mem; epc->mem = epc->windows[0];
epc->num_windows = num_windows;
return 0; return 0;
err_mem: err_mem:
kfree(mem); for (; i >= 0; i--) {
mem = epc->windows[i];
kfree(mem->bitmap);
kfree(mem);
}
kfree(epc->windows);
return ret;
}
EXPORT_SYMBOL_GPL(pci_epc_multi_mem_init);
int pci_epc_mem_init(struct pci_epc *epc, phys_addr_t base,
size_t size, size_t page_size)
{
struct pci_epc_mem_window mem_window;
mem_window.phys_base = base;
mem_window.size = size;
mem_window.page_size = page_size;
err: return pci_epc_multi_mem_init(epc, &mem_window, 1);
return ret;
} }
EXPORT_SYMBOL_GPL(__pci_epc_mem_init); EXPORT_SYMBOL_GPL(pci_epc_mem_init);
/** /**
* pci_epc_mem_exit() - cleanup the pci_epc_mem structure * pci_epc_mem_exit() - cleanup the pci_epc_mem structure
...@@ -102,11 +137,22 @@ EXPORT_SYMBOL_GPL(__pci_epc_mem_init); ...@@ -102,11 +137,22 @@ EXPORT_SYMBOL_GPL(__pci_epc_mem_init);
*/ */
void pci_epc_mem_exit(struct pci_epc *epc) void pci_epc_mem_exit(struct pci_epc *epc)
{ {
struct pci_epc_mem *mem = epc->mem; struct pci_epc_mem *mem;
int i;
if (!epc->num_windows)
return;
for (i = 0; i < epc->num_windows; i++) {
mem = epc->windows[i];
kfree(mem->bitmap);
kfree(mem);
}
kfree(epc->windows);
epc->windows = NULL;
epc->mem = NULL; epc->mem = NULL;
kfree(mem->bitmap); epc->num_windows = 0;
kfree(mem);
} }
EXPORT_SYMBOL_GPL(pci_epc_mem_exit); EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
...@@ -122,31 +168,60 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_exit); ...@@ -122,31 +168,60 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_exit);
void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc, void __iomem *pci_epc_mem_alloc_addr(struct pci_epc *epc,
phys_addr_t *phys_addr, size_t size) phys_addr_t *phys_addr, size_t size)
{ {
int pageno;
void __iomem *virt_addr = NULL; void __iomem *virt_addr = NULL;
struct pci_epc_mem *mem = epc->mem; struct pci_epc_mem *mem;
unsigned int page_shift = ilog2(mem->page_size); unsigned int page_shift;
size_t align_size;
int pageno;
int order; int order;
int i;
size = ALIGN(size, mem->page_size); for (i = 0; i < epc->num_windows; i++) {
order = pci_epc_mem_get_order(mem, size); mem = epc->windows[i];
mutex_lock(&mem->lock);
mutex_lock(&mem->lock); align_size = ALIGN(size, mem->window.page_size);
pageno = bitmap_find_free_region(mem->bitmap, mem->pages, order); order = pci_epc_mem_get_order(mem, align_size);
if (pageno < 0)
goto ret;
*phys_addr = mem->phys_base + ((phys_addr_t)pageno << page_shift); pageno = bitmap_find_free_region(mem->bitmap, mem->pages,
virt_addr = ioremap(*phys_addr, size); order);
if (!virt_addr) if (pageno >= 0) {
bitmap_release_region(mem->bitmap, pageno, order); page_shift = ilog2(mem->window.page_size);
*phys_addr = mem->window.phys_base +
((phys_addr_t)pageno << page_shift);
virt_addr = ioremap(*phys_addr, align_size);
if (!virt_addr) {
bitmap_release_region(mem->bitmap,
pageno, order);
mutex_unlock(&mem->lock);
continue;
}
mutex_unlock(&mem->lock);
return virt_addr;
}
mutex_unlock(&mem->lock);
}
ret:
mutex_unlock(&mem->lock);
return virt_addr; return virt_addr;
} }
EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
static struct pci_epc_mem *pci_epc_get_matching_window(struct pci_epc *epc,
phys_addr_t phys_addr)
{
struct pci_epc_mem *mem;
int i;
for (i = 0; i < epc->num_windows; i++) {
mem = epc->windows[i];
if (phys_addr >= mem->window.phys_base &&
phys_addr < (mem->window.phys_base + mem->window.size))
return mem;
}
return NULL;
}
/** /**
* pci_epc_mem_free_addr() - free the allocated memory address * pci_epc_mem_free_addr() - free the allocated memory address
* @epc: the EPC device on which memory was allocated * @epc: the EPC device on which memory was allocated
...@@ -159,14 +234,23 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr); ...@@ -159,14 +234,23 @@ EXPORT_SYMBOL_GPL(pci_epc_mem_alloc_addr);
void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr, void pci_epc_mem_free_addr(struct pci_epc *epc, phys_addr_t phys_addr,
void __iomem *virt_addr, size_t size) void __iomem *virt_addr, size_t size)
{ {
struct pci_epc_mem *mem;
unsigned int page_shift;
size_t page_size;
int pageno; int pageno;
struct pci_epc_mem *mem = epc->mem;
unsigned int page_shift = ilog2(mem->page_size);
int order; int order;
mem = pci_epc_get_matching_window(epc, phys_addr);
if (!mem) {
pr_err("failed to get matching window\n");
return;
}
page_size = mem->window.page_size;
page_shift = ilog2(page_size);
iounmap(virt_addr); iounmap(virt_addr);
pageno = (phys_addr - mem->phys_base) >> page_shift; pageno = (phys_addr - mem->window.phys_base) >> page_shift;
size = ALIGN(size, mem->page_size); size = ALIGN(size, page_size);
order = pci_epc_mem_get_order(mem, size); order = pci_epc_mem_get_order(mem, size);
mutex_lock(&mem->lock); mutex_lock(&mem->lock);
bitmap_release_region(mem->bitmap, pageno, order); bitmap_release_region(mem->bitmap, pageno, order);
......
...@@ -148,8 +148,6 @@ struct controller { ...@@ -148,8 +148,6 @@ struct controller {
#define MRL_SENS(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_MRLSP) #define MRL_SENS(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_MRLSP)
#define ATTN_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_AIP) #define ATTN_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_AIP)
#define PWR_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_PIP) #define PWR_LED(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_PIP)
#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_HPS)
#define EMI(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_EIP)
#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS) #define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_NCCS)
#define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19) #define PSN(ctrl) (((ctrl)->slot_cap & PCI_EXP_SLTCAP_PSN) >> 19)
......
...@@ -435,7 +435,7 @@ static int rpaphp_drc_add_slot(struct device_node *dn) ...@@ -435,7 +435,7 @@ static int rpaphp_drc_add_slot(struct device_node *dn)
*/ */
int rpaphp_add_slot(struct device_node *dn) int rpaphp_add_slot(struct device_node *dn)
{ {
if (!dn->name || strcmp(dn->name, "pci")) if (!of_node_name_eq(dn, "pci"))
return 0; return 0;
if (of_find_property(dn, "ibm,drc-info", NULL)) if (of_find_property(dn, "ibm,drc-info", NULL))
......
...@@ -164,7 +164,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl); ...@@ -164,7 +164,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl); u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl); u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
int shpchp_configure_device(struct slot *p_slot); int shpchp_configure_device(struct slot *p_slot);
int shpchp_unconfigure_device(struct slot *p_slot); void shpchp_unconfigure_device(struct slot *p_slot);
void cleanup_slots(struct controller *ctrl); void cleanup_slots(struct controller *ctrl);
void shpchp_queue_pushbutton_work(struct work_struct *work); void shpchp_queue_pushbutton_work(struct work_struct *work);
int shpc_init(struct controller *ctrl, struct pci_dev *pdev); int shpc_init(struct controller *ctrl, struct pci_dev *pdev);
......
...@@ -341,8 +341,7 @@ static int remove_board(struct slot *p_slot) ...@@ -341,8 +341,7 @@ static int remove_board(struct slot *p_slot)
u8 hp_slot; u8 hp_slot;
int rc; int rc;
if (shpchp_unconfigure_device(p_slot)) shpchp_unconfigure_device(p_slot);
return(1);
hp_slot = p_slot->device - ctrl->slot_device_offset; hp_slot = p_slot->device - ctrl->slot_device_offset;
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
......
...@@ -61,9 +61,8 @@ int shpchp_configure_device(struct slot *p_slot) ...@@ -61,9 +61,8 @@ int shpchp_configure_device(struct slot *p_slot)
return ret; return ret;
} }
int shpchp_unconfigure_device(struct slot *p_slot) void shpchp_unconfigure_device(struct slot *p_slot)
{ {
int rc = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
struct pci_dev *dev, *temp; struct pci_dev *dev, *temp;
struct controller *ctrl = p_slot->ctrl; struct controller *ctrl = p_slot->ctrl;
...@@ -83,6 +82,4 @@ int shpchp_unconfigure_device(struct slot *p_slot) ...@@ -83,6 +82,4 @@ int shpchp_unconfigure_device(struct slot *p_slot)
} }
pci_unlock_rescan_remove(); pci_unlock_rescan_remove();
return rc;
} }
...@@ -592,7 +592,7 @@ int of_pci_get_max_link_speed(struct device_node *node) ...@@ -592,7 +592,7 @@ int of_pci_get_max_link_speed(struct device_node *node)
u32 max_link_speed; u32 max_link_speed;
if (of_property_read_u32(node, "max-link-speed", &max_link_speed) || if (of_property_read_u32(node, "max-link-speed", &max_link_speed) ||
max_link_speed > 4) max_link_speed == 0 || max_link_speed > 4)
return -EINVAL; return -EINVAL;
return max_link_speed; return max_link_speed;
......
...@@ -282,6 +282,8 @@ static const struct pci_p2pdma_whitelist_entry { ...@@ -282,6 +282,8 @@ static const struct pci_p2pdma_whitelist_entry {
} pci_p2pdma_whitelist[] = { } pci_p2pdma_whitelist[] = {
/* AMD ZEN */ /* AMD ZEN */
{PCI_VENDOR_ID_AMD, 0x1450, 0}, {PCI_VENDOR_ID_AMD, 0x1450, 0},
{PCI_VENDOR_ID_AMD, 0x15d0, 0},
{PCI_VENDOR_ID_AMD, 0x1630, 0},
/* Intel Xeon E5/Core i7 */ /* Intel Xeon E5/Core i7 */
{PCI_VENDOR_ID_INTEL, 0x3c00, REQ_SAME_HOST_BRIDGE}, {PCI_VENDOR_ID_INTEL, 0x3c00, REQ_SAME_HOST_BRIDGE},
......
...@@ -948,7 +948,7 @@ static bool acpi_pci_bridge_d3(struct pci_dev *dev) ...@@ -948,7 +948,7 @@ static bool acpi_pci_bridge_d3(struct pci_dev *dev)
* Look for a special _DSD property for the root port and if it * Look for a special _DSD property for the root port and if it
* is set we know the hierarchy behind it supports D3 just fine. * is set we know the hierarchy behind it supports D3 just fine.
*/ */
root = pci_find_pcie_root_port(dev); root = pcie_find_root_port(dev);
if (!root) if (!root)
return false; return false;
...@@ -1128,7 +1128,7 @@ void acpi_pci_add_bus(struct pci_bus *bus) ...@@ -1128,7 +1128,7 @@ void acpi_pci_add_bus(struct pci_bus *bus)
return; return;
obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3, obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3,
RESET_DELAY_DSM, NULL); DSM_PCI_POWER_ON_RESET_DELAY, NULL);
if (!obj) if (!obj)
return; return;
...@@ -1193,7 +1193,7 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev, ...@@ -1193,7 +1193,7 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
pdev->d3cold_delay = 0; pdev->d3cold_delay = 0;
obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3, obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3,
FUNCTION_DELAY_DSM, NULL); DSM_PCI_DEVICE_READINESS_DURATIONS, NULL);
if (!obj) if (!obj)
return; return;
......
...@@ -24,6 +24,17 @@ ...@@ -24,6 +24,17 @@
#define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END #define PCI_CAP_PCIE_START PCI_BRIDGE_CONF_END
#define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2) #define PCI_CAP_PCIE_END (PCI_CAP_PCIE_START + PCI_EXP_SLTSTA2 + 2)
/**
* struct pci_bridge_reg_behavior - register bits behaviors
* @ro: Read-Only bits
* @rw: Read-Write bits
* @w1c: Write-1-to-Clear bits
*
* Reads and Writes will be filtered by specified behavior. All other bits not
* declared are assumed 'Reserved' and will return 0 on reads, per PCIe 5.0:
* "Reserved register fields must be read only and must return 0 (all 0's for
* multi-bit fields) when read".
*/
struct pci_bridge_reg_behavior { struct pci_bridge_reg_behavior {
/* Read-only bits */ /* Read-only bits */
u32 ro; u32 ro;
...@@ -33,9 +44,6 @@ struct pci_bridge_reg_behavior { ...@@ -33,9 +44,6 @@ struct pci_bridge_reg_behavior {
/* Write-1-to-clear bits */ /* Write-1-to-clear bits */
u32 w1c; u32 w1c;
/* Reserved bits (hardwired to 0) */
u32 rsvd;
}; };
static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
...@@ -49,7 +57,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { ...@@ -49,7 +57,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
PCI_COMMAND_FAST_BACK) | PCI_COMMAND_FAST_BACK) |
(PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ | (PCI_STATUS_CAP_LIST | PCI_STATUS_66MHZ |
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16), PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MASK) << 16),
.rsvd = GENMASK(15, 10) | ((BIT(6) | GENMASK(3, 0)) << 16),
.w1c = PCI_STATUS_ERROR_BITS << 16, .w1c = PCI_STATUS_ERROR_BITS << 16,
}, },
[PCI_CLASS_REVISION / 4] = { .ro = ~0 }, [PCI_CLASS_REVISION / 4] = { .ro = ~0 },
...@@ -96,8 +103,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { ...@@ -96,8 +103,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
GENMASK(11, 8) | GENMASK(3, 0)), GENMASK(11, 8) | GENMASK(3, 0)),
.w1c = PCI_STATUS_ERROR_BITS << 16, .w1c = PCI_STATUS_ERROR_BITS << 16,
.rsvd = ((BIT(6) | GENMASK(4, 0)) << 16),
}, },
[PCI_MEMORY_BASE / 4] = { [PCI_MEMORY_BASE / 4] = {
...@@ -130,12 +135,10 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { ...@@ -130,12 +135,10 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
[PCI_CAPABILITY_LIST / 4] = { [PCI_CAPABILITY_LIST / 4] = {
.ro = GENMASK(7, 0), .ro = GENMASK(7, 0),
.rsvd = GENMASK(31, 8),
}, },
[PCI_ROM_ADDRESS1 / 4] = { [PCI_ROM_ADDRESS1 / 4] = {
.rw = GENMASK(31, 11) | BIT(0), .rw = GENMASK(31, 11) | BIT(0),
.rsvd = GENMASK(10, 1),
}, },
/* /*
...@@ -158,8 +161,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = { ...@@ -158,8 +161,6 @@ static const struct pci_bridge_reg_behavior pci_regs_behavior[] = {
.ro = (GENMASK(15, 8) | ((PCI_BRIDGE_CTL_FAST_BACK) << 16)), .ro = (GENMASK(15, 8) | ((PCI_BRIDGE_CTL_FAST_BACK) << 16)),
.w1c = BIT(10) << 16, .w1c = BIT(10) << 16,
.rsvd = (GENMASK(15, 12) | BIT(4)) << 16,
}, },
}; };
...@@ -181,31 +182,29 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { ...@@ -181,31 +182,29 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
.rw = GENMASK(15, 0), .rw = GENMASK(15, 0),
/* /*
* Device status register has 4 bits W1C, then 2 bits * Device status register has bits 6 and [3:0] W1C, [5:4] RO,
* RO, the rest is reserved * the rest is reserved
*/ */
.w1c = GENMASK(19, 16), .w1c = (BIT(6) | GENMASK(3, 0)) << 16,
.ro = GENMASK(20, 19), .ro = GENMASK(5, 4) << 16,
.rsvd = GENMASK(31, 21),
}, },
[PCI_EXP_LNKCAP / 4] = { [PCI_EXP_LNKCAP / 4] = {
/* All bits are RO, except bit 23 which is reserved */ /* All bits are RO, except bit 23 which is reserved */
.ro = lower_32_bits(~BIT(23)), .ro = lower_32_bits(~BIT(23)),
.rsvd = BIT(23),
}, },
[PCI_EXP_LNKCTL / 4] = { [PCI_EXP_LNKCTL / 4] = {
/* /*
* Link control has bits [1:0] and [11:3] RW, the * Link control has bits [15:14], [11:3] and [1:0] RW, the
* other bits are reserved. * rest is reserved.
* Link status has bits [13:0] RO, and bits [14:15] *
* Link status has bits [13:0] RO, and bits [15:14]
* W1C. * W1C.
*/ */
.rw = GENMASK(11, 3) | GENMASK(1, 0), .rw = GENMASK(15, 14) | GENMASK(11, 3) | GENMASK(1, 0),
.ro = GENMASK(13, 0) << 16, .ro = GENMASK(13, 0) << 16,
.w1c = GENMASK(15, 14) << 16, .w1c = GENMASK(15, 14) << 16,
.rsvd = GENMASK(15, 12) | BIT(2),
}, },
[PCI_EXP_SLTCAP / 4] = { [PCI_EXP_SLTCAP / 4] = {
...@@ -214,19 +213,18 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { ...@@ -214,19 +213,18 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
[PCI_EXP_SLTCTL / 4] = { [PCI_EXP_SLTCTL / 4] = {
/* /*
* Slot control has bits [12:0] RW, the rest is * Slot control has bits [14:0] RW, the rest is
* reserved. * reserved.
* *
* Slot status has a mix of W1C and RO bits, as well * Slot status has bits 8 and [4:0] W1C, bits [7:5] RO, the
* as reserved bits. * rest is reserved.
*/ */
.rw = GENMASK(12, 0), .rw = GENMASK(14, 0),
.w1c = (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | .w1c = (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC) << 16, PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC) << 16,
.ro = (PCI_EXP_SLTSTA_MRLSS | PCI_EXP_SLTSTA_PDS | .ro = (PCI_EXP_SLTSTA_MRLSS | PCI_EXP_SLTSTA_PDS |
PCI_EXP_SLTSTA_EIS) << 16, PCI_EXP_SLTSTA_EIS) << 16,
.rsvd = GENMASK(15, 12) | (GENMASK(15, 9) << 16),
}, },
[PCI_EXP_RTCTL / 4] = { [PCI_EXP_RTCTL / 4] = {
...@@ -234,19 +232,21 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { ...@@ -234,19 +232,21 @@ static const struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = {
* Root control has bits [4:0] RW, the rest is * Root control has bits [4:0] RW, the rest is
* reserved. * reserved.
* *
* Root status has bit 0 RO, the rest is reserved. * Root capabilities has bit 0 RO, the rest is reserved.
*/ */
.rw = (PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE | .rw = (PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE | PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE |
PCI_EXP_RTCTL_CRSSVE), PCI_EXP_RTCTL_CRSSVE),
.ro = PCI_EXP_RTCAP_CRSVIS << 16, .ro = PCI_EXP_RTCAP_CRSVIS << 16,
.rsvd = GENMASK(15, 5) | (GENMASK(15, 1) << 16),
}, },
[PCI_EXP_RTSTA / 4] = { [PCI_EXP_RTSTA / 4] = {
/*
* Root status has bits 17 and [15:0] RO, bit 16 W1C, the rest
* is reserved.
*/
.ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING, .ro = GENMASK(15, 0) | PCI_EXP_RTSTA_PENDING,
.w1c = PCI_EXP_RTSTA_PME, .w1c = PCI_EXP_RTSTA_PME,
.rsvd = GENMASK(31, 18),
}, },
}; };
...@@ -354,7 +354,8 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, ...@@ -354,7 +354,8 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
* Make sure we never return any reserved bit with a value * Make sure we never return any reserved bit with a value
* different from 0. * different from 0.
*/ */
*value &= ~behavior[reg / 4].rsvd; *value &= behavior[reg / 4].ro | behavior[reg / 4].rw |
behavior[reg / 4].w1c;
if (size == 1) if (size == 1)
*value = (*value >> (8 * (where & 3))) & 0xff; *value = (*value >> (8 * (where & 3))) & 0xff;
......
...@@ -178,7 +178,7 @@ static int dsm_get_label(struct device *dev, char *buf, ...@@ -178,7 +178,7 @@ static int dsm_get_label(struct device *dev, char *buf,
return -1; return -1;
obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 0x2, obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 0x2,
DEVICE_LABEL_DSM, NULL); DSM_PCI_DEVICE_NAME, NULL);
if (!obj) if (!obj)
return -1; return -1;
...@@ -218,7 +218,7 @@ static bool device_has_dsm(struct device *dev) ...@@ -218,7 +218,7 @@ static bool device_has_dsm(struct device *dev)
return false; return false;
return !!acpi_check_dsm(handle, &pci_acpi_dsm_guid, 0x2, return !!acpi_check_dsm(handle, &pci_acpi_dsm_guid, 0x2,
1 << DEVICE_LABEL_DSM); 1 << DSM_PCI_DEVICE_NAME);
} }
static umode_t acpi_index_string_exist(struct kobject *kobj, static umode_t acpi_index_string_exist(struct kobject *kobj,
......
...@@ -751,30 +751,6 @@ struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res) ...@@ -751,30 +751,6 @@ struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res)
} }
EXPORT_SYMBOL(pci_find_resource); EXPORT_SYMBOL(pci_find_resource);
/**
* pci_find_pcie_root_port - return PCIe Root Port
* @dev: PCI device to query
*
* Traverse up the parent chain and return the PCIe Root Port PCI Device
* for a given PCI Device.
*/
struct pci_dev *pci_find_pcie_root_port(struct pci_dev *dev)
{
struct pci_dev *bridge, *highest_pcie_bridge = dev;
bridge = pci_upstream_bridge(dev);
while (bridge && pci_is_pcie(bridge)) {
highest_pcie_bridge = bridge;
bridge = pci_upstream_bridge(bridge);
}
if (pci_pcie_type(highest_pcie_bridge) != PCI_EXP_TYPE_ROOT_PORT)
return NULL;
return highest_pcie_bridge;
}
EXPORT_SYMBOL(pci_find_pcie_root_port);
/** /**
* pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
* @dev: the PCI device to operate on * @dev: the PCI device to operate on
...@@ -868,7 +844,9 @@ static inline bool platform_pci_need_resume(struct pci_dev *dev) ...@@ -868,7 +844,9 @@ static inline bool platform_pci_need_resume(struct pci_dev *dev)
static inline bool platform_pci_bridge_d3(struct pci_dev *dev) static inline bool platform_pci_bridge_d3(struct pci_dev *dev)
{ {
return pci_platform_pm ? pci_platform_pm->bridge_d3(dev) : false; if (pci_platform_pm && pci_platform_pm->bridge_d3)
return pci_platform_pm->bridge_d3(dev);
return false;
} }
/** /**
...@@ -1578,7 +1556,7 @@ EXPORT_SYMBOL(pci_restore_state); ...@@ -1578,7 +1556,7 @@ EXPORT_SYMBOL(pci_restore_state);
struct pci_saved_state { struct pci_saved_state {
u32 config_space[16]; u32 config_space[16];
struct pci_cap_saved_data cap[0]; struct pci_cap_saved_data cap[];
}; };
/** /**
...@@ -4660,7 +4638,8 @@ static int pci_pm_reset(struct pci_dev *dev, int probe) ...@@ -4660,7 +4638,8 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
* pcie_wait_for_link_delay - Wait until link is active or inactive * pcie_wait_for_link_delay - Wait until link is active or inactive
* @pdev: Bridge device * @pdev: Bridge device
* @active: waiting for active or inactive? * @active: waiting for active or inactive?
* @delay: Delay to wait after link has become active (in ms) * @delay: Delay to wait after link has become active (in ms). Specify %0
* for no delay.
* *
* Use this to wait till link becomes active or inactive. * Use this to wait till link becomes active or inactive.
*/ */
...@@ -4673,10 +4652,10 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, ...@@ -4673,10 +4652,10 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
/* /*
* Some controllers might not implement link active reporting. In this * Some controllers might not implement link active reporting. In this
* case, we wait for 1000 + 100 ms. * case, we wait for 1000 ms + any delay requested by the caller.
*/ */
if (!pdev->link_active_reporting) { if (!pdev->link_active_reporting) {
msleep(1100); msleep(timeout + delay);
return true; return true;
} }
...@@ -4701,7 +4680,7 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, ...@@ -4701,7 +4680,7 @@ static bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active,
msleep(10); msleep(10);
timeout -= 10; timeout -= 10;
} }
if (active && ret) if (active && ret && delay)
msleep(delay); msleep(delay);
else if (ret != active) else if (ret != active)
pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n",
...@@ -4822,17 +4801,28 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev) ...@@ -4822,17 +4801,28 @@ void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev)
if (!pcie_downstream_port(dev)) if (!pcie_downstream_port(dev))
return; return;
if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) { /*
pci_dbg(dev, "waiting %d ms for downstream link\n", delay); * Per PCIe r5.0, sec 6.6.1, for downstream ports that support
msleep(delay); * speeds > 5 GT/s, we must wait for link training to complete
} else { * before the mandatory delay.
pci_dbg(dev, "waiting %d ms for downstream link, after activation\n", *
delay); * We can only tell when link training completes via DLL Link
if (!pcie_wait_for_link_delay(dev, true, delay)) { * Active, which is required for downstream ports that support
* speeds > 5 GT/s (sec 7.5.3.6). Unfortunately some common
* devices do not implement Link Active reporting even when it's
* required, so we'll check for that directly instead of checking
* the supported link speed. We assume devices without Link Active
* reporting can train in 100 ms regardless of speed.
*/
if (dev->link_active_reporting) {
pci_dbg(dev, "waiting for link to train\n");
if (!pcie_wait_for_link_delay(dev, true, 0)) {
/* Did not train, no need to wait any further */ /* Did not train, no need to wait any further */
return; return;
} }
} }
pci_dbg(child, "waiting %d ms to become accessible\n", delay);
msleep(delay);
if (!pci_device_is_present(child)) { if (!pci_device_is_present(child)) {
pci_dbg(child, "waiting additional %d ms to become accessible\n", delay); pci_dbg(child, "waiting additional %d ms to become accessible\n", delay);
......
...@@ -25,7 +25,6 @@ config PCIEAER ...@@ -25,7 +25,6 @@ config PCIEAER
bool "PCI Express Advanced Error Reporting support" bool "PCI Express Advanced Error Reporting support"
depends on PCIEPORTBUS depends on PCIEPORTBUS
select RAS select RAS
default y
help help
This enables PCI Express Root Port Advanced Error Reporting This enables PCI Express Root Port Advanced Error Reporting
(AER) driver support. Error reporting messages sent to Root (AER) driver support. Error reporting messages sent to Root
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus) ...@@ -160,6 +160,6 @@ void pci_remove_root_bus(struct pci_bus *bus)
host_bridge->bus = NULL; host_bridge->bus = NULL;
/* remove the host bridge */ /* remove the host bridge */
device_unregister(&host_bridge->dev); device_del(&host_bridge->dev);
} }
EXPORT_SYMBOL_GPL(pci_remove_root_bus); EXPORT_SYMBOL_GPL(pci_remove_root_bus);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册