mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
pci-v6.7-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmVBaU8UHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vwEdxAAo++s98+ZaaTdUuoV0Zpft1fuY6Yr mR80jUDxjHDbcI1G4iNVUSWG6pGIdlURnrBp5kU74FV9R2Ps3Fl49XQUHowE0HfH D/qmihiJQdnMsQKwzw3XGoTSINrDcF6nLafl9brBItVkgjNxfxSEbnweJMBf+Boc rpRXHzxbVHVjwwhBLODF2Wt/8sQ24w9c+wcQkpo7im8ZZReoigNMKgEa4J7tLlqA vTyPR/K6QeU8IBUk2ObCY3GeYrVuqi82eRK3Uwzu7IkQwA9orE416Okvq3Z026/h TUAivtrcygHaFRdGNvzspYLbc2hd2sEXF+KKKb6GNAjxuDWUhVQW4ObY4FgFkZ65 Gqz/05D6c1dqTS3vTxp3nZYpvPEbNnO1RaGRL4h0/mbU+QSPSlHXWd9Lfg6noVVd 3O+CcstQK8RzMiiWLeyctRPV5XIf7nGVQTJW5aCLajlHeJWcvygNpNG4N57j/hXQ gyEHrz3idXXHXkBKmyWZfre6YpLkxZtKyONZDHWI/AVhU0TgRdJWmqpRfC1kVVUe IUWBRcPUF4/r3jEu6t10N/aDWQN1uQzIsJNnCrKzAddPDTTYQJk8VVzKPo8SVxPD X+OjEMgBB/fXUfkJ7IMwgYnWaFJhxthrs6/3j1UqRvGYRoulE4NdWwJDky9UYIHd qV3dzuAxC/cpv08= =G//C -----END PGP SIGNATURE----- Merge tag 'pci-v6.7-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci Pull pci updates from Bjorn Helgaas: "Enumeration: - Use acpi_evaluate_dsm_typed() instead of open-coding _DSM evaluation to learn device characteristics (Andy Shevchenko) - Tidy multi-function header checks using new PCI_HEADER_TYPE_MASK definition (Ilpo Järvinen) - Simplify config access error checking in various drivers (Ilpo Järvinen) - Use pcie_capability_clear_word() (not pcie_capability_clear_and_set_word()) when only clearing (Ilpo Järvinen) - Add pci_get_base_class() to simplify finding devices using base class only (ignoring subclass and programming interface) (Sui Jingfeng) - Add pci_is_vga(), which includes ancient PCI_CLASS_NOT_DEFINED_VGA devices from before the Class Code was added to PCI (Sui Jingfeng) - Use pci_is_vga() for vgaarb, sysfs "boot_vga", virtio, qxl to include ancient VGA devices (Sui Jingfeng) Resource management: - Make pci_assign_unassigned_resources() non-init because sparc uses it after init (Randy Dunlap) Driver binding: - Retain .remove() and .probe() callbacks (previously __init) because sysfs may cause them to be called later (Uwe Kleine-König) - Prevent xHCI driver from claiming AMD VanGogh USB3 DRD device, so it can be claimed by dwc3 instead (Vicki Pfau) PCI device hotplug: - Add Ampere Altra Attention Indicator extension driver for acpiphp (D Scott Phillips) Power management: - Quirk VideoPropulsion Torrent QN16e with longer delay after reset (Lukas Wunner) - Prevent users from overriding drivers that say we shouldn't use D3cold (Lukas Wunner) - Avoid PME from D3hot/D3cold for AMD Rembrandt and Phoenix USB4 because wakeup interrupts from those states don't work if amd-pmc has put the platform in a hardware sleep state (Mario Limonciello) IOMMU: - Disable ATS for Intel IPU E2000 devices with invalidation message endianness erratum (Bartosz Pawlowski) Error handling: - Factor out interrupt enable/disable into helpers (Kai-Heng Feng) Peer-to-peer DMA: - Fix flexible-array usage in struct pci_p2pdma_pagemap in case we ever use pagemaps with multiple entries (Gustavo A. R. Silva) ASPM: - Revert a change that broke when drivers disabled L1 and users later enabled an L1.x substate via sysfs, and fix a similar issue when users disabled L1 via sysfs (Heiner Kallweit) Endpoint framework: - Fix double free in __pci_epc_create() (Dan Carpenter) - Use IS_ERR_OR_NULL() to simplify endpoint core (Ruan Jinjie) Cadence PCIe controller driver: - Drop unused "is_rc" member (Li Chen) Freescale Layerscape PCIe controller driver: - Enable 64-bit addressing in endpoint mode (Guanhua Gao) Intel VMD host bridge driver: - Fix multi-function header check (Ilpo Järvinen) Microsoft Hyper-V host bridge driver: - Annotate struct hv_dr_state with __counted_by (Kees Cook) NVIDIA Tegra194 PCIe controller driver: - Drop setting of LNKCAP_MLW (max link width) since dw_pcie_setup() already does this via dw_pcie_link_set_max_link_width() (Yoshihiro Shimoda) Qualcomm PCIe controller driver: - Use PCIE_SPEED2MBS_ENC() to simplify encoding of link speed (Manivannan Sadhasivam) - Add a .write_dbi2() callback so DBI2 register writes, e.g., for setting the BAR size, work correctly (Manivannan Sadhasivam) - Enable ASPM for platforms that use 1.9.0 ops, because the PCI core doesn't enable ASPM states that haven't been enabled by the firmware (Manivannan Sadhasivam) Renesas R-Car Gen4 PCIe controller driver: - Add DesignWare core support (set max link width, EDMA_UNROLL flag, .pre_init(), .deinit(), etc) for use by R-Car Gen4 driver (Yoshihiro Shimoda) - Add driver and DT schema for DesignWare-based Renesas R-Car Gen4 controller in both host and endpoint mode (Yoshihiro Shimoda) Xilinx NWL PCIe controller driver: - Update ECAM size to support 256 buses (Thippeswamy Havalige) - Stop setting bridge primary/secondary/subordinate bus numbers, since PCI core does this (Thippeswamy Havalige) Xilinx XDMA controller driver: - Add driver and DT schema for Zynq UltraScale+ MPSoCs devices with Xilinx XDMA Soft IP (Thippeswamy Havalige) Miscellaneous: - Use FIELD_GET()/FIELD_PREP() to simplify and reduce use of _SHIFT macros (Ilpo Järvinen, Bjorn Helgaas) - Remove logic_outb(), _outw(), outl() duplicate declarations (John Sanpe) - Replace unnecessary UTF-8 in Kconfig help text because menuconfig doesn't render it correctly (Liu Song)" * tag 'pci-v6.7-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (102 commits) PCI: qcom-ep: Add dedicated callback for writing to DBI2 registers PCI: Simplify pcie_capability_clear_and_set_word() to ..._clear_word() PCI: endpoint: Fix double free in __pci_epc_create() PCI: xilinx-xdma: Add Xilinx XDMA Root Port driver dt-bindings: PCI: xilinx-xdma: Add schemas for Xilinx XDMA PCIe Root Port Bridge PCI: xilinx-cpm: Move IRQ definitions to a common header PCI: xilinx-nwl: Modify ECAM size to enable support for 256 buses PCI: xilinx-nwl: Rename the NWL_ECAM_VALUE_DEFAULT macro dt-bindings: PCI: xilinx-nwl: Modify ECAM size in the DT example PCI: xilinx-nwl: Remove redundant code that sets Type 1 header fields PCI: hotplug: Add Ampere Altra Attention Indicator extension driver PCI/AER: Factor out interrupt toggling into helpers PCI: acpiphp: Allow built-in drivers for Attention Indicators PCI/portdrv: Use FIELD_GET() PCI/VC: Use FIELD_GET() PCI/PTM: Use FIELD_GET() PCI/PME: Use FIELD_GET() PCI/ATS: Use FIELD_GET() PCI/ATS: Show PASID Capability register width in bitmasks PCI/ASPM: Fix L1 substate handling in aspm_attr_store_common() ...
This commit is contained in:
commit
27beb3ca34
115
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
Normal file
115
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Renesas Electronics Corp.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/rcar-gen4-pci-ep.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Gen4 PCIe Endpoint
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dw-pcie-ep.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: renesas,r8a779f0-pcie-ep # R-Car S4-8
|
||||
- const: renesas,rcar-gen4-pcie-ep # R-Car Gen4
|
||||
|
||||
reg:
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: atu
|
||||
- const: dma
|
||||
- const: app
|
||||
- const: phy
|
||||
- const: addr_space
|
||||
|
||||
interrupts:
|
||||
maxItems: 3
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: dma
|
||||
- const: sft_ce
|
||||
- const: app
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: pwr
|
||||
|
||||
max-link-speed:
|
||||
maximum: 4
|
||||
|
||||
num-lanes:
|
||||
maximum: 4
|
||||
|
||||
max-functions:
|
||||
maximum: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a779f0-sysc.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pcie0_ep: pcie-ep@e65d0000 {
|
||||
compatible = "renesas,r8a779f0-pcie-ep", "renesas,rcar-gen4-pcie-ep";
|
||||
reg = <0 0xe65d0000 0 0x2000>, <0 0xe65d2000 0 0x1000>,
|
||||
<0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>,
|
||||
<0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>,
|
||||
<0 0xfe000000 0 0x400000>;
|
||||
reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "addr_space";
|
||||
interrupts = <GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "dma", "sft_ce", "app";
|
||||
clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>;
|
||||
clock-names = "core", "ref";
|
||||
power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 624>;
|
||||
reset-names = "pwr";
|
||||
max-link-speed = <4>;
|
||||
num-lanes = <2>;
|
||||
max-functions = /bits/ 8 <2>;
|
||||
};
|
||||
};
|
127
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
Normal file
127
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
Normal file
@ -0,0 +1,127 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Renesas Electronics Corp.
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/rcar-gen4-pci-host.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas R-Car Gen4 PCIe Host
|
||||
|
||||
maintainers:
|
||||
- Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dw-pcie.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: renesas,r8a779f0-pcie # R-Car S4-8
|
||||
- const: renesas,rcar-gen4-pcie # R-Car Gen4
|
||||
|
||||
reg:
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: atu
|
||||
- const: dma
|
||||
- const: app
|
||||
- const: phy
|
||||
- const: config
|
||||
|
||||
interrupts:
|
||||
maxItems: 4
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: msi
|
||||
- const: dma
|
||||
- const: sft_ce
|
||||
- const: app
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: ref
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: pwr
|
||||
|
||||
max-link-speed:
|
||||
maximum: 4
|
||||
|
||||
num-lanes:
|
||||
maximum: 4
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a779f0-cpg-mssr.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/power/r8a779f0-sysc.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pcie: pcie@e65d0000 {
|
||||
compatible = "renesas,r8a779f0-pcie", "renesas,rcar-gen4-pcie";
|
||||
reg = <0 0xe65d0000 0 0x1000>, <0 0xe65d2000 0 0x0800>,
|
||||
<0 0xe65d3000 0 0x2000>, <0 0xe65d5000 0 0x1200>,
|
||||
<0 0xe65d6200 0 0x0e00>, <0 0xe65d7000 0 0x0400>,
|
||||
<0 0xfe000000 0 0x400000>;
|
||||
reg-names = "dbi", "dbi2", "atu", "dma", "app", "phy", "config";
|
||||
interrupts = <GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 418 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 422 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "msi", "dma", "sft_ce", "app";
|
||||
clocks = <&cpg CPG_MOD 624>, <&pcie0_clkref>;
|
||||
clock-names = "core", "ref";
|
||||
power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 624>;
|
||||
reset-names = "pwr";
|
||||
max-link-speed = <4>;
|
||||
num-lanes = <2>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
bus-range = <0x00 0xff>;
|
||||
device_type = "pci";
|
||||
ranges = <0x01000000 0 0x00000000 0 0xfe000000 0 0x00400000>,
|
||||
<0x02000000 0 0x30000000 0 0x30000000 0 0x10000000>;
|
||||
dma-ranges = <0x42000000 0 0x00000000 0 0x00000000 1 0x00000000>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 7>;
|
||||
interrupt-map = <0 0 0 1 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 2 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 3 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<0 0 0 4 &gic GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH>;
|
||||
snps,enable-cdm-check;
|
||||
};
|
||||
};
|
@ -33,11 +33,11 @@ properties:
|
||||
specific for each activated function, while the rest of the sub-spaces
|
||||
are common for all of them (if there are more than one).
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 6
|
||||
maxItems: 7
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
|
@ -33,11 +33,11 @@ properties:
|
||||
normal controller functioning. iATU memory IO region is also required
|
||||
if the space is unrolled (IP-core version >= 4.80a).
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
items:
|
||||
oneOf:
|
||||
- description:
|
||||
|
@ -42,11 +42,11 @@ properties:
|
||||
are required for the normal controller work. iATU memory IO region is
|
||||
also required if the space is unrolled (IP-core version >= 4.80a).
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
maxItems: 7
|
||||
items:
|
||||
oneOf:
|
||||
- description:
|
||||
|
@ -118,7 +118,7 @@ examples:
|
||||
compatible = "xlnx,nwl-pcie-2.11";
|
||||
reg = <0x0 0xfd0e0000 0x0 0x1000>,
|
||||
<0x0 0xfd480000 0x0 0x1000>,
|
||||
<0x80 0x00000000 0x0 0x1000000>;
|
||||
<0x80 0x00000000 0x0 0x10000000>;
|
||||
reg-names = "breg", "pcireg", "cfg";
|
||||
ranges = <0x02000000 0x0 0xe0000000 0x0 0xe0000000 0x0 0x10000000>,
|
||||
<0x43000000 0x00000006 0x0 0x00000006 0x0 0x00000002 0x0>;
|
||||
|
114
Documentation/devicetree/bindings/pci/xlnx,xdma-host.yaml
Normal file
114
Documentation/devicetree/bindings/pci/xlnx,xdma-host.yaml
Normal file
@ -0,0 +1,114 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/xlnx,xdma-host.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx XDMA PL PCIe Root Port Bridge
|
||||
|
||||
maintainers:
|
||||
- Thippeswamy Havalige <thippeswamy.havalige@amd.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pci/pci-bus.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: xlnx,xdma-host-3.00
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ranges:
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: interrupt asserted when miscellaneous interrupt is received.
|
||||
- description: msi0 interrupt asserted when an MSI is received.
|
||||
- description: msi1 interrupt asserted when an MSI is received.
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: misc
|
||||
- const: msi0
|
||||
- const: msi1
|
||||
|
||||
interrupt-map-mask:
|
||||
items:
|
||||
- const: 0
|
||||
- const: 0
|
||||
- const: 0
|
||||
- const: 7
|
||||
|
||||
interrupt-map:
|
||||
maxItems: 4
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
|
||||
interrupt-controller:
|
||||
description: identifies the node as an interrupt controller
|
||||
type: object
|
||||
properties:
|
||||
interrupt-controller: true
|
||||
|
||||
"#address-cells":
|
||||
const: 0
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- interrupt-controller
|
||||
- "#address-cells"
|
||||
- "#interrupt-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- ranges
|
||||
- interrupts
|
||||
- interrupt-map
|
||||
- interrupt-map-mask
|
||||
- "#interrupt-cells"
|
||||
- interrupt-controller
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
pcie@a0000000 {
|
||||
compatible = "xlnx,xdma-host-3.00";
|
||||
reg = <0x0 0xa0000000 0x0 0x10000000>;
|
||||
ranges = <0x2000000 0x0 0xb0000000 0x0 0xb0000000 0x0 0x1000000>,
|
||||
<0x43000000 0x5 0x0 0x5 0x0 0x0 0x1000000>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
device_type = "pci";
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "misc", "msi0", "msi1";
|
||||
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &pcie_intc_0 0>,
|
||||
<0 0 0 2 &pcie_intc_0 1>,
|
||||
<0 0 0 3 &pcie_intc_0 2>,
|
||||
<0 0 0 4 &pcie_intc_0 3>;
|
||||
pcie_intc_0: interrupt-controller {
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
};
|
||||
};
|
||||
};
|
@ -16526,6 +16526,7 @@ L: linux-renesas-soc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/pci/*rcar*
|
||||
F: drivers/pci/controller/*rcar*
|
||||
F: drivers/pci/controller/dwc/*rcar*
|
||||
|
||||
PCI DRIVER FOR SAMSUNG EXYNOS
|
||||
M: Jingoo Han <jingoohan1@gmail.com>
|
||||
|
@ -183,16 +183,17 @@ miata_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
the 2nd 8259 controller. So we have to check for it first. */
|
||||
|
||||
if((slot == 7) && (PCI_FUNC(dev->devfn) == 3)) {
|
||||
u8 irq=0;
|
||||
struct pci_dev *pdev = pci_get_slot(dev->bus, dev->devfn & ~7);
|
||||
if(pdev == NULL || pci_read_config_byte(pdev, 0x40,&irq) != PCIBIOS_SUCCESSFUL) {
|
||||
pci_dev_put(pdev);
|
||||
u8 irq = 0;
|
||||
int ret;
|
||||
|
||||
if (!pdev)
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
pci_dev_put(pdev);
|
||||
return irq;
|
||||
}
|
||||
|
||||
ret = pci_read_config_byte(pdev, 0x40, &irq);
|
||||
pci_dev_put(pdev);
|
||||
|
||||
return ret == PCIBIOS_SUCCESSFUL ? irq : -1;
|
||||
}
|
||||
|
||||
return COMMON_TABLE_LOOKUP;
|
||||
|
@ -50,20 +50,21 @@ int __init pci_is_66mhz_capable(struct pci_channel *hose,
|
||||
int top_bus, int current_bus)
|
||||
{
|
||||
u32 pci_devfn;
|
||||
unsigned short vid;
|
||||
u16 vid;
|
||||
int cap66 = -1;
|
||||
u16 stat;
|
||||
int ret;
|
||||
|
||||
pr_info("PCI: Checking 66MHz capabilities...\n");
|
||||
|
||||
for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
|
||||
if (PCI_FUNC(pci_devfn))
|
||||
continue;
|
||||
if (early_read_config_word(hose, top_bus, current_bus,
|
||||
pci_devfn, PCI_VENDOR_ID, &vid) !=
|
||||
PCIBIOS_SUCCESSFUL)
|
||||
ret = early_read_config_word(hose, top_bus, current_bus,
|
||||
pci_devfn, PCI_VENDOR_ID, &vid);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
continue;
|
||||
if (vid == 0xffff)
|
||||
if (PCI_POSSIBLE_ERROR(vid))
|
||||
continue;
|
||||
|
||||
/* check 66MHz capability */
|
||||
|
@ -3,9 +3,11 @@
|
||||
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/vgaarb.h>
|
||||
#include <asm/amd_nb.h>
|
||||
#include <asm/hpet.h>
|
||||
@ -904,3 +906,60 @@ static void chromeos_fixup_apl_pci_l1ss_capability(struct pci_dev *dev)
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_save_apl_pci_l1ss_capability);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, 0x5ad6, chromeos_fixup_apl_pci_l1ss_capability);
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
/*
|
||||
* Root Ports on some AMD SoCs advertise PME_Support for D3hot and D3cold, but
|
||||
* if the SoC is put into a hardware sleep state by the amd-pmc driver, the
|
||||
* Root Ports don't generate wakeup interrupts for USB devices.
|
||||
*
|
||||
* When suspending, remove D3hot and D3cold from the PME_Support advertised
|
||||
* by the Root Port so we don't use those states if we're expecting wakeup
|
||||
* interrupts. Restore the advertised PME_Support when resuming.
|
||||
*/
|
||||
static void amd_rp_pme_suspend(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *rp;
|
||||
|
||||
/*
|
||||
* PM_SUSPEND_ON means we're doing runtime suspend, which means
|
||||
* amd-pmc will not be involved so PMEs during D3 work as advertised.
|
||||
*
|
||||
* The PMEs *do* work if amd-pmc doesn't put the SoC in the hardware
|
||||
* sleep state, but we assume amd-pmc is always present.
|
||||
*/
|
||||
if (pm_suspend_target_state == PM_SUSPEND_ON)
|
||||
return;
|
||||
|
||||
rp = pcie_find_root_port(dev);
|
||||
if (!rp->pm_cap)
|
||||
return;
|
||||
|
||||
rp->pme_support &= ~((PCI_PM_CAP_PME_D3hot|PCI_PM_CAP_PME_D3cold) >>
|
||||
PCI_PM_CAP_PME_SHIFT);
|
||||
dev_info_once(&rp->dev, "quirk: disabling D3cold for suspend\n");
|
||||
}
|
||||
|
||||
static void amd_rp_pme_resume(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *rp;
|
||||
u16 pmc;
|
||||
|
||||
rp = pcie_find_root_port(dev);
|
||||
if (!rp->pm_cap)
|
||||
return;
|
||||
|
||||
pci_read_config_word(rp, rp->pm_cap + PCI_PM_PMC, &pmc);
|
||||
rp->pme_support = FIELD_GET(PCI_PM_CAP_PME_MASK, pmc);
|
||||
}
|
||||
/* Rembrandt (yellow_carp) */
|
||||
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_suspend);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162e, amd_rp_pme_resume);
|
||||
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_suspend);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x162f, amd_rp_pme_resume);
|
||||
/* Phoenix (pink_sardine) */
|
||||
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_suspend);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1668, amd_rp_pme_resume);
|
||||
DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_suspend);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1669, amd_rp_pme_resume);
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
|
@ -2291,19 +2291,21 @@ static int get_esi(struct atm_dev *dev)
|
||||
static int reset_sar(struct atm_dev *dev)
|
||||
{
|
||||
IADEV *iadev;
|
||||
int i, error = 1;
|
||||
int i, error;
|
||||
unsigned int pci[64];
|
||||
|
||||
iadev = INPH_IA_DEV(dev);
|
||||
for(i=0; i<64; i++)
|
||||
if ((error = pci_read_config_dword(iadev->pci,
|
||||
i*4, &pci[i])) != PCIBIOS_SUCCESSFUL)
|
||||
return error;
|
||||
for (i = 0; i < 64; i++) {
|
||||
error = pci_read_config_dword(iadev->pci, i * 4, &pci[i]);
|
||||
if (error != PCIBIOS_SUCCESSFUL)
|
||||
return error;
|
||||
}
|
||||
writel(0, iadev->reg+IPHASE5575_EXT_RESET);
|
||||
for(i=0; i<64; i++)
|
||||
if ((error = pci_write_config_dword(iadev->pci,
|
||||
i*4, pci[i])) != PCIBIOS_SUCCESSFUL)
|
||||
return error;
|
||||
for (i = 0; i < 64; i++) {
|
||||
error = pci_write_config_dword(iadev->pci, i * 4, pci[i]);
|
||||
if (error != PCIBIOS_SUCCESSFUL)
|
||||
return error;
|
||||
}
|
||||
udelay(5);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1393,14 +1393,11 @@ void amdgpu_acpi_detect(void)
|
||||
struct pci_dev *pdev = NULL;
|
||||
int ret;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
if (!atif->handle)
|
||||
amdgpu_atif_pci_probe_handle(pdev);
|
||||
if (!atcs->handle)
|
||||
amdgpu_atcs_pci_probe_handle(pdev);
|
||||
}
|
||||
while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
||||
if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
(pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
|
||||
continue;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
|
||||
if (!atif->handle)
|
||||
amdgpu_atif_pci_probe_handle(pdev);
|
||||
if (!atcs->handle)
|
||||
|
@ -287,7 +287,11 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
||||
if (adev->flags & AMD_IS_APU)
|
||||
return false;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
||||
if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
(pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
|
||||
continue;
|
||||
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!dhandle)
|
||||
continue;
|
||||
@ -299,20 +303,6 @@ static bool amdgpu_atrm_get_bios(struct amdgpu_device *adev)
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!dhandle)
|
||||
continue;
|
||||
|
||||
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
pci_dev_put(pdev);
|
||||
|
@ -284,14 +284,11 @@ static bool nouveau_dsm_detect(void)
|
||||
printk("MXM: GUID detected in BIOS\n");
|
||||
|
||||
/* now do DSM detection */
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
vga_count++;
|
||||
while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
||||
if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
(pdev->class != PCI_CLASS_DISPLAY_3D << 8))
|
||||
continue;
|
||||
|
||||
nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
|
||||
&has_optimus_flags, &has_power_resources);
|
||||
}
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
|
||||
vga_count++;
|
||||
|
||||
nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
|
||||
|
@ -68,11 +68,6 @@ module_param_named(num_heads, qxl_num_crtc, int, 0400);
|
||||
static struct drm_driver qxl_driver;
|
||||
static struct pci_driver qxl_pci_driver;
|
||||
|
||||
static bool is_vga(struct pci_dev *pdev)
|
||||
{
|
||||
return pdev->class == PCI_CLASS_DISPLAY_VGA << 8;
|
||||
}
|
||||
|
||||
static int
|
||||
qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
@ -100,7 +95,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
if (ret)
|
||||
goto disable_pci;
|
||||
|
||||
if (is_vga(pdev) && pdev->revision < 5) {
|
||||
if (pci_is_vga(pdev) && pdev->revision < 5) {
|
||||
ret = vga_get_interruptible(pdev, VGA_RSRC_LEGACY_IO);
|
||||
if (ret) {
|
||||
DRM_ERROR("can't get legacy vga ioports\n");
|
||||
@ -131,7 +126,7 @@ qxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
unload:
|
||||
qxl_device_fini(qdev);
|
||||
put_vga:
|
||||
if (is_vga(pdev) && pdev->revision < 5)
|
||||
if (pci_is_vga(pdev) && pdev->revision < 5)
|
||||
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
||||
disable_pci:
|
||||
pci_disable_device(pdev);
|
||||
@ -159,7 +154,7 @@ qxl_pci_remove(struct pci_dev *pdev)
|
||||
|
||||
drm_dev_unregister(dev);
|
||||
drm_atomic_helper_shutdown(dev);
|
||||
if (is_vga(pdev) && pdev->revision < 5)
|
||||
if (pci_is_vga(pdev) && pdev->revision < 5)
|
||||
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,11 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
|
||||
if (rdev->flags & RADEON_IS_IGP)
|
||||
return false;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
||||
if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
(pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
|
||||
continue;
|
||||
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!dhandle)
|
||||
continue;
|
||||
@ -211,20 +215,6 @@ static bool radeon_atrm_get_bios(struct radeon_device *rdev)
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!dhandle)
|
||||
continue;
|
||||
|
||||
status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return false;
|
||||
pci_dev_put(pdev);
|
||||
|
@ -51,7 +51,7 @@ static int virtio_gpu_pci_quirk(struct drm_device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev->dev);
|
||||
const char *pname = dev_name(&pdev->dev);
|
||||
bool vga = (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
|
||||
bool vga = pci_is_vga(pdev);
|
||||
int ret;
|
||||
|
||||
DRM_INFO("pci: %s detected at %s\n",
|
||||
|
@ -81,6 +81,7 @@
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774B1 0x002b
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
|
||||
#define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
|
||||
|
||||
static DEFINE_IDA(pci_endpoint_test_ida);
|
||||
|
||||
@ -990,6 +991,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
|
||||
.driver_data = (kernel_ulong_t)&j721e_data,
|
||||
},
|
||||
|
@ -170,7 +170,7 @@ config PCI_P2PDMA
|
||||
select GENERIC_ALLOCATOR
|
||||
select NEED_SG_DMA_FLAGS
|
||||
help
|
||||
Enableѕ drivers to do PCI peer-to-peer transactions to and from
|
||||
Enables drivers to do PCI peer-to-peer transactions to and from
|
||||
BARs that are exposed in other devices that are the part of
|
||||
the hierarchy where peer-to-peer DMA is guaranteed by the PCI
|
||||
specification to work (ie. anything below a single PCI bridge).
|
||||
|
@ -9,6 +9,7 @@
|
||||
* Copyright (C) 2011 Advanced Micro Devices,
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pci-ats.h>
|
||||
#include <linux/pci.h>
|
||||
@ -480,8 +481,6 @@ int pci_pasid_features(struct pci_dev *pdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_pasid_features);
|
||||
|
||||
#define PASID_NUMBER_SHIFT 8
|
||||
#define PASID_NUMBER_MASK (0x1f << PASID_NUMBER_SHIFT)
|
||||
/**
|
||||
* pci_max_pasids - Get maximum number of PASIDs supported by device
|
||||
* @pdev: PCI device structure
|
||||
@ -503,9 +502,7 @@ int pci_max_pasids(struct pci_dev *pdev)
|
||||
|
||||
pci_read_config_word(pdev, pasid + PCI_PASID_CAP, &supported);
|
||||
|
||||
supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
|
||||
|
||||
return (1 << supported);
|
||||
return (1 << FIELD_GET(PCI_PASID_CAP_WIDTH, supported));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_max_pasids);
|
||||
#endif /* CONFIG_PCI_PASID */
|
||||
|
@ -324,6 +324,17 @@ config PCIE_XILINX
|
||||
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
|
||||
Host Bridge driver.
|
||||
|
||||
config PCIE_XILINX_DMA_PL
|
||||
bool "Xilinx DMA PL PCIe host bridge support"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select PCI_HOST_COMMON
|
||||
help
|
||||
Say 'Y' here if you want kernel support for the Xilinx PL DMA
|
||||
PCIe host bridge. The controller is a Soft IP which can act as
|
||||
Root Port. If your system provides Xilinx PCIe host controller
|
||||
bridge DMA as Soft IP say 'Y'; if you are not sure, say 'N'.
|
||||
|
||||
config PCIE_XILINX_NWL
|
||||
bool "Xilinx NWL PCIe controller"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
|
||||
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
|
||||
obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o
|
||||
obj-$(CONFIG_PCIE_XILINX_CPM) += pcie-xilinx-cpm.o
|
||||
obj-$(CONFIG_PCIE_XILINX_DMA_PL) += pcie-xilinx-dma-pl.o
|
||||
obj-$(CONFIG_PCI_V3_SEMI) += pci-v3-semi.o
|
||||
obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
|
||||
obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Cadence PCIe endpoint controller driver.
|
||||
// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
@ -262,7 +263,7 @@ static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn, u8 vfn)
|
||||
* Get the Multiple Message Enable bitfield from the Message Control
|
||||
* register.
|
||||
*/
|
||||
mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
|
||||
|
||||
return mme;
|
||||
}
|
||||
@ -394,7 +395,7 @@ static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the number of enabled MSIs */
|
||||
mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
|
||||
msi_count = 1 << mme;
|
||||
if (!interrupt_num || interrupt_num > msi_count)
|
||||
return -EINVAL;
|
||||
@ -449,7 +450,7 @@ static int cdns_pcie_ep_map_msi_irq(struct pci_epc *epc, u8 fn, u8 vfn,
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the number of enabled MSIs */
|
||||
mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
mme = FIELD_GET(PCI_MSI_FLAGS_QSIZE, flags);
|
||||
msi_count = 1 << mme;
|
||||
if (!interrupt_num || interrupt_num > msi_count)
|
||||
return -EINVAL;
|
||||
@ -506,7 +507,7 @@ static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
|
||||
|
||||
reg = cap + PCI_MSIX_TABLE;
|
||||
tbl_offset = cdns_pcie_ep_fn_readl(pcie, fn, reg);
|
||||
bir = tbl_offset & PCI_MSIX_TABLE_BIR;
|
||||
bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
|
||||
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
|
||||
|
||||
msix_tbl = epf->epf_bar[bir]->addr + tbl_offset;
|
||||
|
@ -17,12 +17,9 @@
|
||||
/**
|
||||
* struct cdns_plat_pcie - private data for this PCIe platform driver
|
||||
* @pcie: Cadence PCIe controller
|
||||
* @is_rc: Set to 1 indicates the PCIe controller mode is Root Complex,
|
||||
* if 0 it is in Endpoint mode.
|
||||
*/
|
||||
struct cdns_plat_pcie {
|
||||
struct cdns_pcie *pcie;
|
||||
bool is_rc;
|
||||
};
|
||||
|
||||
struct cdns_plat_pcie_of_data {
|
||||
@ -76,7 +73,6 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
|
||||
rc->pcie.dev = dev;
|
||||
rc->pcie.ops = &cdns_plat_ops;
|
||||
cdns_plat_pcie->pcie = &rc->pcie;
|
||||
cdns_plat_pcie->is_rc = is_rc;
|
||||
|
||||
ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
|
||||
if (ret) {
|
||||
@ -104,7 +100,6 @@ static int cdns_plat_pcie_probe(struct platform_device *pdev)
|
||||
ep->pcie.dev = dev;
|
||||
ep->pcie.ops = &cdns_plat_ops;
|
||||
cdns_plat_pcie->pcie = &ep->pcie;
|
||||
cdns_plat_pcie->is_rc = is_rc;
|
||||
|
||||
ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
|
||||
if (ret) {
|
||||
|
@ -286,6 +286,31 @@ config PCIE_QCOM_EP
|
||||
to work in endpoint mode. The PCIe controller uses the DesignWare core
|
||||
plus Qualcomm-specific hardware wrappers.
|
||||
|
||||
config PCIE_RCAR_GEN4
|
||||
tristate
|
||||
|
||||
config PCIE_RCAR_GEN4_HOST
|
||||
tristate "Renesas R-Car Gen4 PCIe controller (host mode)"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on PCI_MSI
|
||||
select PCIE_DW_HOST
|
||||
select PCIE_RCAR_GEN4
|
||||
help
|
||||
Say Y here if you want PCIe controller (host mode) on R-Car Gen4 SoCs.
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called pcie-rcar-gen4.ko. This uses the DesignWare core.
|
||||
|
||||
config PCIE_RCAR_GEN4_EP
|
||||
tristate "Renesas R-Car Gen4 PCIe controller (endpoint mode)"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCIE_RCAR_GEN4
|
||||
help
|
||||
Say Y here if you want PCIe controller (endpoint mode) on R-Car Gen4
|
||||
SoCs. To compile this driver as a module, choose M here: the module
|
||||
will be called pcie-rcar-gen4.ko. This uses the DesignWare core.
|
||||
|
||||
config PCIE_ROCKCHIP_DW_HOST
|
||||
bool "Rockchip DesignWare PCIe controller"
|
||||
select PCIE_DW
|
||||
|
@ -26,6 +26,7 @@ obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
|
||||
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
||||
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
|
||||
obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
|
||||
obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
|
||||
|
||||
# The following drivers are for devices that use the generic ACPI
|
||||
# pci_root.c driver but don't support standard ECAM config access.
|
||||
|
@ -375,7 +375,7 @@ static int exynos_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit exynos_pcie_remove(struct platform_device *pdev)
|
||||
static int exynos_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_pcie *ep = platform_get_drvdata(pdev);
|
||||
|
||||
@ -431,7 +431,7 @@ static const struct of_device_id exynos_pcie_of_match[] = {
|
||||
|
||||
static struct platform_driver exynos_pcie_driver = {
|
||||
.probe = exynos_pcie_probe,
|
||||
.remove = __exit_p(exynos_pcie_remove),
|
||||
.remove = exynos_pcie_remove,
|
||||
.driver = {
|
||||
.name = "exynos-pcie",
|
||||
.of_match_table = exynos_pcie_of_match,
|
||||
|
@ -1100,7 +1100,7 @@ static const struct of_device_id ks_pcie_of_match[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
static int ks_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct dw_pcie_host_ops *host_ops;
|
||||
const struct dw_pcie_ep_ops *ep_ops;
|
||||
@ -1302,7 +1302,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit ks_pcie_remove(struct platform_device *pdev)
|
||||
static int ks_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
|
||||
struct device_link **link = ks_pcie->link;
|
||||
@ -1318,9 +1318,9 @@ static int __exit ks_pcie_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ks_pcie_driver __refdata = {
|
||||
static struct platform_driver ks_pcie_driver = {
|
||||
.probe = ks_pcie_probe,
|
||||
.remove = __exit_p(ks_pcie_remove),
|
||||
.remove = ks_pcie_remove,
|
||||
.driver = {
|
||||
.name = "keystone-pcie",
|
||||
.of_match_table = ks_pcie_of_match,
|
||||
|
@ -266,6 +266,8 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
|
||||
pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
|
||||
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
@ -58,7 +58,7 @@ static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
|
||||
u32 header_type;
|
||||
|
||||
header_type = ioread8(pci->dbi_base + PCI_HEADER_TYPE);
|
||||
header_type &= 0x7f;
|
||||
header_type &= PCI_HEADER_TYPE_MASK;
|
||||
|
||||
return header_type == PCI_HEADER_TYPE_BRIDGE;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Author: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@ -52,21 +53,35 @@ static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
|
||||
return func_offset;
|
||||
}
|
||||
|
||||
static unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
unsigned int dbi2_offset = 0;
|
||||
|
||||
if (ep->ops->get_dbi2_offset)
|
||||
dbi2_offset = ep->ops->get_dbi2_offset(ep, func_no);
|
||||
else if (ep->ops->func_conf_select) /* for backward compatibility */
|
||||
dbi2_offset = ep->ops->func_conf_select(ep, func_no);
|
||||
|
||||
return dbi2_offset;
|
||||
}
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
|
||||
enum pci_barno bar, int flags)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
unsigned int func_offset, dbi2_offset;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
u32 reg, reg_dbi2;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
|
||||
|
||||
reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
reg_dbi2 = dbi2_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
||||
dw_pcie_writel_dbi2(pci, reg + 4, 0x0);
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg + 4, 0x0);
|
||||
}
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
@ -228,16 +243,18 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset, dbi2_offset;
|
||||
enum pci_barno bar = epf_bar->barno;
|
||||
size_t size = epf_bar->size;
|
||||
int flags = epf_bar->flags;
|
||||
unsigned int func_offset = 0;
|
||||
u32 reg, reg_dbi2;
|
||||
int ret, type;
|
||||
u32 reg;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
|
||||
reg_dbi2 = PCI_BASE_ADDRESS_0 + (4 * bar) + dbi2_offset;
|
||||
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
type = PCIE_ATU_TYPE_MEM;
|
||||
@ -253,11 +270,11 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
dw_pcie_writel_dbi2(pci, reg, lower_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2, lower_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi(pci, reg, flags);
|
||||
|
||||
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
|
||||
dw_pcie_writel_dbi2(pci, reg + 4, upper_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, upper_32_bits(size - 1));
|
||||
dw_pcie_writel_dbi(pci, reg + 4, 0);
|
||||
}
|
||||
|
||||
@ -334,7 +351,7 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
|
||||
if (!(val & PCI_MSI_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
val = (val & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
val = FIELD_GET(PCI_MSI_FLAGS_QSIZE, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -357,7 +374,7 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSI_FLAGS_QMASK;
|
||||
val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
|
||||
val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, interrupts);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, reg, val);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
@ -584,7 +601,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
|
||||
tbl_offset = dw_pcie_readl_dbi(pci, reg);
|
||||
bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
|
||||
bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
|
||||
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
|
||||
|
||||
msix_tbl = ep->epf_bar[bir]->addr + tbl_offset;
|
||||
@ -621,7 +638,11 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
|
||||
epc->mem->window.page_size);
|
||||
|
||||
pci_epc_mem_exit(epc);
|
||||
|
||||
if (ep->ops->deinit)
|
||||
ep->ops->deinit(ep);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_exit);
|
||||
|
||||
static unsigned int dw_pcie_ep_find_ext_capability(struct dw_pcie *pci, int cap)
|
||||
{
|
||||
@ -723,6 +744,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
if (ep->ops->pre_init)
|
||||
ep->ops->pre_init(ep);
|
||||
|
||||
dw_pcie_version_detect(pci);
|
||||
|
||||
dw_pcie_iatu_detect(pci);
|
||||
@ -777,7 +801,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->page_size);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize address space\n");
|
||||
return ret;
|
||||
goto err_ep_deinit;
|
||||
}
|
||||
|
||||
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
|
||||
@ -814,6 +838,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
err_exit_epc_mem:
|
||||
pci_epc_mem_exit(epc);
|
||||
|
||||
err_ep_deinit:
|
||||
if (ep->ops->deinit)
|
||||
ep->ops->deinit(ep);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init);
|
||||
|
@ -502,6 +502,9 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
if (ret)
|
||||
goto err_stop_link;
|
||||
|
||||
if (pp->ops->host_post_init)
|
||||
pp->ops->host_post_init(pp);
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_link:
|
||||
|
@ -365,6 +365,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
if (ret)
|
||||
dev_err(pci->dev, "write DBI address failed\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_write_dbi2);
|
||||
|
||||
static inline void __iomem *dw_pcie_select_atu(struct dw_pcie *pci, u32 dir,
|
||||
u32 index)
|
||||
@ -732,6 +733,53 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
|
||||
}
|
||||
|
||||
static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
|
||||
{
|
||||
u32 lnkcap, lwsc, plc;
|
||||
u8 cap;
|
||||
|
||||
if (!num_lanes)
|
||||
return;
|
||||
|
||||
/* Set the number of lanes */
|
||||
plc = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
plc &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
plc &= ~PORT_LINK_MODE_MASK;
|
||||
|
||||
/* Set link width speed control register */
|
||||
lwsc = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
lwsc &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (num_lanes) {
|
||||
case 1:
|
||||
plc |= PORT_LINK_MODE_1_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
plc |= PORT_LINK_MODE_2_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
plc |= PORT_LINK_MODE_4_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
plc |= PORT_LINK_MODE_8_LANES;
|
||||
lwsc |= PORT_LOGIC_LINK_WIDTH_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, plc);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, lwsc);
|
||||
|
||||
cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
|
||||
lnkcap &= ~PCI_EXP_LNKCAP_MLW;
|
||||
lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, num_lanes);
|
||||
dw_pcie_writel_dbi(pci, cap + PCI_EXP_LNKCAP, lnkcap);
|
||||
}
|
||||
|
||||
void dw_pcie_iatu_detect(struct dw_pcie *pci)
|
||||
{
|
||||
int max_region, ob, ib;
|
||||
@ -840,8 +888,14 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
|
||||
* Indirect eDMA CSRs access has been completely removed since v5.40a
|
||||
* thus no space is now reserved for the eDMA channels viewport and
|
||||
* former DMA CTRL register is no longer fixed to FFs.
|
||||
*
|
||||
* Note that Renesas R-Car S4-8's PCIe controllers for unknown reason
|
||||
* have zeros in the eDMA CTRL register even though the HW-manual
|
||||
* explicitly states there must FFs if the unrolled mapping is enabled.
|
||||
* For such cases the low-level drivers are supposed to manually
|
||||
* activate the unrolled mapping to bypass the auto-detection procedure.
|
||||
*/
|
||||
if (dw_pcie_ver_is_ge(pci, 540A))
|
||||
if (dw_pcie_ver_is_ge(pci, 540A) || dw_pcie_cap_is(pci, EDMA_UNROLL))
|
||||
val = 0xFFFFFFFF;
|
||||
else
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
|
||||
@ -1013,49 +1067,5 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
val |= PORT_LINK_DLL_LINK_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
if (!pci->num_lanes) {
|
||||
dev_dbg(pci->dev, "Using h/w default number of lanes\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the number of lanes */
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val &= ~PORT_LINK_MODE_MASK;
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LINK_MODE_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
val |= PORT_LINK_MODE_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
val |= PORT_LINK_MODE_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
val |= PORT_LINK_MODE_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
/* Set link width speed control register */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
case 2:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_2_LANES;
|
||||
break;
|
||||
case 4:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_4_LANES;
|
||||
break;
|
||||
case 8:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_8_LANES;
|
||||
break;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
|
||||
}
|
||||
|
@ -51,8 +51,9 @@
|
||||
|
||||
/* DWC PCIe controller capabilities */
|
||||
#define DW_PCIE_CAP_REQ_RES 0
|
||||
#define DW_PCIE_CAP_IATU_UNROLL 1
|
||||
#define DW_PCIE_CAP_CDM_CHECK 2
|
||||
#define DW_PCIE_CAP_EDMA_UNROLL 1
|
||||
#define DW_PCIE_CAP_IATU_UNROLL 2
|
||||
#define DW_PCIE_CAP_CDM_CHECK 3
|
||||
|
||||
#define dw_pcie_cap_is(_pci, _cap) \
|
||||
test_bit(DW_PCIE_CAP_ ## _cap, &(_pci)->caps)
|
||||
@ -301,6 +302,7 @@ enum dw_pcie_ltssm {
|
||||
struct dw_pcie_host_ops {
|
||||
int (*host_init)(struct dw_pcie_rp *pp);
|
||||
void (*host_deinit)(struct dw_pcie_rp *pp);
|
||||
void (*host_post_init)(struct dw_pcie_rp *pp);
|
||||
int (*msi_host_init)(struct dw_pcie_rp *pp);
|
||||
void (*pme_turn_off)(struct dw_pcie_rp *pp);
|
||||
};
|
||||
@ -329,7 +331,9 @@ struct dw_pcie_rp {
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_ops {
|
||||
void (*pre_init)(struct dw_pcie_ep *ep);
|
||||
void (*ep_init)(struct dw_pcie_ep *ep);
|
||||
void (*deinit)(struct dw_pcie_ep *ep);
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
|
||||
@ -341,6 +345,7 @@ struct dw_pcie_ep_ops {
|
||||
* driver.
|
||||
*/
|
||||
unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
unsigned int (*get_dbi2_offset)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_func {
|
||||
|
@ -741,7 +741,7 @@ static int kirin_pcie_power_on(struct platform_device *pdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit kirin_pcie_remove(struct platform_device *pdev)
|
||||
static int kirin_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kirin_pcie *kirin_pcie = platform_get_drvdata(pdev);
|
||||
|
||||
@ -818,7 +818,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver kirin_pcie_driver = {
|
||||
.probe = kirin_pcie_probe,
|
||||
.remove = __exit_p(kirin_pcie_remove),
|
||||
.remove = kirin_pcie_remove,
|
||||
.driver = {
|
||||
.name = "kirin-pcie",
|
||||
.of_match_table = kirin_pcie_match,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/reset.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
/* PARF registers */
|
||||
@ -123,6 +124,7 @@
|
||||
|
||||
/* ELBI registers */
|
||||
#define ELBI_SYS_STTS 0x08
|
||||
#define ELBI_CS2_ENABLE 0xa4
|
||||
|
||||
/* DBI registers */
|
||||
#define DBI_CON_STATUS 0x44
|
||||
@ -135,10 +137,8 @@
|
||||
#define CORE_RESET_TIME_US_MAX 1005
|
||||
#define WAKE_DELAY_US 2000 /* 2 ms */
|
||||
|
||||
#define PCIE_GEN1_BW_MBPS 250
|
||||
#define PCIE_GEN2_BW_MBPS 500
|
||||
#define PCIE_GEN3_BW_MBPS 985
|
||||
#define PCIE_GEN4_BW_MBPS 1969
|
||||
#define QCOM_PCIE_LINK_SPEED_TO_BW(speed) \
|
||||
Mbps_to_icc(PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]))
|
||||
|
||||
#define to_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
@ -263,10 +263,25 @@ static void qcom_pcie_dw_stop_link(struct dw_pcie *pci)
|
||||
disable_irq(pcie_ep->perst_irq);
|
||||
}
|
||||
|
||||
static void qcom_pcie_dw_write_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size, u32 val)
|
||||
{
|
||||
struct qcom_pcie_ep *pcie_ep = to_pcie_ep(pci);
|
||||
int ret;
|
||||
|
||||
writel(1, pcie_ep->elbi + ELBI_CS2_ENABLE);
|
||||
|
||||
ret = dw_pcie_write(pci->dbi_base2 + reg, size, val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "Failed to write DBI2 register (0x%x): %d\n", reg, ret);
|
||||
|
||||
writel(0, pcie_ep->elbi + ELBI_CS2_ENABLE);
|
||||
}
|
||||
|
||||
static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep)
|
||||
{
|
||||
struct dw_pcie *pci = &pcie_ep->pci;
|
||||
u32 offset, status, bw;
|
||||
u32 offset, status;
|
||||
int speed, width;
|
||||
int ret;
|
||||
|
||||
@ -279,25 +294,7 @@ static void qcom_pcie_ep_icc_update(struct qcom_pcie_ep *pcie_ep)
|
||||
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
|
||||
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
|
||||
|
||||
switch (speed) {
|
||||
case 1:
|
||||
bw = MBps_to_icc(PCIE_GEN1_BW_MBPS);
|
||||
break;
|
||||
case 2:
|
||||
bw = MBps_to_icc(PCIE_GEN2_BW_MBPS);
|
||||
break;
|
||||
case 3:
|
||||
bw = MBps_to_icc(PCIE_GEN3_BW_MBPS);
|
||||
break;
|
||||
default:
|
||||
dev_warn(pci->dev, "using default GEN4 bandwidth\n");
|
||||
fallthrough;
|
||||
case 4:
|
||||
bw = MBps_to_icc(PCIE_GEN4_BW_MBPS);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = icc_set_bw(pcie_ep->icc_mem, 0, width * bw);
|
||||
ret = icc_set_bw(pcie_ep->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
|
||||
if (ret)
|
||||
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
|
||||
ret);
|
||||
@ -335,7 +332,7 @@ static int qcom_pcie_enable_resources(struct qcom_pcie_ep *pcie_ep)
|
||||
* Set an initial peak bandwidth corresponding to single-lane Gen 1
|
||||
* for the pcie-mem path.
|
||||
*/
|
||||
ret = icc_set_bw(pcie_ep->icc_mem, 0, MBps_to_icc(PCIE_GEN1_BW_MBPS));
|
||||
ret = icc_set_bw(pcie_ep->icc_mem, 0, QCOM_PCIE_LINK_SPEED_TO_BW(1));
|
||||
if (ret) {
|
||||
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
|
||||
ret);
|
||||
@ -519,6 +516,7 @@ static const struct dw_pcie_ops pci_ops = {
|
||||
.link_up = qcom_pcie_dw_link_up,
|
||||
.start_link = qcom_pcie_dw_start_link,
|
||||
.stop_link = qcom_pcie_dw_stop_link,
|
||||
.write_dbi2 = qcom_pcie_dw_write_dbi2,
|
||||
};
|
||||
|
||||
static int qcom_pcie_ep_get_io_resources(struct platform_device *pdev,
|
||||
|
@ -147,6 +147,9 @@
|
||||
|
||||
#define QCOM_PCIE_CRC8_POLYNOMIAL (BIT(2) | BIT(1) | BIT(0))
|
||||
|
||||
#define QCOM_PCIE_LINK_SPEED_TO_BW(speed) \
|
||||
Mbps_to_icc(PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]))
|
||||
|
||||
#define QCOM_PCIE_1_0_0_MAX_CLOCKS 4
|
||||
struct qcom_pcie_resources_1_0_0 {
|
||||
struct clk_bulk_data clks[QCOM_PCIE_1_0_0_MAX_CLOCKS];
|
||||
@ -218,6 +221,7 @@ struct qcom_pcie_ops {
|
||||
int (*get_resources)(struct qcom_pcie *pcie);
|
||||
int (*init)(struct qcom_pcie *pcie);
|
||||
int (*post_init)(struct qcom_pcie *pcie);
|
||||
void (*host_post_init)(struct qcom_pcie *pcie);
|
||||
void (*deinit)(struct qcom_pcie *pcie);
|
||||
void (*ltssm_enable)(struct qcom_pcie *pcie);
|
||||
int (*config_sid)(struct qcom_pcie *pcie);
|
||||
@ -962,6 +966,22 @@ static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_pcie_enable_aspm(struct pci_dev *pdev, void *userdata)
|
||||
{
|
||||
/* Downstream devices need to be in D0 state before enabling PCI PM substates */
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcom_pcie_host_post_init_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct dw_pcie_rp *pp = &pcie->pci->pp;
|
||||
|
||||
pci_walk_bus(pp->bridge->bus, qcom_pcie_enable_aspm, NULL);
|
||||
}
|
||||
|
||||
static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
|
||||
@ -1214,9 +1234,19 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp)
|
||||
pcie->cfg->ops->deinit(pcie);
|
||||
}
|
||||
|
||||
static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct qcom_pcie *pcie = to_qcom_pcie(pci);
|
||||
|
||||
if (pcie->cfg->ops->host_post_init)
|
||||
pcie->cfg->ops->host_post_init(pcie);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
|
||||
.host_init = qcom_pcie_host_init,
|
||||
.host_deinit = qcom_pcie_host_deinit,
|
||||
.host_post_init = qcom_pcie_host_post_init,
|
||||
};
|
||||
|
||||
/* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
|
||||
@ -1278,6 +1308,7 @@ static const struct qcom_pcie_ops ops_1_9_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_7_0,
|
||||
.init = qcom_pcie_init_2_7_0,
|
||||
.post_init = qcom_pcie_post_init_2_7_0,
|
||||
.host_post_init = qcom_pcie_host_post_init_2_7_0,
|
||||
.deinit = qcom_pcie_deinit_2_7_0,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
.config_sid = qcom_pcie_config_sid_1_9_0,
|
||||
@ -1345,7 +1376,7 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
|
||||
* Set an initial peak bandwidth corresponding to single-lane Gen 1
|
||||
* for the pcie-mem path.
|
||||
*/
|
||||
ret = icc_set_bw(pcie->icc_mem, 0, MBps_to_icc(250));
|
||||
ret = icc_set_bw(pcie->icc_mem, 0, QCOM_PCIE_LINK_SPEED_TO_BW(1));
|
||||
if (ret) {
|
||||
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
|
||||
ret);
|
||||
@ -1358,7 +1389,7 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
|
||||
static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
u32 offset, status, bw;
|
||||
u32 offset, status;
|
||||
int speed, width;
|
||||
int ret;
|
||||
|
||||
@ -1375,22 +1406,7 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
|
||||
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
|
||||
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
|
||||
|
||||
switch (speed) {
|
||||
case 1:
|
||||
bw = MBps_to_icc(250);
|
||||
break;
|
||||
case 2:
|
||||
bw = MBps_to_icc(500);
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
fallthrough;
|
||||
case 3:
|
||||
bw = MBps_to_icc(985);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = icc_set_bw(pcie->icc_mem, 0, width * bw);
|
||||
ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
|
||||
if (ret) {
|
||||
dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
|
||||
ret);
|
||||
|
527
drivers/pci/controller/dwc/pcie-rcar-gen4.c
Normal file
527
drivers/pci/controller/dwc/pcie-rcar-gen4.c
Normal file
@ -0,0 +1,527 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PCIe controller driver for Renesas R-Car Gen4 Series SoCs
|
||||
* Copyright (C) 2022-2023 Renesas Electronics Corporation
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
/* Renesas-specific */
|
||||
/* PCIe Mode Setting Register 0 */
|
||||
#define PCIEMSR0 0x0000
|
||||
#define BIFUR_MOD_SET_ON BIT(0)
|
||||
#define DEVICE_TYPE_EP 0
|
||||
#define DEVICE_TYPE_RC BIT(4)
|
||||
|
||||
/* PCIe Interrupt Status 0 */
|
||||
#define PCIEINTSTS0 0x0084
|
||||
|
||||
/* PCIe Interrupt Status 0 Enable */
|
||||
#define PCIEINTSTS0EN 0x0310
|
||||
#define MSI_CTRL_INT BIT(26)
|
||||
#define SMLH_LINK_UP BIT(7)
|
||||
#define RDLH_LINK_UP BIT(6)
|
||||
|
||||
/* PCIe DMA Interrupt Status Enable */
|
||||
#define PCIEDMAINTSTSEN 0x0314
|
||||
#define PCIEDMAINTSTSEN_INIT GENMASK(15, 0)
|
||||
|
||||
/* PCIe Reset Control Register 1 */
|
||||
#define PCIERSTCTRL1 0x0014
|
||||
#define APP_HOLD_PHY_RST BIT(16)
|
||||
#define APP_LTSSM_ENABLE BIT(0)
|
||||
|
||||
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
|
||||
#define RCAR_MAX_LINK_SPEED 4
|
||||
|
||||
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
|
||||
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
|
||||
|
||||
struct rcar_gen4_pcie {
|
||||
struct dw_pcie dw;
|
||||
void __iomem *base;
|
||||
struct platform_device *pdev;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
|
||||
|
||||
/* Common */
|
||||
static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
|
||||
bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(rcar->base + PCIERSTCTRL1);
|
||||
if (enable) {
|
||||
val |= APP_LTSSM_ENABLE;
|
||||
val &= ~APP_HOLD_PHY_RST;
|
||||
} else {
|
||||
/*
|
||||
* Since the datasheet of R-Car doesn't mention how to assert
|
||||
* the APP_HOLD_PHY_RST, don't assert it again. Otherwise,
|
||||
* hang-up issue happened in the dw_edma_core_off() when
|
||||
* the controller didn't detect a PCI device.
|
||||
*/
|
||||
val &= ~APP_LTSSM_ENABLE;
|
||||
}
|
||||
writel(val, rcar->base + PCIERSTCTRL1);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_link_up(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
u32 val, mask;
|
||||
|
||||
val = readl(rcar->base + PCIEINTSTS0);
|
||||
mask = RDLH_LINK_UP | SMLH_LINK_UP;
|
||||
|
||||
return (val & mask) == mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually initiate the speed change. Return 0 if change succeeded; otherwise
|
||||
* -ETIMEDOUT.
|
||||
*/
|
||||
static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
|
||||
{
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
for (i = 0; i < RCAR_NUM_SPEED_CHANGE_RETRIES; i++) {
|
||||
val = dw_pcie_readl_dbi(dw, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
if (!(val & PORT_LOGIC_SPEED_CHANGE))
|
||||
return 0;
|
||||
usleep_range(10000, 11000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable LTSSM of this controller and manually initiate the speed change.
|
||||
* Always return 0.
|
||||
*/
|
||||
static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int i, changes;
|
||||
|
||||
rcar_gen4_pcie_ltssm_enable(rcar, true);
|
||||
|
||||
/*
|
||||
* Require direct speed change with retrying here if the link_gen is
|
||||
* PCIe Gen2 or higher.
|
||||
*/
|
||||
changes = min_not_zero(dw->link_gen, RCAR_MAX_LINK_SPEED) - 1;
|
||||
|
||||
/*
|
||||
* Since dw_pcie_setup_rc() sets it once, PCIe Gen2 will be trained.
|
||||
* So, this needs remaining times for up to PCIe Gen4 if RC mode.
|
||||
*/
|
||||
if (changes && rcar->mode == DW_PCIE_RC_TYPE)
|
||||
changes--;
|
||||
|
||||
for (i = 0; i < changes; i++) {
|
||||
/* It may not be connected in EP mode yet. So, break the loop */
|
||||
if (rcar_gen4_pcie_speed_change(dw))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_stop_link(struct dw_pcie *dw)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
rcar_gen4_pcie_ltssm_enable(rcar, false);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie *dw = &rcar->dw;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
if (ret) {
|
||||
dev_err(dw->dev, "Enabling core clocks failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!reset_control_status(dw->core_rsts[DW_PCIE_PWR_RST].rstc))
|
||||
reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
|
||||
val = readl(rcar->base + PCIEMSR0);
|
||||
if (rcar->mode == DW_PCIE_RC_TYPE) {
|
||||
val |= DEVICE_TYPE_RC;
|
||||
} else if (rcar->mode == DW_PCIE_EP_TYPE) {
|
||||
val |= DEVICE_TYPE_EP;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto err_unprepare;
|
||||
}
|
||||
|
||||
if (dw->num_lanes < 4)
|
||||
val |= BIFUR_MOD_SET_ON;
|
||||
|
||||
writel(val, rcar->base + PCIEMSR0);
|
||||
|
||||
ret = reset_control_deassert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
if (ret)
|
||||
goto err_unprepare;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unprepare:
|
||||
clk_bulk_disable_unprepare(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_common_deinit(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie *dw = &rcar->dw;
|
||||
|
||||
reset_control_assert(dw->core_rsts[DW_PCIE_PWR_RST].rstc);
|
||||
clk_bulk_disable_unprepare(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_prepare(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct device *dev = rcar->dw.dev;
|
||||
int err;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
err = pm_runtime_resume_and_get(dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Runtime resume failed\n");
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct device *dev = rcar->dw.dev;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
/* Renesas-specific registers */
|
||||
rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
|
||||
|
||||
return PTR_ERR_OR_ZERO(rcar->base);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = rcar_gen4_pcie_start_link,
|
||||
.stop_link = rcar_gen4_pcie_stop_link,
|
||||
.link_up = rcar_gen4_pcie_link_up,
|
||||
};
|
||||
|
||||
static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_gen4_pcie *rcar;
|
||||
|
||||
rcar = devm_kzalloc(dev, sizeof(*rcar), GFP_KERNEL);
|
||||
if (!rcar)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rcar->dw.ops = &dw_pcie_ops;
|
||||
rcar->dw.dev = dev;
|
||||
rcar->pdev = pdev;
|
||||
dw_pcie_cap_set(&rcar->dw, EDMA_UNROLL);
|
||||
dw_pcie_cap_set(&rcar->dw, REQ_RES);
|
||||
platform_set_drvdata(pdev, rcar);
|
||||
|
||||
return rcar;
|
||||
}
|
||||
|
||||
/* Host mode */
|
||||
static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 1);
|
||||
|
||||
ret = rcar_gen4_pcie_common_init(rcar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* According to the section 3.5.7.2 "RC Mode" in DWC PCIe Dual Mode
|
||||
* Rev.5.20a and 3.5.6.1 "RC mode" in DWC PCIe RC databook v5.20a, we
|
||||
* should disable two BARs to avoid unnecessary memory assignment
|
||||
* during device enumeration.
|
||||
*/
|
||||
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_0, 0x0);
|
||||
dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_1, 0x0);
|
||||
|
||||
/* Enable MSI interrupt signal */
|
||||
val = readl(rcar->base + PCIEINTSTS0EN);
|
||||
val |= MSI_CTRL_INT;
|
||||
writel(val, rcar->base + PCIEINTSTS0EN);
|
||||
|
||||
msleep(PCIE_T_PVPERL_MS); /* pe_rst requires 100msec delay */
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
gpiod_set_value_cansleep(dw->pe_rst, 1);
|
||||
rcar_gen4_pcie_common_deinit(rcar);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops rcar_gen4_pcie_host_ops = {
|
||||
.host_init = rcar_gen4_pcie_host_init,
|
||||
.host_deinit = rcar_gen4_pcie_host_deinit,
|
||||
};
|
||||
|
||||
static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie_rp *pp = &rcar->dw.pp;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_HOST))
|
||||
return -ENODEV;
|
||||
|
||||
pp->num_vectors = MAX_MSI_IRQS;
|
||||
pp->ops = &rcar_gen4_pcie_host_ops;
|
||||
|
||||
return dw_pcie_host_init(pp);
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
dw_pcie_host_deinit(&rcar->dw.pp);
|
||||
}
|
||||
|
||||
/* Endpoint mode */
|
||||
static void rcar_gen4_pcie_ep_pre_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
int ret;
|
||||
|
||||
ret = rcar_gen4_pcie_common_init(rcar);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
writel(PCIEDMAINTSTSEN_INIT, rcar->base + PCIEDMAINTSTSEN);
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
enum pci_barno bar;
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
|
||||
|
||||
writel(0, rcar->base + PCIEDMAINTSTSEN);
|
||||
rcar_gen4_pcie_common_deinit(rcar);
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
|
||||
|
||||
switch (type) {
|
||||
case PCI_EPC_IRQ_LEGACY:
|
||||
return dw_pcie_ep_raise_legacy_irq(ep, func_no);
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||
default:
|
||||
dev_err(dw->dev, "Unknown IRQ type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epc_features rcar_gen4_pcie_epc_features = {
|
||||
.linkup_notifier = false,
|
||||
.msi_capable = true,
|
||||
.msix_capable = false,
|
||||
.reserved_bar = 1 << BAR_1 | 1 << BAR_3 | 1 << BAR_5,
|
||||
.align = SZ_1M,
|
||||
};
|
||||
|
||||
static const struct pci_epc_features*
|
||||
rcar_gen4_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &rcar_gen4_pcie_epc_features;
|
||||
}
|
||||
|
||||
static unsigned int rcar_gen4_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET;
|
||||
}
|
||||
|
||||
static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.pre_init = rcar_gen4_pcie_ep_pre_init,
|
||||
.ep_init = rcar_gen4_pcie_ep_init,
|
||||
.deinit = rcar_gen4_pcie_ep_deinit,
|
||||
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
|
||||
.get_features = rcar_gen4_pcie_ep_get_features,
|
||||
.func_conf_select = rcar_gen4_pcie_ep_func_conf_select,
|
||||
.get_dbi2_offset = rcar_gen4_pcie_ep_get_dbi2_offset,
|
||||
};
|
||||
|
||||
static int rcar_gen4_add_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
struct dw_pcie_ep *ep = &rcar->dw.ep;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_EP))
|
||||
return -ENODEV;
|
||||
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
return dw_pcie_ep_init(ep);
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
dw_pcie_ep_exit(&rcar->dw.ep);
|
||||
}
|
||||
|
||||
/* Common */
|
||||
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
rcar->mode = (enum dw_pcie_device_mode)of_device_get_match_data(&rcar->pdev->dev);
|
||||
|
||||
switch (rcar->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
return rcar_gen4_add_dw_pcie_rp(rcar);
|
||||
case DW_PCIE_EP_TYPE:
|
||||
return rcar_gen4_add_dw_pcie_ep(rcar);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rcar_gen4_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar;
|
||||
int err;
|
||||
|
||||
rcar = rcar_gen4_pcie_alloc(pdev);
|
||||
if (IS_ERR(rcar))
|
||||
return PTR_ERR(rcar);
|
||||
|
||||
err = rcar_gen4_pcie_get_resources(rcar);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rcar_gen4_pcie_prepare(rcar);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rcar_gen4_add_dw_pcie(rcar);
|
||||
if (err)
|
||||
goto err_unprepare;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unprepare:
|
||||
rcar_gen4_pcie_unprepare(rcar);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rcar_gen4_remove_dw_pcie(struct rcar_gen4_pcie *rcar)
|
||||
{
|
||||
switch (rcar->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
rcar_gen4_remove_dw_pcie_rp(rcar);
|
||||
break;
|
||||
case DW_PCIE_EP_TYPE:
|
||||
rcar_gen4_remove_dw_pcie_ep(rcar);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rcar_gen4_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen4_pcie *rcar = platform_get_drvdata(pdev);
|
||||
|
||||
rcar_gen4_remove_dw_pcie(rcar);
|
||||
rcar_gen4_pcie_unprepare(rcar);
|
||||
}
|
||||
|
||||
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-pcie",
|
||||
.data = (void *)DW_PCIE_RC_TYPE,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,rcar-gen4-pcie-ep",
|
||||
.data = (void *)DW_PCIE_EP_TYPE,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen4_pcie_of_match);
|
||||
|
||||
static struct platform_driver rcar_gen4_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "pcie-rcar-gen4",
|
||||
.of_match_table = rcar_gen4_pcie_of_match,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.probe = rcar_gen4_pcie_probe,
|
||||
.remove_new = rcar_gen4_pcie_remove,
|
||||
};
|
||||
module_platform_driver(rcar_gen4_pcie_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Renesas R-Car Gen4 PCIe controller driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -9,6 +9,7 @@
|
||||
* Author: Vidya Sagar <vidyas@nvidia.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
@ -125,7 +126,7 @@
|
||||
|
||||
#define APPL_LTR_MSG_1 0xC4
|
||||
#define LTR_MSG_REQ BIT(15)
|
||||
#define LTR_MST_NO_SNOOP_SHIFT 16
|
||||
#define LTR_NOSNOOP_MSG_REQ BIT(31)
|
||||
|
||||
#define APPL_LTR_MSG_2 0xC8
|
||||
#define APPL_LTR_MSG_2_LTR_MSG_REQ_STATE BIT(3)
|
||||
@ -321,9 +322,9 @@ static void tegra_pcie_icc_set(struct tegra_pcie_dw *pcie)
|
||||
speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, val);
|
||||
width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val);
|
||||
|
||||
val = width * (PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]) / BITS_PER_BYTE);
|
||||
val = width * PCIE_SPEED2MBS_ENC(pcie_link_speed[speed]);
|
||||
|
||||
if (icc_set_bw(pcie->icc_path, MBps_to_icc(val), 0))
|
||||
if (icc_set_bw(pcie->icc_path, Mbps_to_icc(val), 0))
|
||||
dev_err(pcie->dev, "can't set bw[%u]\n", val);
|
||||
|
||||
if (speed >= ARRAY_SIZE(pcie_gen_freq))
|
||||
@ -346,8 +347,7 @@ static void apply_bad_link_workaround(struct dw_pcie_rp *pp)
|
||||
*/
|
||||
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKSTA);
|
||||
if (val & PCI_EXP_LNKSTA_LBMS) {
|
||||
current_link_width = (val & PCI_EXP_LNKSTA_NLW) >>
|
||||
PCI_EXP_LNKSTA_NLW_SHIFT;
|
||||
current_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val);
|
||||
if (pcie->init_link_width > current_link_width) {
|
||||
dev_warn(pci->dev, "PCIe link is bad, width reduced\n");
|
||||
val = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
|
||||
@ -496,8 +496,12 @@ static irqreturn_t tegra_pcie_ep_irq_thread(int irq, void *arg)
|
||||
ktime_t timeout;
|
||||
|
||||
/* 110us for both snoop and no-snoop */
|
||||
val = 110 | (2 << PCI_LTR_SCALE_SHIFT) | LTR_MSG_REQ;
|
||||
val |= (val << LTR_MST_NO_SNOOP_SHIFT);
|
||||
val = FIELD_PREP(PCI_LTR_VALUE_MASK, 110) |
|
||||
FIELD_PREP(PCI_LTR_SCALE_MASK, 2) |
|
||||
LTR_MSG_REQ |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_VALUE, 110) |
|
||||
FIELD_PREP(PCI_LTR_NOSNOOP_SCALE, 2) |
|
||||
LTR_NOSNOOP_MSG_REQ;
|
||||
appl_writel(pcie, val, APPL_LTR_MSG_1);
|
||||
|
||||
/* Send LTR upstream */
|
||||
@ -760,8 +764,7 @@ static void tegra_pcie_enable_system_interrupts(struct dw_pcie_rp *pp)
|
||||
|
||||
val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKSTA);
|
||||
pcie->init_link_width = (val_w & PCI_EXP_LNKSTA_NLW) >>
|
||||
PCI_EXP_LNKSTA_NLW_SHIFT;
|
||||
pcie->init_link_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, val_w);
|
||||
|
||||
val_w = dw_pcie_readw_dbi(&pcie->pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCTL);
|
||||
@ -917,12 +920,6 @@ static int tegra_pcie_dw_host_init(struct dw_pcie_rp *pp)
|
||||
AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
|
||||
|
||||
/* Configure Max lane width from DT */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_MLW;
|
||||
val |= (pcie->num_lanes << PCI_EXP_LNKSTA_NLW_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP, val);
|
||||
|
||||
/* Clear Slot Clock Configuration bit if SRNS configuration */
|
||||
if (pcie->enable_srns) {
|
||||
val_16 = dw_pcie_readw_dbi(pci, pcie->pcie_cap_base +
|
||||
|
@ -539,7 +539,7 @@ static bool mobiveil_pcie_is_bridge(struct mobiveil_pcie *pcie)
|
||||
u32 header_type;
|
||||
|
||||
header_type = mobiveil_csr_readb(pcie, PCI_HEADER_TYPE);
|
||||
header_type &= 0x7f;
|
||||
header_type &= PCI_HEADER_TYPE_MASK;
|
||||
|
||||
return header_type == PCI_HEADER_TYPE_BRIDGE;
|
||||
}
|
||||
|
@ -545,7 +545,7 @@ struct hv_pcidev_description {
|
||||
struct hv_dr_state {
|
||||
struct list_head list_entry;
|
||||
u32 device_count;
|
||||
struct hv_pcidev_description func[];
|
||||
struct hv_pcidev_description func[] __counted_by(device_count);
|
||||
};
|
||||
|
||||
struct hv_pci_dev {
|
||||
|
@ -264,7 +264,7 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
|
||||
*/
|
||||
lnkcap = mvebu_readl(port, PCIE_CAP_PCIEXP + PCI_EXP_LNKCAP);
|
||||
lnkcap &= ~PCI_EXP_LNKCAP_MLW;
|
||||
lnkcap |= (port->is_x4 ? 4 : 1) << 4;
|
||||
lnkcap |= FIELD_PREP(PCI_EXP_LNKCAP_MLW, port->is_x4 ? 4 : 1);
|
||||
mvebu_writel(port, lnkcap, PCIE_CAP_PCIEXP + PCI_EXP_LNKCAP);
|
||||
|
||||
/* Disable Root Bridge I/O space, memory space and bus mastering. */
|
||||
|
@ -163,10 +163,11 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct xgene_pcie *port = pcie_bus_to_port(bus);
|
||||
int ret;
|
||||
|
||||
if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
|
||||
PCIBIOS_SUCCESSFUL)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
ret = pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The v1 controller has a bug in its Configuration Request Retry
|
||||
|
@ -783,7 +783,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie)
|
||||
|
||||
/* make sure we are not in EP mode */
|
||||
iproc_pci_raw_config_read32(pcie, 0, PCI_HEADER_TYPE, 1, &hdr_type);
|
||||
if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) {
|
||||
dev_err(dev, "in EP mode, hdr=%#02x\n", hdr_type);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
|
||||
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,
|
||||
rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), PCI_HEADER_TYPE_MASK,
|
||||
PCI_HEADER_TYPE_NORMAL);
|
||||
|
||||
/* Write out the physical slot number = 0 */
|
||||
|
@ -460,7 +460,7 @@ static int rcar_pcie_hw_init(struct rcar_pcie *pcie)
|
||||
rcar_rmw32(pcie, REXPCAP(0), 0xff, PCI_CAP_ID_EXP);
|
||||
rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
|
||||
PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
|
||||
rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
|
||||
rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), PCI_HEADER_TYPE_MASK,
|
||||
PCI_HEADER_TYPE_BRIDGE);
|
||||
|
||||
/* Enable data link layer active state reporting */
|
||||
|
31
drivers/pci/controller/pcie-xilinx-common.h
Normal file
31
drivers/pci/controller/pcie-xilinx-common.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* (C) Copyright 2023, Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/* Interrupt registers definitions */
|
||||
#define XILINX_PCIE_INTR_LINK_DOWN 0
|
||||
#define XILINX_PCIE_INTR_HOT_RESET 3
|
||||
#define XILINX_PCIE_INTR_CFG_PCIE_TIMEOUT 4
|
||||
#define XILINX_PCIE_INTR_CFG_TIMEOUT 8
|
||||
#define XILINX_PCIE_INTR_CORRECTABLE 9
|
||||
#define XILINX_PCIE_INTR_NONFATAL 10
|
||||
#define XILINX_PCIE_INTR_FATAL 11
|
||||
#define XILINX_PCIE_INTR_CFG_ERR_POISON 12
|
||||
#define XILINX_PCIE_INTR_PME_TO_ACK_RCVD 15
|
||||
#define XILINX_PCIE_INTR_INTX 16
|
||||
#define XILINX_PCIE_INTR_PM_PME_RCVD 17
|
||||
#define XILINX_PCIE_INTR_MSI 17
|
||||
#define XILINX_PCIE_INTR_SLV_UNSUPP 20
|
||||
#define XILINX_PCIE_INTR_SLV_UNEXP 21
|
||||
#define XILINX_PCIE_INTR_SLV_COMPL 22
|
||||
#define XILINX_PCIE_INTR_SLV_ERRP 23
|
||||
#define XILINX_PCIE_INTR_SLV_CMPABT 24
|
||||
#define XILINX_PCIE_INTR_SLV_ILLBUR 25
|
||||
#define XILINX_PCIE_INTR_MST_DECERR 26
|
||||
#define XILINX_PCIE_INTR_MST_SLVERR 27
|
||||
#define XILINX_PCIE_INTR_SLV_PCIE_TIMEOUT 28
|
@ -16,11 +16,9 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pci-ecam.h>
|
||||
|
||||
#include "../pci.h"
|
||||
#include "pcie-xilinx-common.h"
|
||||
|
||||
/* Register definitions */
|
||||
#define XILINX_CPM_PCIE_REG_IDR 0x00000E10
|
||||
@ -38,29 +36,7 @@
|
||||
#define XILINX_CPM_PCIE_IR_ENABLE 0x000002A8
|
||||
#define XILINX_CPM_PCIE_IR_LOCAL BIT(0)
|
||||
|
||||
/* Interrupt registers definitions */
|
||||
#define XILINX_CPM_PCIE_INTR_LINK_DOWN 0
|
||||
#define XILINX_CPM_PCIE_INTR_HOT_RESET 3
|
||||
#define XILINX_CPM_PCIE_INTR_CFG_PCIE_TIMEOUT 4
|
||||
#define XILINX_CPM_PCIE_INTR_CFG_TIMEOUT 8
|
||||
#define XILINX_CPM_PCIE_INTR_CORRECTABLE 9
|
||||
#define XILINX_CPM_PCIE_INTR_NONFATAL 10
|
||||
#define XILINX_CPM_PCIE_INTR_FATAL 11
|
||||
#define XILINX_CPM_PCIE_INTR_CFG_ERR_POISON 12
|
||||
#define XILINX_CPM_PCIE_INTR_PME_TO_ACK_RCVD 15
|
||||
#define XILINX_CPM_PCIE_INTR_INTX 16
|
||||
#define XILINX_CPM_PCIE_INTR_PM_PME_RCVD 17
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_UNSUPP 20
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_UNEXP 21
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_COMPL 22
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_ERRP 23
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_CMPABT 24
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_ILLBUR 25
|
||||
#define XILINX_CPM_PCIE_INTR_MST_DECERR 26
|
||||
#define XILINX_CPM_PCIE_INTR_MST_SLVERR 27
|
||||
#define XILINX_CPM_PCIE_INTR_SLV_PCIE_TIMEOUT 28
|
||||
|
||||
#define IMR(x) BIT(XILINX_CPM_PCIE_INTR_ ##x)
|
||||
#define IMR(x) BIT(XILINX_PCIE_INTR_ ##x)
|
||||
|
||||
#define XILINX_CPM_PCIE_IMR_ALL_MASK \
|
||||
( \
|
||||
@ -323,7 +299,7 @@ static void xilinx_cpm_pcie_event_flow(struct irq_desc *desc)
|
||||
}
|
||||
|
||||
#define _IC(x, s) \
|
||||
[XILINX_CPM_PCIE_INTR_ ## x] = { __stringify(x), s }
|
||||
[XILINX_PCIE_INTR_ ## x] = { __stringify(x), s }
|
||||
|
||||
static const struct {
|
||||
const char *sym;
|
||||
@ -359,9 +335,9 @@ static irqreturn_t xilinx_cpm_pcie_intr_handler(int irq, void *dev_id)
|
||||
d = irq_domain_get_irq_data(port->cpm_domain, irq);
|
||||
|
||||
switch (d->hwirq) {
|
||||
case XILINX_CPM_PCIE_INTR_CORRECTABLE:
|
||||
case XILINX_CPM_PCIE_INTR_NONFATAL:
|
||||
case XILINX_CPM_PCIE_INTR_FATAL:
|
||||
case XILINX_PCIE_INTR_CORRECTABLE:
|
||||
case XILINX_PCIE_INTR_NONFATAL:
|
||||
case XILINX_PCIE_INTR_FATAL:
|
||||
cpm_pcie_clear_err_interrupts(port);
|
||||
fallthrough;
|
||||
|
||||
@ -466,7 +442,7 @@ static int xilinx_cpm_setup_irq(struct xilinx_cpm_pcie *port)
|
||||
}
|
||||
|
||||
port->intx_irq = irq_create_mapping(port->cpm_domain,
|
||||
XILINX_CPM_PCIE_INTR_INTX);
|
||||
XILINX_PCIE_INTR_INTX);
|
||||
if (!port->intx_irq) {
|
||||
dev_err(dev, "Failed to map INTx interrupt\n");
|
||||
return -ENXIO;
|
||||
|
814
drivers/pci/controller/pcie-xilinx-dma-pl.c
Normal file
814
drivers/pci/controller/pcie-xilinx-dma-pl.c
Normal file
@ -0,0 +1,814 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PCIe host controller driver for Xilinx XDMA PCIe Bridge
|
||||
*
|
||||
* Copyright (C) 2023 Xilinx, Inc. All rights reserved.
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
|
||||
#include "../pci.h"
|
||||
#include "pcie-xilinx-common.h"
|
||||
|
||||
/* Register definitions */
|
||||
#define XILINX_PCIE_DMA_REG_IDR 0x00000138
|
||||
#define XILINX_PCIE_DMA_REG_IMR 0x0000013c
|
||||
#define XILINX_PCIE_DMA_REG_PSCR 0x00000144
|
||||
#define XILINX_PCIE_DMA_REG_RPSC 0x00000148
|
||||
#define XILINX_PCIE_DMA_REG_MSIBASE1 0x0000014c
|
||||
#define XILINX_PCIE_DMA_REG_MSIBASE2 0x00000150
|
||||
#define XILINX_PCIE_DMA_REG_RPEFR 0x00000154
|
||||
#define XILINX_PCIE_DMA_REG_IDRN 0x00000160
|
||||
#define XILINX_PCIE_DMA_REG_IDRN_MASK 0x00000164
|
||||
#define XILINX_PCIE_DMA_REG_MSI_LOW 0x00000170
|
||||
#define XILINX_PCIE_DMA_REG_MSI_HI 0x00000174
|
||||
#define XILINX_PCIE_DMA_REG_MSI_LOW_MASK 0x00000178
|
||||
#define XILINX_PCIE_DMA_REG_MSI_HI_MASK 0x0000017c
|
||||
|
||||
#define IMR(x) BIT(XILINX_PCIE_INTR_ ##x)
|
||||
|
||||
#define XILINX_PCIE_INTR_IMR_ALL_MASK \
|
||||
( \
|
||||
IMR(LINK_DOWN) | \
|
||||
IMR(HOT_RESET) | \
|
||||
IMR(CFG_TIMEOUT) | \
|
||||
IMR(CORRECTABLE) | \
|
||||
IMR(NONFATAL) | \
|
||||
IMR(FATAL) | \
|
||||
IMR(INTX) | \
|
||||
IMR(MSI) | \
|
||||
IMR(SLV_UNSUPP) | \
|
||||
IMR(SLV_UNEXP) | \
|
||||
IMR(SLV_COMPL) | \
|
||||
IMR(SLV_ERRP) | \
|
||||
IMR(SLV_CMPABT) | \
|
||||
IMR(SLV_ILLBUR) | \
|
||||
IMR(MST_DECERR) | \
|
||||
IMR(MST_SLVERR) | \
|
||||
)
|
||||
|
||||
#define XILINX_PCIE_DMA_IMR_ALL_MASK 0x0ff30fe9
|
||||
#define XILINX_PCIE_DMA_IDR_ALL_MASK 0xffffffff
|
||||
#define XILINX_PCIE_DMA_IDRN_MASK GENMASK(19, 16)
|
||||
|
||||
/* Root Port Error Register definitions */
|
||||
#define XILINX_PCIE_DMA_RPEFR_ERR_VALID BIT(18)
|
||||
#define XILINX_PCIE_DMA_RPEFR_REQ_ID GENMASK(15, 0)
|
||||
#define XILINX_PCIE_DMA_RPEFR_ALL_MASK 0xffffffff
|
||||
|
||||
/* Root Port Interrupt Register definitions */
|
||||
#define XILINX_PCIE_DMA_IDRN_SHIFT 16
|
||||
|
||||
/* Root Port Status/control Register definitions */
|
||||
#define XILINX_PCIE_DMA_REG_RPSC_BEN BIT(0)
|
||||
|
||||
/* Phy Status/Control Register definitions */
|
||||
#define XILINX_PCIE_DMA_REG_PSCR_LNKUP BIT(11)
|
||||
|
||||
/* Number of MSI IRQs */
|
||||
#define XILINX_NUM_MSI_IRQS 64
|
||||
|
||||
struct xilinx_msi {
|
||||
struct irq_domain *msi_domain;
|
||||
unsigned long *bitmap;
|
||||
struct irq_domain *dev_domain;
|
||||
struct mutex lock; /* Protect bitmap variable */
|
||||
int irq_msi0;
|
||||
int irq_msi1;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pl_dma_pcie - PCIe port information
|
||||
* @dev: Device pointer
|
||||
* @reg_base: IO Mapped Register Base
|
||||
* @irq: Interrupt number
|
||||
* @cfg: Holds mappings of config space window
|
||||
* @phys_reg_base: Physical address of reg base
|
||||
* @intx_domain: Legacy IRQ domain pointer
|
||||
* @pldma_domain: PL DMA IRQ domain pointer
|
||||
* @resources: Bus Resources
|
||||
* @msi: MSI information
|
||||
* @intx_irq: INTx error interrupt number
|
||||
* @lock: Lock protecting shared register access
|
||||
*/
|
||||
struct pl_dma_pcie {
|
||||
struct device *dev;
|
||||
void __iomem *reg_base;
|
||||
int irq;
|
||||
struct pci_config_window *cfg;
|
||||
phys_addr_t phys_reg_base;
|
||||
struct irq_domain *intx_domain;
|
||||
struct irq_domain *pldma_domain;
|
||||
struct list_head resources;
|
||||
struct xilinx_msi msi;
|
||||
int intx_irq;
|
||||
raw_spinlock_t lock;
|
||||
};
|
||||
|
||||
static inline u32 pcie_read(struct pl_dma_pcie *port, u32 reg)
|
||||
{
|
||||
return readl(port->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void pcie_write(struct pl_dma_pcie *port, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, port->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline bool xilinx_pl_dma_pcie_link_up(struct pl_dma_pcie *port)
|
||||
{
|
||||
return (pcie_read(port, XILINX_PCIE_DMA_REG_PSCR) &
|
||||
XILINX_PCIE_DMA_REG_PSCR_LNKUP) ? true : false;
|
||||
}
|
||||
|
||||
static void xilinx_pl_dma_pcie_clear_err_interrupts(struct pl_dma_pcie *port)
|
||||
{
|
||||
unsigned long val = pcie_read(port, XILINX_PCIE_DMA_REG_RPEFR);
|
||||
|
||||
if (val & XILINX_PCIE_DMA_RPEFR_ERR_VALID) {
|
||||
dev_dbg(port->dev, "Requester ID %lu\n",
|
||||
val & XILINX_PCIE_DMA_RPEFR_REQ_ID);
|
||||
pcie_write(port, XILINX_PCIE_DMA_RPEFR_ALL_MASK,
|
||||
XILINX_PCIE_DMA_REG_RPEFR);
|
||||
}
|
||||
}
|
||||
|
||||
static bool xilinx_pl_dma_pcie_valid_device(struct pci_bus *bus,
|
||||
unsigned int devfn)
|
||||
{
|
||||
struct pl_dma_pcie *port = bus->sysdata;
|
||||
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
/*
|
||||
* Checking whether the link is up is the last line of
|
||||
* defense, and this check is inherently racy by definition.
|
||||
* Sending a PIO request to a downstream device when the link is
|
||||
* down causes an unrecoverable error, and a reset of the entire
|
||||
* PCIe controller will be needed. We can reduce the likelihood
|
||||
* of that unrecoverable error by checking whether the link is
|
||||
* up, but we can't completely prevent it because the link may
|
||||
* go down between the link-up check and the PIO request.
|
||||
*/
|
||||
if (!xilinx_pl_dma_pcie_link_up(port))
|
||||
return false;
|
||||
} else if (devfn > 0)
|
||||
/* Only one device down on each root port */
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void __iomem *xilinx_pl_dma_pcie_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pl_dma_pcie *port = bus->sysdata;
|
||||
|
||||
if (!xilinx_pl_dma_pcie_valid_device(bus, devfn))
|
||||
return NULL;
|
||||
|
||||
return port->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
|
||||
}
|
||||
|
||||
/* PCIe operations */
|
||||
static struct pci_ecam_ops xilinx_pl_dma_pcie_ops = {
|
||||
.pci_ops = {
|
||||
.map_bus = xilinx_pl_dma_pcie_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
}
|
||||
};
|
||||
|
||||
static void xilinx_pl_dma_pcie_enable_msi(struct pl_dma_pcie *port)
|
||||
{
|
||||
phys_addr_t msi_addr = port->phys_reg_base;
|
||||
|
||||
pcie_write(port, upper_32_bits(msi_addr), XILINX_PCIE_DMA_REG_MSIBASE1);
|
||||
pcie_write(port, lower_32_bits(msi_addr), XILINX_PCIE_DMA_REG_MSIBASE2);
|
||||
}
|
||||
|
||||
static void xilinx_mask_intx_irq(struct irq_data *data)
|
||||
{
|
||||
struct pl_dma_pcie *port = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u32 mask, val;
|
||||
|
||||
mask = BIT(data->hwirq + XILINX_PCIE_DMA_IDRN_SHIFT);
|
||||
raw_spin_lock_irqsave(&port->lock, flags);
|
||||
val = pcie_read(port, XILINX_PCIE_DMA_REG_IDRN_MASK);
|
||||
pcie_write(port, (val & (~mask)), XILINX_PCIE_DMA_REG_IDRN_MASK);
|
||||
raw_spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void xilinx_unmask_intx_irq(struct irq_data *data)
|
||||
{
|
||||
struct pl_dma_pcie *port = irq_data_get_irq_chip_data(data);
|
||||
unsigned long flags;
|
||||
u32 mask, val;
|
||||
|
||||
mask = BIT(data->hwirq + XILINX_PCIE_DMA_IDRN_SHIFT);
|
||||
raw_spin_lock_irqsave(&port->lock, flags);
|
||||
val = pcie_read(port, XILINX_PCIE_DMA_REG_IDRN_MASK);
|
||||
pcie_write(port, (val | mask), XILINX_PCIE_DMA_REG_IDRN_MASK);
|
||||
raw_spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_leg_irq_chip = {
|
||||
.name = "pl_dma:INTx",
|
||||
.irq_mask = xilinx_mask_intx_irq,
|
||||
.irq_unmask = xilinx_unmask_intx_irq,
|
||||
};
|
||||
|
||||
static int xilinx_pl_dma_pcie_intx_map(struct irq_domain *domain,
|
||||
unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &xilinx_leg_irq_chip, handle_level_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
irq_set_status_flags(irq, IRQ_LEVEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* INTx IRQ Domain operations */
|
||||
static const struct irq_domain_ops intx_domain_ops = {
|
||||
.map = xilinx_pl_dma_pcie_intx_map,
|
||||
};
|
||||
|
||||
static irqreturn_t xilinx_pl_dma_pcie_msi_handler_high(int irq, void *args)
|
||||
{
|
||||
struct xilinx_msi *msi;
|
||||
unsigned long status;
|
||||
u32 bit, virq;
|
||||
struct pl_dma_pcie *port = args;
|
||||
|
||||
msi = &port->msi;
|
||||
|
||||
while ((status = pcie_read(port, XILINX_PCIE_DMA_REG_MSI_HI)) != 0) {
|
||||
for_each_set_bit(bit, &status, 32) {
|
||||
pcie_write(port, 1 << bit, XILINX_PCIE_DMA_REG_MSI_HI);
|
||||
bit = bit + 32;
|
||||
virq = irq_find_mapping(msi->dev_domain, bit);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t xilinx_pl_dma_pcie_msi_handler_low(int irq, void *args)
|
||||
{
|
||||
struct pl_dma_pcie *port = args;
|
||||
struct xilinx_msi *msi;
|
||||
unsigned long status;
|
||||
u32 bit, virq;
|
||||
|
||||
msi = &port->msi;
|
||||
|
||||
while ((status = pcie_read(port, XILINX_PCIE_DMA_REG_MSI_LOW)) != 0) {
|
||||
for_each_set_bit(bit, &status, 32) {
|
||||
pcie_write(port, 1 << bit, XILINX_PCIE_DMA_REG_MSI_LOW);
|
||||
virq = irq_find_mapping(msi->dev_domain, bit);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t xilinx_pl_dma_pcie_event_flow(int irq, void *args)
|
||||
{
|
||||
struct pl_dma_pcie *port = args;
|
||||
unsigned long val;
|
||||
int i;
|
||||
|
||||
val = pcie_read(port, XILINX_PCIE_DMA_REG_IDR);
|
||||
val &= pcie_read(port, XILINX_PCIE_DMA_REG_IMR);
|
||||
for_each_set_bit(i, &val, 32)
|
||||
generic_handle_domain_irq(port->pldma_domain, i);
|
||||
|
||||
pcie_write(port, val, XILINX_PCIE_DMA_REG_IDR);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define _IC(x, s) \
|
||||
[XILINX_PCIE_INTR_ ## x] = { __stringify(x), s }
|
||||
|
||||
static const struct {
|
||||
const char *sym;
|
||||
const char *str;
|
||||
} intr_cause[32] = {
|
||||
_IC(LINK_DOWN, "Link Down"),
|
||||
_IC(HOT_RESET, "Hot reset"),
|
||||
_IC(CFG_TIMEOUT, "ECAM access timeout"),
|
||||
_IC(CORRECTABLE, "Correctable error message"),
|
||||
_IC(NONFATAL, "Non fatal error message"),
|
||||
_IC(FATAL, "Fatal error message"),
|
||||
_IC(SLV_UNSUPP, "Slave unsupported request"),
|
||||
_IC(SLV_UNEXP, "Slave unexpected completion"),
|
||||
_IC(SLV_COMPL, "Slave completion timeout"),
|
||||
_IC(SLV_ERRP, "Slave Error Poison"),
|
||||
_IC(SLV_CMPABT, "Slave Completer Abort"),
|
||||
_IC(SLV_ILLBUR, "Slave Illegal Burst"),
|
||||
_IC(MST_DECERR, "Master decode error"),
|
||||
_IC(MST_SLVERR, "Master slave error"),
|
||||
};
|
||||
|
||||
static irqreturn_t xilinx_pl_dma_pcie_intr_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct pl_dma_pcie *port = (struct pl_dma_pcie *)dev_id;
|
||||
struct device *dev = port->dev;
|
||||
struct irq_data *d;
|
||||
|
||||
d = irq_domain_get_irq_data(port->pldma_domain, irq);
|
||||
switch (d->hwirq) {
|
||||
case XILINX_PCIE_INTR_CORRECTABLE:
|
||||
case XILINX_PCIE_INTR_NONFATAL:
|
||||
case XILINX_PCIE_INTR_FATAL:
|
||||
xilinx_pl_dma_pcie_clear_err_interrupts(port);
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
if (intr_cause[d->hwirq].str)
|
||||
dev_warn(dev, "%s\n", intr_cause[d->hwirq].str);
|
||||
else
|
||||
dev_warn(dev, "Unknown IRQ %ld\n", d->hwirq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_msi_irq_chip = {
|
||||
.name = "pl_dma:PCIe MSI",
|
||||
.irq_enable = pci_msi_unmask_irq,
|
||||
.irq_disable = pci_msi_mask_irq,
|
||||
.irq_mask = pci_msi_mask_irq,
|
||||
.irq_unmask = pci_msi_unmask_irq,
|
||||
};
|
||||
|
||||
static struct msi_domain_info xilinx_msi_domain_info = {
|
||||
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_MULTI_PCI_MSI),
|
||||
.chip = &xilinx_msi_irq_chip,
|
||||
};
|
||||
|
||||
static void xilinx_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
{
|
||||
struct pl_dma_pcie *pcie = irq_data_get_irq_chip_data(data);
|
||||
phys_addr_t msi_addr = pcie->phys_reg_base;
|
||||
|
||||
msg->address_lo = lower_32_bits(msi_addr);
|
||||
msg->address_hi = upper_32_bits(msi_addr);
|
||||
msg->data = data->hwirq;
|
||||
}
|
||||
|
||||
static int xilinx_msi_set_affinity(struct irq_data *irq_data,
|
||||
const struct cpumask *mask, bool force)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_irq_chip = {
|
||||
.name = "pl_dma:MSI",
|
||||
.irq_compose_msi_msg = xilinx_compose_msi_msg,
|
||||
.irq_set_affinity = xilinx_msi_set_affinity,
|
||||
};
|
||||
|
||||
static int xilinx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs, void *args)
|
||||
{
|
||||
struct pl_dma_pcie *pcie = domain->host_data;
|
||||
struct xilinx_msi *msi = &pcie->msi;
|
||||
int bit, i;
|
||||
|
||||
mutex_lock(&msi->lock);
|
||||
bit = bitmap_find_free_region(msi->bitmap, XILINX_NUM_MSI_IRQS,
|
||||
get_count_order(nr_irqs));
|
||||
if (bit < 0) {
|
||||
mutex_unlock(&msi->lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
irq_domain_set_info(domain, virq + i, bit + i, &xilinx_irq_chip,
|
||||
domain->host_data, handle_simple_irq,
|
||||
NULL, NULL);
|
||||
}
|
||||
mutex_unlock(&msi->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xilinx_irq_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *data = irq_domain_get_irq_data(domain, virq);
|
||||
struct pl_dma_pcie *pcie = irq_data_get_irq_chip_data(data);
|
||||
struct xilinx_msi *msi = &pcie->msi;
|
||||
|
||||
mutex_lock(&msi->lock);
|
||||
bitmap_release_region(msi->bitmap, data->hwirq,
|
||||
get_count_order(nr_irqs));
|
||||
mutex_unlock(&msi->lock);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops dev_msi_domain_ops = {
|
||||
.alloc = xilinx_irq_domain_alloc,
|
||||
.free = xilinx_irq_domain_free,
|
||||
};
|
||||
|
||||
static void xilinx_pl_dma_pcie_free_irq_domains(struct pl_dma_pcie *port)
|
||||
{
|
||||
struct xilinx_msi *msi = &port->msi;
|
||||
|
||||
if (port->intx_domain) {
|
||||
irq_domain_remove(port->intx_domain);
|
||||
port->intx_domain = NULL;
|
||||
}
|
||||
|
||||
if (msi->dev_domain) {
|
||||
irq_domain_remove(msi->dev_domain);
|
||||
msi->dev_domain = NULL;
|
||||
}
|
||||
|
||||
if (msi->msi_domain) {
|
||||
irq_domain_remove(msi->msi_domain);
|
||||
msi->msi_domain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int xilinx_pl_dma_pcie_init_msi_irq_domain(struct pl_dma_pcie *port)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct xilinx_msi *msi = &port->msi;
|
||||
int size = BITS_TO_LONGS(XILINX_NUM_MSI_IRQS) * sizeof(long);
|
||||
struct fwnode_handle *fwnode = of_node_to_fwnode(port->dev->of_node);
|
||||
|
||||
msi->dev_domain = irq_domain_add_linear(NULL, XILINX_NUM_MSI_IRQS,
|
||||
&dev_msi_domain_ops, port);
|
||||
if (!msi->dev_domain)
|
||||
goto out;
|
||||
|
||||
msi->msi_domain = pci_msi_create_irq_domain(fwnode,
|
||||
&xilinx_msi_domain_info,
|
||||
msi->dev_domain);
|
||||
if (!msi->msi_domain)
|
||||
goto out;
|
||||
|
||||
mutex_init(&msi->lock);
|
||||
msi->bitmap = kzalloc(size, GFP_KERNEL);
|
||||
if (!msi->bitmap)
|
||||
goto out;
|
||||
|
||||
raw_spin_lock_init(&port->lock);
|
||||
xilinx_pl_dma_pcie_enable_msi(port);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
xilinx_pl_dma_pcie_free_irq_domains(port);
|
||||
dev_err(dev, "Failed to allocate MSI IRQ domains\n");
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* INTx error interrupts are Xilinx controller specific interrupt, used to
|
||||
* notify user about errors such as cfg timeout, slave unsupported requests,
|
||||
* fatal and non fatal error etc.
|
||||
*/
|
||||
|
||||
static irqreturn_t xilinx_pl_dma_pcie_intx_flow(int irq, void *args)
|
||||
{
|
||||
unsigned long val;
|
||||
int i;
|
||||
struct pl_dma_pcie *port = args;
|
||||
|
||||
val = FIELD_GET(XILINX_PCIE_DMA_IDRN_MASK,
|
||||
pcie_read(port, XILINX_PCIE_DMA_REG_IDRN));
|
||||
|
||||
for_each_set_bit(i, &val, PCI_NUM_INTX)
|
||||
generic_handle_domain_irq(port->intx_domain, i);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void xilinx_pl_dma_pcie_mask_event_irq(struct irq_data *d)
|
||||
{
|
||||
struct pl_dma_pcie *port = irq_data_get_irq_chip_data(d);
|
||||
u32 val;
|
||||
|
||||
raw_spin_lock(&port->lock);
|
||||
val = pcie_read(port, XILINX_PCIE_DMA_REG_IMR);
|
||||
val &= ~BIT(d->hwirq);
|
||||
pcie_write(port, val, XILINX_PCIE_DMA_REG_IMR);
|
||||
raw_spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
static void xilinx_pl_dma_pcie_unmask_event_irq(struct irq_data *d)
|
||||
{
|
||||
struct pl_dma_pcie *port = irq_data_get_irq_chip_data(d);
|
||||
u32 val;
|
||||
|
||||
raw_spin_lock(&port->lock);
|
||||
val = pcie_read(port, XILINX_PCIE_DMA_REG_IMR);
|
||||
val |= BIT(d->hwirq);
|
||||
pcie_write(port, val, XILINX_PCIE_DMA_REG_IMR);
|
||||
raw_spin_unlock(&port->lock);
|
||||
}
|
||||
|
||||
static struct irq_chip xilinx_pl_dma_pcie_event_irq_chip = {
|
||||
.name = "pl_dma:RC-Event",
|
||||
.irq_mask = xilinx_pl_dma_pcie_mask_event_irq,
|
||||
.irq_unmask = xilinx_pl_dma_pcie_unmask_event_irq,
|
||||
};
|
||||
|
||||
static int xilinx_pl_dma_pcie_event_map(struct irq_domain *domain,
|
||||
unsigned int irq, irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &xilinx_pl_dma_pcie_event_irq_chip,
|
||||
handle_level_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
irq_set_status_flags(irq, IRQ_LEVEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops event_domain_ops = {
|
||||
.map = xilinx_pl_dma_pcie_event_map,
|
||||
};
|
||||
|
||||
/**
|
||||
* xilinx_pl_dma_pcie_init_irq_domain - Initialize IRQ domain
|
||||
* @port: PCIe port information
|
||||
*
|
||||
* Return: '0' on success and error value on failure.
|
||||
*/
|
||||
static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *pcie_intc_node;
|
||||
int ret;
|
||||
|
||||
/* Setup INTx */
|
||||
pcie_intc_node = of_get_child_by_name(node, "interrupt-controller");
|
||||
if (!pcie_intc_node) {
|
||||
dev_err(dev, "No PCIe Intc node found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port->pldma_domain = irq_domain_add_linear(pcie_intc_node, 32,
|
||||
&event_domain_ops, port);
|
||||
if (!port->pldma_domain)
|
||||
return -ENOMEM;
|
||||
|
||||
irq_domain_update_bus_token(port->pldma_domain, DOMAIN_BUS_NEXUS);
|
||||
|
||||
port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
|
||||
&intx_domain_ops, port);
|
||||
if (!port->intx_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
return PTR_ERR(port->intx_domain);
|
||||
}
|
||||
|
||||
irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
|
||||
|
||||
ret = xilinx_pl_dma_pcie_init_msi_irq_domain(port);
|
||||
if (ret != 0) {
|
||||
irq_domain_remove(port->intx_domain);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
of_node_put(pcie_intc_node);
|
||||
raw_spin_lock_init(&port->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_pl_dma_pcie_setup_irq(struct pl_dma_pcie *port)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int i, irq, err;
|
||||
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
if (port->irq < 0)
|
||||
return port->irq;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(intr_cause); i++) {
|
||||
int err;
|
||||
|
||||
if (!intr_cause[i].str)
|
||||
continue;
|
||||
|
||||
irq = irq_create_mapping(port->pldma_domain, i);
|
||||
if (!irq) {
|
||||
dev_err(dev, "Failed to map interrupt\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, irq,
|
||||
xilinx_pl_dma_pcie_intr_handler,
|
||||
IRQF_SHARED | IRQF_NO_THREAD,
|
||||
intr_cause[i].sym, port);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request IRQ %d\n", irq);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
port->intx_irq = irq_create_mapping(port->pldma_domain,
|
||||
XILINX_PCIE_INTR_INTX);
|
||||
if (!port->intx_irq) {
|
||||
dev_err(dev, "Failed to map INTx interrupt\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, port->intx_irq, xilinx_pl_dma_pcie_intx_flow,
|
||||
IRQF_SHARED | IRQF_NO_THREAD, NULL, port);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request INTx IRQ %d\n", irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_request_irq(dev, port->irq, xilinx_pl_dma_pcie_event_flow,
|
||||
IRQF_SHARED | IRQF_NO_THREAD, NULL, port);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request event IRQ %d\n", irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xilinx_pl_dma_pcie_init_port(struct pl_dma_pcie *port)
|
||||
{
|
||||
if (xilinx_pl_dma_pcie_link_up(port))
|
||||
dev_info(port->dev, "PCIe Link is UP\n");
|
||||
else
|
||||
dev_info(port->dev, "PCIe Link is DOWN\n");
|
||||
|
||||
/* Disable all interrupts */
|
||||
pcie_write(port, ~XILINX_PCIE_DMA_IDR_ALL_MASK,
|
||||
XILINX_PCIE_DMA_REG_IMR);
|
||||
|
||||
/* Clear pending interrupts */
|
||||
pcie_write(port, pcie_read(port, XILINX_PCIE_DMA_REG_IDR) &
|
||||
XILINX_PCIE_DMA_IMR_ALL_MASK,
|
||||
XILINX_PCIE_DMA_REG_IDR);
|
||||
|
||||
/* Needed for MSI DECODE MODE */
|
||||
pcie_write(port, XILINX_PCIE_DMA_IDR_ALL_MASK,
|
||||
XILINX_PCIE_DMA_REG_MSI_LOW_MASK);
|
||||
pcie_write(port, XILINX_PCIE_DMA_IDR_ALL_MASK,
|
||||
XILINX_PCIE_DMA_REG_MSI_HI_MASK);
|
||||
|
||||
/* Set the Bridge enable bit */
|
||||
pcie_write(port, pcie_read(port, XILINX_PCIE_DMA_REG_RPSC) |
|
||||
XILINX_PCIE_DMA_REG_RPSC_BEN,
|
||||
XILINX_PCIE_DMA_REG_RPSC);
|
||||
}
|
||||
|
||||
static int xilinx_request_msi_irq(struct pl_dma_pcie *port)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int ret;
|
||||
|
||||
port->msi.irq_msi0 = platform_get_irq_byname(pdev, "msi0");
|
||||
if (port->msi.irq_msi0 <= 0) {
|
||||
dev_err(dev, "Unable to find msi0 IRQ line\n");
|
||||
return port->msi.irq_msi0;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, port->msi.irq_msi0, xilinx_pl_dma_pcie_msi_handler_low,
|
||||
IRQF_SHARED | IRQF_NO_THREAD, "xlnx-pcie-dma-pl",
|
||||
port);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register interrupt\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
port->msi.irq_msi1 = platform_get_irq_byname(pdev, "msi1");
|
||||
if (port->msi.irq_msi1 <= 0) {
|
||||
dev_err(dev, "Unable to find msi1 IRQ line\n");
|
||||
return port->msi.irq_msi1;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(dev, port->msi.irq_msi1, xilinx_pl_dma_pcie_msi_handler_high,
|
||||
IRQF_SHARED | IRQF_NO_THREAD, "xlnx-pcie-dma-pl",
|
||||
port);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register interrupt\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_pl_dma_pcie_parse_dt(struct pl_dma_pcie *port,
|
||||
struct resource *bus_range)
|
||||
{
|
||||
struct device *dev = port->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
int err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "Missing \"reg\" property\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
port->phys_reg_base = res->start;
|
||||
|
||||
port->cfg = pci_ecam_create(dev, res, bus_range, &xilinx_pl_dma_pcie_ops);
|
||||
if (IS_ERR(port->cfg))
|
||||
return PTR_ERR(port->cfg);
|
||||
|
||||
port->reg_base = port->cfg->win;
|
||||
|
||||
err = xilinx_request_msi_irq(port);
|
||||
if (err) {
|
||||
pci_ecam_free(port->cfg);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_pl_dma_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pl_dma_pcie *port;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource_entry *bus;
|
||||
int err;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*port));
|
||||
if (!bridge)
|
||||
return -ENODEV;
|
||||
|
||||
port = pci_host_bridge_priv(bridge);
|
||||
|
||||
port->dev = dev;
|
||||
|
||||
bus = resource_list_first_type(&bridge->windows, IORESOURCE_BUS);
|
||||
if (!bus)
|
||||
return -ENODEV;
|
||||
|
||||
err = xilinx_pl_dma_pcie_parse_dt(port, bus->res);
|
||||
if (err) {
|
||||
dev_err(dev, "Parsing DT failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
xilinx_pl_dma_pcie_init_port(port);
|
||||
|
||||
err = xilinx_pl_dma_pcie_init_irq_domain(port);
|
||||
if (err)
|
||||
goto err_irq_domain;
|
||||
|
||||
err = xilinx_pl_dma_pcie_setup_irq(port);
|
||||
|
||||
bridge->sysdata = port;
|
||||
bridge->ops = &xilinx_pl_dma_pcie_ops.pci_ops;
|
||||
|
||||
err = pci_host_probe(bridge);
|
||||
if (err < 0)
|
||||
goto err_host_bridge;
|
||||
|
||||
return 0;
|
||||
|
||||
err_host_bridge:
|
||||
xilinx_pl_dma_pcie_free_irq_domains(port);
|
||||
|
||||
err_irq_domain:
|
||||
pci_ecam_free(port->cfg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id xilinx_pl_dma_pcie_of_match[] = {
|
||||
{
|
||||
.compatible = "xlnx,xdma-host-3.00",
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver xilinx_pl_dma_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "xilinx-xdma-pcie",
|
||||
.of_match_table = xilinx_pl_dma_pcie_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = xilinx_pl_dma_pcie_probe,
|
||||
};
|
||||
|
||||
builtin_platform_driver(xilinx_pl_dma_pcie_driver);
|
@ -126,7 +126,7 @@
|
||||
#define E_ECAM_CR_ENABLE BIT(0)
|
||||
#define E_ECAM_SIZE_LOC GENMASK(20, 16)
|
||||
#define E_ECAM_SIZE_SHIFT 16
|
||||
#define NWL_ECAM_VALUE_DEFAULT 12
|
||||
#define NWL_ECAM_MAX_SIZE 16
|
||||
|
||||
#define CFG_DMA_REG_BAR GENMASK(2, 0)
|
||||
#define CFG_PCIE_CACHE GENMASK(7, 0)
|
||||
@ -165,8 +165,6 @@ struct nwl_pcie {
|
||||
u32 ecam_size;
|
||||
int irq_intx;
|
||||
int irq_misc;
|
||||
u32 ecam_value;
|
||||
u8 last_busno;
|
||||
struct nwl_msi msi;
|
||||
struct irq_domain *legacy_irq_domain;
|
||||
struct clk *clk;
|
||||
@ -625,7 +623,7 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
u32 breg_val, ecam_val, first_busno = 0;
|
||||
u32 breg_val, ecam_val;
|
||||
int err;
|
||||
|
||||
breg_val = nwl_bridge_readl(pcie, E_BREG_CAPABILITIES) & BREG_PRESENT;
|
||||
@ -675,7 +673,7 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
|
||||
E_ECAM_CR_ENABLE, E_ECAM_CONTROL);
|
||||
|
||||
nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, E_ECAM_CONTROL) |
|
||||
(pcie->ecam_value << E_ECAM_SIZE_SHIFT),
|
||||
(NWL_ECAM_MAX_SIZE << E_ECAM_SIZE_SHIFT),
|
||||
E_ECAM_CONTROL);
|
||||
|
||||
nwl_bridge_writel(pcie, lower_32_bits(pcie->phys_ecam_base),
|
||||
@ -683,15 +681,6 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
|
||||
nwl_bridge_writel(pcie, upper_32_bits(pcie->phys_ecam_base),
|
||||
E_ECAM_BASE_HI);
|
||||
|
||||
/* Get bus range */
|
||||
ecam_val = nwl_bridge_readl(pcie, E_ECAM_CONTROL);
|
||||
pcie->last_busno = (ecam_val & E_ECAM_SIZE_LOC) >> E_ECAM_SIZE_SHIFT;
|
||||
/* Write primary, secondary and subordinate bus numbers */
|
||||
ecam_val = first_busno;
|
||||
ecam_val |= (first_busno + 1) << 8;
|
||||
ecam_val |= (pcie->last_busno << E_ECAM_SIZE_SHIFT);
|
||||
writel(ecam_val, (pcie->ecam_base + PCI_PRIMARY_BUS));
|
||||
|
||||
if (nwl_pcie_link_up(pcie))
|
||||
dev_info(dev, "Link is UP\n");
|
||||
else
|
||||
@ -792,7 +781,6 @@ static int nwl_pcie_probe(struct platform_device *pdev)
|
||||
pcie = pci_host_bridge_priv(bridge);
|
||||
|
||||
pcie->dev = dev;
|
||||
pcie->ecam_value = NWL_ECAM_VALUE_DEFAULT;
|
||||
|
||||
err = nwl_pcie_parse_dt(pcie, pdev);
|
||||
if (err) {
|
||||
|
@ -525,10 +525,9 @@ static void vmd_domain_reset(struct vmd_dev *vmd)
|
||||
base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,
|
||||
PCI_DEVFN(dev, 0), 0);
|
||||
|
||||
hdr_type = readb(base + PCI_HEADER_TYPE) &
|
||||
PCI_HEADER_TYPE_MASK;
|
||||
hdr_type = readb(base + PCI_HEADER_TYPE);
|
||||
|
||||
functions = (hdr_type & 0x80) ? 8 : 1;
|
||||
functions = (hdr_type & PCI_HEADER_TYPE_MFD) ? 8 : 1;
|
||||
for (fn = 0; fn < functions; fn++) {
|
||||
base = vmd->cfgbar + PCIE_ECAM_OFFSET(bus,
|
||||
PCI_DEVFN(dev, fn), 0);
|
||||
@ -1078,10 +1077,7 @@ static int vmd_resume(struct device *dev)
|
||||
struct vmd_dev *vmd = pci_get_drvdata(pdev);
|
||||
int err, i;
|
||||
|
||||
if (vmd->irq_domain)
|
||||
vmd_set_msi_remapping(vmd, true);
|
||||
else
|
||||
vmd_set_msi_remapping(vmd, false);
|
||||
vmd_set_msi_remapping(vmd, !!vmd->irq_domain);
|
||||
|
||||
for (i = 0; i < vmd->msix_count; i++) {
|
||||
err = devm_request_irq(dev, vmd->irqs[i].virq,
|
||||
|
@ -38,7 +38,7 @@ static int devm_pci_epc_match(struct device *dev, void *res, void *match_data)
|
||||
*/
|
||||
void pci_epc_put(struct pci_epc *epc)
|
||||
{
|
||||
if (!epc || IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc))
|
||||
return;
|
||||
|
||||
module_put(epc->ops->owner);
|
||||
@ -660,7 +660,7 @@ void pci_epc_remove_epf(struct pci_epc *epc, struct pci_epf *epf,
|
||||
struct list_head *list;
|
||||
u32 func_no = 0;
|
||||
|
||||
if (!epc || IS_ERR(epc) || !epf)
|
||||
if (IS_ERR_OR_NULL(epc) || !epf)
|
||||
return;
|
||||
|
||||
if (type == PRIMARY_INTERFACE) {
|
||||
@ -691,7 +691,7 @@ void pci_epc_linkup(struct pci_epc *epc)
|
||||
{
|
||||
struct pci_epf *epf;
|
||||
|
||||
if (!epc || IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc))
|
||||
return;
|
||||
|
||||
mutex_lock(&epc->list_lock);
|
||||
@ -717,7 +717,7 @@ void pci_epc_linkdown(struct pci_epc *epc)
|
||||
{
|
||||
struct pci_epf *epf;
|
||||
|
||||
if (!epc || IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc))
|
||||
return;
|
||||
|
||||
mutex_lock(&epc->list_lock);
|
||||
@ -743,7 +743,7 @@ void pci_epc_init_notify(struct pci_epc *epc)
|
||||
{
|
||||
struct pci_epf *epf;
|
||||
|
||||
if (!epc || IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc))
|
||||
return;
|
||||
|
||||
mutex_lock(&epc->list_lock);
|
||||
@ -769,7 +769,7 @@ void pci_epc_bme_notify(struct pci_epc *epc)
|
||||
{
|
||||
struct pci_epf *epf;
|
||||
|
||||
if (!epc || IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc))
|
||||
return;
|
||||
|
||||
mutex_lock(&epc->list_lock);
|
||||
@ -869,7 +869,6 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
|
||||
|
||||
put_dev:
|
||||
put_device(&epc->dev);
|
||||
kfree(epc);
|
||||
|
||||
err_ret:
|
||||
return ERR_PTR(ret);
|
||||
|
@ -61,6 +61,18 @@ config HOTPLUG_PCI_ACPI
|
||||
|
||||
When in doubt, say N.
|
||||
|
||||
config HOTPLUG_PCI_ACPI_AMPERE_ALTRA
|
||||
tristate "ACPI PCI Hotplug driver Ampere Altra extensions"
|
||||
depends on HOTPLUG_PCI_ACPI
|
||||
depends on HAVE_ARM_SMCCC_DISCOVERY
|
||||
help
|
||||
Say Y here if you have an Ampere Altra system.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called acpiphp_ampere_altra.
|
||||
|
||||
When in doubt, say N.
|
||||
|
||||
config HOTPLUG_PCI_ACPI_IBM
|
||||
tristate "ACPI PCI Hotplug driver IBM extensions"
|
||||
depends on HOTPLUG_PCI_ACPI
|
||||
|
@ -23,6 +23,7 @@ obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o
|
||||
|
||||
# acpiphp_ibm extends acpiphp, so should be linked afterwards.
|
||||
|
||||
obj-$(CONFIG_HOTPLUG_PCI_ACPI_AMPERE_ALTRA) += acpiphp_ampere_altra.o
|
||||
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
|
||||
|
||||
pci_hotplug-objs := pci_hotplug_core.o
|
||||
|
127
drivers/pci/hotplug/acpiphp_ampere_altra.c
Normal file
127
drivers/pci/hotplug/acpiphp_ampere_altra.c
Normal file
@ -0,0 +1,127 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ACPI PCI Hot Plug Extension for Ampere Altra. Allows control of
|
||||
* attention LEDs via requests to system firmware.
|
||||
*
|
||||
* Copyright (C) 2023 Ampere Computing LLC
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "acpiphp_ampere_altra: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "acpiphp.h"
|
||||
|
||||
#define HANDLE_OPEN 0xb0200000
|
||||
#define HANDLE_CLOSE 0xb0300000
|
||||
#define REQUEST 0xf0700000
|
||||
#define LED_CMD 0x00000004
|
||||
#define LED_ATTENTION 0x00000002
|
||||
#define LED_SET_ON 0x00000001
|
||||
#define LED_SET_OFF 0x00000002
|
||||
#define LED_SET_BLINK 0x00000003
|
||||
|
||||
static u32 led_service_id[4];
|
||||
|
||||
static int led_status(u8 status)
|
||||
{
|
||||
switch (status) {
|
||||
case 1: return LED_SET_ON;
|
||||
case 2: return LED_SET_BLINK;
|
||||
default: return LED_SET_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_attention_status(struct hotplug_slot *slot, u8 status)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
struct pci_bus *bus;
|
||||
struct pci_dev *root_port;
|
||||
unsigned long flags;
|
||||
u32 handle;
|
||||
int ret = 0;
|
||||
|
||||
bus = slot->pci_slot->bus;
|
||||
root_port = pcie_find_root_port(bus->self);
|
||||
if (!root_port)
|
||||
return -ENODEV;
|
||||
|
||||
local_irq_save(flags);
|
||||
arm_smccc_smc(HANDLE_OPEN, led_service_id[0], led_service_id[1],
|
||||
led_service_id[2], led_service_id[3], 0, 0, 0, &res);
|
||||
if (res.a0) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
handle = res.a1 & 0xffff0000;
|
||||
|
||||
arm_smccc_smc(REQUEST, LED_CMD, led_status(status), LED_ATTENTION,
|
||||
(PCI_SLOT(root_port->devfn) << 4) | (pci_domain_nr(bus) & 0xf),
|
||||
0, 0, handle, &res);
|
||||
if (res.a0)
|
||||
ret = -ENODEV;
|
||||
|
||||
arm_smccc_smc(HANDLE_CLOSE, handle, 0, 0, 0, 0, 0, 0, &res);
|
||||
|
||||
out:
|
||||
local_irq_restore(flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_attention_status(struct hotplug_slot *slot, u8 *status)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct acpiphp_attention_info ampere_altra_attn = {
|
||||
.set_attn = set_attention_status,
|
||||
.get_attn = get_attention_status,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int altra_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
|
||||
int ret;
|
||||
|
||||
ret = fwnode_property_read_u32_array(fwnode, "uuid", led_service_id, 4);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't find uuid\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = acpiphp_register_attention(&ere_altra_attn);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't register driver\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void altra_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
acpiphp_unregister_attention(&ere_altra_attn);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id altra_led_ids[] = {
|
||||
{ "AMPC0008", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, altra_led_ids);
|
||||
|
||||
static struct platform_driver altra_led_driver = {
|
||||
.driver = {
|
||||
.name = "ampere-altra-leds",
|
||||
.acpi_match_table = altra_led_ids,
|
||||
},
|
||||
.probe = altra_led_probe,
|
||||
.remove_new = altra_led_remove,
|
||||
};
|
||||
module_platform_driver(altra_led_driver);
|
||||
|
||||
MODULE_AUTHOR("D Scott Phillips <scott@os.amperecomputing.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -78,8 +78,7 @@ int acpiphp_register_attention(struct acpiphp_attention_info *info)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (info && info->owner && info->set_attn &&
|
||||
info->get_attn && !attention_info) {
|
||||
if (info && info->set_attn && info->get_attn && !attention_info) {
|
||||
retval = 0;
|
||||
attention_info = info;
|
||||
}
|
||||
|
@ -2059,7 +2059,7 @@ int cpqhp_process_SS(struct controller *ctrl, struct pci_func *func)
|
||||
return rc;
|
||||
|
||||
/* If it's a bridge, check the VGA Enable bit */
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
rc = pci_bus_read_config_byte(pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -2342,7 +2342,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((temp_byte & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* set Primary bus */
|
||||
dbg("set Primary bus = %d\n", func->bus);
|
||||
rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func->bus);
|
||||
@ -2739,7 +2739,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
|
||||
* PCI_BRIDGE_CTL_SERR |
|
||||
* PCI_BRIDGE_CTL_NO_ISA */
|
||||
rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
|
||||
} else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
|
||||
} else if ((temp_byte & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) {
|
||||
/* Standard device */
|
||||
rc = pci_bus_read_config_byte(pci_bus, devfn, 0x0B, &class_code);
|
||||
|
||||
|
@ -363,7 +363,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
|
||||
return rc;
|
||||
|
||||
/* If multi-function device, set max_functions to 8 */
|
||||
if (header_type & 0x80)
|
||||
if (header_type & PCI_HEADER_TYPE_MFD)
|
||||
max_functions = 8;
|
||||
else
|
||||
max_functions = 1;
|
||||
@ -372,7 +372,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
|
||||
|
||||
do {
|
||||
DevError = 0;
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* Recurse the subordinate bus
|
||||
* get the subordinate bus number
|
||||
*/
|
||||
@ -487,13 +487,13 @@ int cpqhp_save_slot_config(struct controller *ctrl, struct pci_func *new_slot)
|
||||
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code);
|
||||
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type);
|
||||
|
||||
if (header_type & 0x80) /* Multi-function device */
|
||||
if (header_type & PCI_HEADER_TYPE_MFD)
|
||||
max_functions = 8;
|
||||
else
|
||||
max_functions = 1;
|
||||
|
||||
while (function < max_functions) {
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* Recurse the subordinate bus */
|
||||
pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus);
|
||||
|
||||
@ -571,7 +571,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func)
|
||||
/* Check for Bridge */
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
|
||||
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
|
||||
|
||||
sub_bus = (int) secondary_bus;
|
||||
@ -625,7 +625,7 @@ int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func *func)
|
||||
|
||||
} /* End of base register loop */
|
||||
|
||||
} else if ((header_type & 0x7F) == 0x00) {
|
||||
} else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) {
|
||||
/* Figure out IO and memory base lengths */
|
||||
for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
|
||||
temp_register = 0xFFFFFFFF;
|
||||
@ -723,7 +723,7 @@ int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func)
|
||||
/* Check for Bridge */
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
|
||||
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* Clear Bridge Control Register */
|
||||
command = 0x00;
|
||||
pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
|
||||
@ -858,7 +858,7 @@ int cpqhp_save_used_resources(struct controller *ctrl, struct pci_func *func)
|
||||
}
|
||||
} /* End of base register loop */
|
||||
/* Standard header */
|
||||
} else if ((header_type & 0x7F) == 0x00) {
|
||||
} else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) {
|
||||
/* Figure out IO and memory base lengths */
|
||||
for (cloop = 0x10; cloop <= 0x24; cloop += 4) {
|
||||
pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base);
|
||||
@ -975,7 +975,7 @@ int cpqhp_configure_board(struct controller *ctrl, struct pci_func *func)
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
|
||||
|
||||
/* If this is a bridge device, restore subordinate devices */
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus);
|
||||
|
||||
sub_bus = (int) secondary_bus;
|
||||
@ -1067,7 +1067,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func)
|
||||
/* Check for Bridge */
|
||||
pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type);
|
||||
|
||||
if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* In order to continue checking, we must program the
|
||||
* bus registers in the bridge to respond to accesses
|
||||
* for its subordinate bus(es)
|
||||
@ -1090,7 +1090,7 @@ int cpqhp_valid_replace(struct controller *ctrl, struct pci_func *func)
|
||||
|
||||
}
|
||||
/* Check to see if it is a standard config header */
|
||||
else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) {
|
||||
else if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_NORMAL) {
|
||||
/* Check subsystem vendor and ID */
|
||||
pci_bus_read_config_dword(pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register);
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/pci_regs.h>
|
||||
|
||||
extern int ibmphp_debug;
|
||||
|
||||
@ -286,8 +287,8 @@ int ibmphp_register_pci(void);
|
||||
|
||||
/* pci specific defines */
|
||||
#define PCI_VENDOR_ID_NOTVALID 0xFFFF
|
||||
#define PCI_HEADER_TYPE_MULTIDEVICE 0x80
|
||||
#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81
|
||||
#define PCI_HEADER_TYPE_MULTIDEVICE (PCI_HEADER_TYPE_MFD|PCI_HEADER_TYPE_NORMAL)
|
||||
#define PCI_HEADER_TYPE_MULTIBRIDGE (PCI_HEADER_TYPE_MFD|PCI_HEADER_TYPE_BRIDGE)
|
||||
|
||||
#define LATENCY 0x64
|
||||
#define CACHE 64
|
||||
|
@ -1087,7 +1087,7 @@ static struct res_needed *scan_behind_bridge(struct pci_func *func, u8 busno)
|
||||
pci_bus_read_config_dword(ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class);
|
||||
|
||||
debug("hdr_type behind the bridge is %x\n", hdr_type);
|
||||
if ((hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
if ((hdr_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
|
||||
err("embedded bridges not supported for hot-plugging.\n");
|
||||
amount->not_correct = 1;
|
||||
return amount;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define pr_fmt(fmt) "pciehp: " fmt
|
||||
#define dev_fmt pr_fmt
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
@ -103,7 +104,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
|
||||
struct pci_dev *pdev = ctrl->pcie->port;
|
||||
|
||||
if (status)
|
||||
status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT;
|
||||
status = FIELD_PREP(PCI_EXP_SLTCTL_AIC, status);
|
||||
else
|
||||
status = PCI_EXP_SLTCTL_ATTN_IND_OFF;
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#define dev_fmt(fmt) "pciehp: " fmt
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
@ -484,7 +485,7 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
|
||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||
|
||||
pci_config_pm_runtime_get(pdev);
|
||||
pcie_write_cmd_nowait(ctrl, status << 6,
|
||||
pcie_write_cmd_nowait(ctrl, FIELD_PREP(PCI_EXP_SLTCTL_AIC, status),
|
||||
PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC);
|
||||
pci_config_pm_runtime_put(pdev);
|
||||
return 0;
|
||||
@ -1028,7 +1029,7 @@ struct controller *pcie_init(struct pcie_device *dev)
|
||||
PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC);
|
||||
|
||||
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c IbPresDis%c LLActRep%c%s\n",
|
||||
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
|
||||
FIELD_GET(PCI_EXP_SLTCAP_PSN, slot_cap),
|
||||
FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
|
||||
FLAG(slot_cap, PCI_EXP_SLTCAP_PCP),
|
||||
FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP),
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright Gavin Shan, IBM Corporation 2016.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
@ -731,7 +732,7 @@ static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
|
||||
|
||||
/* Check hotplug MSIx entry is in range */
|
||||
pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
|
||||
entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9;
|
||||
entry.entry = FIELD_GET(PCI_EXP_FLAGS_IRQ, pcie_flag);
|
||||
if (entry.entry >= nr_entries)
|
||||
return -ERANGE;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
|
||||
* Copyright (C) 2016 Christoph Hellwig.
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/irq.h>
|
||||
@ -188,7 +189,7 @@ static inline void pci_write_msg_msi(struct pci_dev *dev, struct msi_desc *desc,
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl);
|
||||
msgctl &= ~PCI_MSI_FLAGS_QSIZE;
|
||||
msgctl |= desc->pci.msi_attrib.multiple << 4;
|
||||
msgctl |= FIELD_PREP(PCI_MSI_FLAGS_QSIZE, desc->pci.msi_attrib.multiple);
|
||||
pci_write_config_word(dev, pos + PCI_MSI_FLAGS, msgctl);
|
||||
|
||||
pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, msg->address_lo);
|
||||
@ -299,7 +300,7 @@ static int msi_setup_msi_desc(struct pci_dev *dev, int nvec,
|
||||
desc.pci.msi_attrib.is_64 = !!(control & PCI_MSI_FLAGS_64BIT);
|
||||
desc.pci.msi_attrib.can_mask = !!(control & PCI_MSI_FLAGS_MASKBIT);
|
||||
desc.pci.msi_attrib.default_irq = dev->irq;
|
||||
desc.pci.msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
|
||||
desc.pci.msi_attrib.multi_cap = FIELD_GET(PCI_MSI_FLAGS_QMASK, control);
|
||||
desc.pci.msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
|
||||
desc.affinity = masks;
|
||||
|
||||
@ -478,7 +479,7 @@ int pci_msi_vec_count(struct pci_dev *dev)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
|
||||
ret = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1);
|
||||
ret = 1 << FIELD_GET(PCI_MSI_FLAGS_QMASK, msgctl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -511,7 +512,8 @@ void __pci_restore_msi_state(struct pci_dev *dev)
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
|
||||
pci_msi_update_mask(entry, 0, 0);
|
||||
control &= ~PCI_MSI_FLAGS_QSIZE;
|
||||
control |= (entry->pci.msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE;
|
||||
control |= PCI_MSI_FLAGS_ENABLE |
|
||||
FIELD_PREP(PCI_MSI_FLAGS_QSIZE, entry->pci.msi_attrib.multiple);
|
||||
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
|
||||
}
|
||||
|
||||
|
@ -28,9 +28,9 @@ struct pci_p2pdma {
|
||||
};
|
||||
|
||||
struct pci_p2pdma_pagemap {
|
||||
struct dev_pagemap pgmap;
|
||||
struct pci_dev *provider;
|
||||
u64 bus_offset;
|
||||
struct dev_pagemap pgmap;
|
||||
};
|
||||
|
||||
static struct pci_p2pdma_pagemap *to_p2p_pgmap(struct dev_pagemap *pgmap)
|
||||
@ -837,7 +837,6 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
|
||||
if (unlikely(!percpu_ref_tryget_live_rcu(ref))) {
|
||||
gen_pool_free(p2pdma->pool, (unsigned long) ret, size);
|
||||
ret = NULL;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
@ -911,7 +911,7 @@ pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
|
||||
{
|
||||
int acpi_state, d_max;
|
||||
|
||||
if (pdev->no_d3cold)
|
||||
if (pdev->no_d3cold || !pdev->d3cold_allowed)
|
||||
d_max = ACPI_STATE_D3_HOT;
|
||||
else
|
||||
d_max = ACPI_STATE_D3_COLD;
|
||||
@ -1215,12 +1215,12 @@ void acpi_pci_add_bus(struct pci_bus *bus)
|
||||
if (!pci_is_root_bus(bus))
|
||||
return;
|
||||
|
||||
obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3,
|
||||
DSM_PCI_POWER_ON_RESET_DELAY, NULL);
|
||||
obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(bus->bridge), &pci_acpi_dsm_guid, 3,
|
||||
DSM_PCI_POWER_ON_RESET_DELAY, NULL, ACPI_TYPE_INTEGER);
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
|
||||
if (obj->integer.value == 1) {
|
||||
bridge = pci_find_host_bridge(bus);
|
||||
bridge->ignore_reset_delay = 1;
|
||||
}
|
||||
@ -1376,12 +1376,13 @@ static void pci_acpi_optimize_delay(struct pci_dev *pdev,
|
||||
if (bridge->ignore_reset_delay)
|
||||
pdev->d3cold_delay = 0;
|
||||
|
||||
obj = acpi_evaluate_dsm(handle, &pci_acpi_dsm_guid, 3,
|
||||
DSM_PCI_DEVICE_READINESS_DURATIONS, NULL);
|
||||
obj = acpi_evaluate_dsm_typed(handle, &pci_acpi_dsm_guid, 3,
|
||||
DSM_PCI_DEVICE_READINESS_DURATIONS, NULL,
|
||||
ACPI_TYPE_PACKAGE);
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
|
||||
if (obj->package.count == 5) {
|
||||
elements = obj->package.elements;
|
||||
if (elements[0].type == ACPI_TYPE_INTEGER) {
|
||||
value = (int)elements[0].integer.value / 1000;
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Modeled after usb's driverfs.c
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
@ -230,8 +230,7 @@ static ssize_t current_link_width_show(struct device *dev,
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
return sysfs_emit(buf, "%u\n",
|
||||
(linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT);
|
||||
return sysfs_emit(buf, "%u\n", FIELD_GET(PCI_EXP_LNKSTA_NLW, linkstat));
|
||||
}
|
||||
static DEVICE_ATTR_RO(current_link_width);
|
||||
|
||||
@ -530,10 +529,7 @@ static ssize_t d3cold_allowed_store(struct device *dev,
|
||||
return -EINVAL;
|
||||
|
||||
pdev->d3cold_allowed = !!val;
|
||||
if (pdev->d3cold_allowed)
|
||||
pci_d3cold_enable(pdev);
|
||||
else
|
||||
pci_d3cold_disable(pdev);
|
||||
pci_bridge_d3_update(pdev);
|
||||
|
||||
pm_runtime_resume(dev);
|
||||
|
||||
@ -1551,11 +1547,10 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
||||
if (a == &dev_attr_boot_vga.attr)
|
||||
if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
|
||||
return 0;
|
||||
if (a == &dev_attr_boot_vga.attr && pci_is_vga(pdev))
|
||||
return a->mode;
|
||||
|
||||
return a->mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute *pci_dev_hp_attrs[] = {
|
||||
|
@ -534,7 +534,7 @@ u8 pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
|
||||
|
||||
pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
|
||||
|
||||
pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f);
|
||||
pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & PCI_HEADER_TYPE_MASK);
|
||||
if (pos)
|
||||
pos = __pci_find_next_cap(bus, devfn, pos, cap);
|
||||
|
||||
@ -732,15 +732,18 @@ u16 pci_find_vsec_capability(struct pci_dev *dev, u16 vendor, int cap)
|
||||
{
|
||||
u16 vsec = 0;
|
||||
u32 header;
|
||||
int ret;
|
||||
|
||||
if (vendor != dev->vendor)
|
||||
return 0;
|
||||
|
||||
while ((vsec = pci_find_next_ext_capability(dev, vsec,
|
||||
PCI_EXT_CAP_ID_VNDR))) {
|
||||
if (pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER,
|
||||
&header) == PCIBIOS_SUCCESSFUL &&
|
||||
PCI_VNDR_HEADER_ID(header) == cap)
|
||||
ret = pci_read_config_dword(dev, vsec + PCI_VNDR_HEADER, &header);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
continue;
|
||||
|
||||
if (PCI_VNDR_HEADER_ID(header) == cap)
|
||||
return vsec;
|
||||
}
|
||||
|
||||
@ -1775,8 +1778,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
|
||||
return;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);
|
||||
|
||||
for (i = 0; i < nbars; i++, pos += 8) {
|
||||
struct resource *res;
|
||||
@ -1787,7 +1789,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev)
|
||||
res = pdev->resource + bar_idx;
|
||||
size = pci_rebar_bytes_to_size(resource_size(res));
|
||||
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
|
||||
ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
|
||||
pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
|
||||
}
|
||||
}
|
||||
@ -3228,7 +3230,7 @@ void pci_pm_init(struct pci_dev *dev)
|
||||
(pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D3hot) ? " D3hot" : "",
|
||||
(pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
|
||||
dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
|
||||
dev->pme_support = FIELD_GET(PCI_PM_CAP_PME_MASK, pmc);
|
||||
dev->pme_poll = true;
|
||||
/*
|
||||
* Make device's PM flags reflect the wake-up capability, but
|
||||
@ -3299,20 +3301,20 @@ static int pci_ea_read(struct pci_dev *dev, int offset)
|
||||
ent_offset += 4;
|
||||
|
||||
/* Entry size field indicates DWORDs after 1st */
|
||||
ent_size = ((dw0 & PCI_EA_ES) + 1) << 2;
|
||||
ent_size = (FIELD_GET(PCI_EA_ES, dw0) + 1) << 2;
|
||||
|
||||
if (!(dw0 & PCI_EA_ENABLE)) /* Entry not enabled */
|
||||
goto out;
|
||||
|
||||
bei = (dw0 & PCI_EA_BEI) >> 4;
|
||||
prop = (dw0 & PCI_EA_PP) >> 8;
|
||||
bei = FIELD_GET(PCI_EA_BEI, dw0);
|
||||
prop = FIELD_GET(PCI_EA_PP, dw0);
|
||||
|
||||
/*
|
||||
* If the Property is in the reserved range, try the Secondary
|
||||
* Property instead.
|
||||
*/
|
||||
if (prop > PCI_EA_P_BRIDGE_IO && prop < PCI_EA_P_MEM_RESERVED)
|
||||
prop = (dw0 & PCI_EA_SP) >> 16;
|
||||
prop = FIELD_GET(PCI_EA_SP, dw0);
|
||||
if (prop > PCI_EA_P_BRIDGE_IO)
|
||||
goto out;
|
||||
|
||||
@ -3719,14 +3721,13 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar)
|
||||
return -ENOTSUPP;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
nbars = (ctrl & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
nbars = FIELD_GET(PCI_REBAR_CTRL_NBAR_MASK, ctrl);
|
||||
|
||||
for (i = 0; i < nbars; i++, pos += 8) {
|
||||
int bar_idx;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
bar_idx = ctrl & PCI_REBAR_CTRL_BAR_IDX;
|
||||
bar_idx = FIELD_GET(PCI_REBAR_CTRL_BAR_IDX, ctrl);
|
||||
if (bar_idx == bar)
|
||||
return pos;
|
||||
}
|
||||
@ -3752,14 +3753,14 @@ u32 pci_rebar_get_possible_sizes(struct pci_dev *pdev, int bar)
|
||||
return 0;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CAP, &cap);
|
||||
cap &= PCI_REBAR_CAP_SIZES;
|
||||
cap = FIELD_GET(PCI_REBAR_CAP_SIZES, cap);
|
||||
|
||||
/* Sapphire RX 5600 XT Pulse has an invalid cap dword for BAR 0 */
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x731f &&
|
||||
bar == 0 && cap == 0x7000)
|
||||
cap = 0x3f000;
|
||||
bar == 0 && cap == 0x700)
|
||||
return 0x3f00;
|
||||
|
||||
return cap >> 4;
|
||||
return cap;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_rebar_get_possible_sizes);
|
||||
|
||||
@ -3781,7 +3782,7 @@ int pci_rebar_get_current_size(struct pci_dev *pdev, int bar)
|
||||
return pos;
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
return (ctrl & PCI_REBAR_CTRL_BAR_SIZE) >> PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
return FIELD_GET(PCI_REBAR_CTRL_BAR_SIZE, ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3804,7 +3805,7 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
|
||||
|
||||
pci_read_config_dword(pdev, pos + PCI_REBAR_CTRL, &ctrl);
|
||||
ctrl &= ~PCI_REBAR_CTRL_BAR_SIZE;
|
||||
ctrl |= size << PCI_REBAR_CTRL_BAR_SHIFT;
|
||||
ctrl |= FIELD_PREP(PCI_REBAR_CTRL_BAR_SIZE, size);
|
||||
pci_write_config_dword(pdev, pos + PCI_REBAR_CTRL, ctrl);
|
||||
return 0;
|
||||
}
|
||||
@ -6042,7 +6043,7 @@ int pcix_get_max_mmrbc(struct pci_dev *dev)
|
||||
if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
return 512 << ((stat & PCI_X_STATUS_MAX_READ) >> 21);
|
||||
return 512 << FIELD_GET(PCI_X_STATUS_MAX_READ, stat);
|
||||
}
|
||||
EXPORT_SYMBOL(pcix_get_max_mmrbc);
|
||||
|
||||
@ -6065,7 +6066,7 @@ int pcix_get_mmrbc(struct pci_dev *dev)
|
||||
if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd))
|
||||
return -EINVAL;
|
||||
|
||||
return 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);
|
||||
return 512 << FIELD_GET(PCI_X_CMD_MAX_READ, cmd);
|
||||
}
|
||||
EXPORT_SYMBOL(pcix_get_mmrbc);
|
||||
|
||||
@ -6096,19 +6097,19 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
|
||||
if (pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat))
|
||||
return -EINVAL;
|
||||
|
||||
if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)
|
||||
if (v > FIELD_GET(PCI_X_STATUS_MAX_READ, stat))
|
||||
return -E2BIG;
|
||||
|
||||
if (pci_read_config_word(dev, cap + PCI_X_CMD, &cmd))
|
||||
return -EINVAL;
|
||||
|
||||
o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
|
||||
o = FIELD_GET(PCI_X_CMD_MAX_READ, cmd);
|
||||
if (o != v) {
|
||||
if (v > o && (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
|
||||
return -EIO;
|
||||
|
||||
cmd &= ~PCI_X_CMD_MAX_READ;
|
||||
cmd |= v << 2;
|
||||
cmd |= FIELD_PREP(PCI_X_CMD_MAX_READ, v);
|
||||
if (pci_write_config_word(dev, cap + PCI_X_CMD, cmd))
|
||||
return -EIO;
|
||||
}
|
||||
@ -6128,7 +6129,7 @@ int pcie_get_readrq(struct pci_dev *dev)
|
||||
|
||||
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
|
||||
|
||||
return 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
|
||||
return 128 << FIELD_GET(PCI_EXP_DEVCTL_READRQ, ctl);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_get_readrq);
|
||||
|
||||
@ -6161,7 +6162,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
|
||||
rq = mps;
|
||||
}
|
||||
|
||||
v = (ffs(rq) - 8) << 12;
|
||||
v = FIELD_PREP(PCI_EXP_DEVCTL_READRQ, ffs(rq) - 8);
|
||||
|
||||
if (bridge->no_inc_mrrs) {
|
||||
int max_mrrs = pcie_get_readrq(dev);
|
||||
@ -6191,7 +6192,7 @@ int pcie_get_mps(struct pci_dev *dev)
|
||||
|
||||
pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl);
|
||||
|
||||
return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
|
||||
return 128 << FIELD_GET(PCI_EXP_DEVCTL_PAYLOAD, ctl);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_get_mps);
|
||||
|
||||
@ -6214,7 +6215,7 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
|
||||
v = ffs(mps) - 8;
|
||||
if (v > dev->pcie_mpss)
|
||||
return -EINVAL;
|
||||
v <<= 5;
|
||||
v = FIELD_PREP(PCI_EXP_DEVCTL_PAYLOAD, v);
|
||||
|
||||
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_PAYLOAD, v);
|
||||
@ -6256,9 +6257,9 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
|
||||
while (dev) {
|
||||
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
|
||||
|
||||
next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
|
||||
next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
|
||||
PCI_EXP_LNKSTA_NLW_SHIFT;
|
||||
next_speed = pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS,
|
||||
lnksta)];
|
||||
next_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
|
||||
|
||||
next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
|
||||
|
||||
@ -6330,7 +6331,7 @@ enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev)
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
|
||||
if (lnkcap)
|
||||
return (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
|
||||
return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap);
|
||||
|
||||
return PCIE_LNK_WIDTH_UNKNOWN;
|
||||
}
|
||||
|
@ -13,6 +13,9 @@
|
||||
|
||||
#define PCIE_LINK_RETRAIN_TIMEOUT_MS 1000
|
||||
|
||||
/* Power stable to PERST# inactive from PCIe card Electromechanical Spec */
|
||||
#define PCIE_T_PVPERL_MS 100
|
||||
|
||||
/*
|
||||
* PCIe r6.0, sec 5.3.3.2.1 <PME Synchronization>
|
||||
* Recommends 1ms to 10ms timeout to check L2 ready.
|
||||
|
@ -1224,6 +1224,28 @@ static irqreturn_t aer_irq(int irq, void *context)
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static void aer_enable_irq(struct pci_dev *pdev)
|
||||
{
|
||||
int aer = pdev->aer_cap;
|
||||
u32 reg32;
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
static void aer_disable_irq(struct pci_dev *pdev)
|
||||
{
|
||||
int aer = pdev->aer_cap;
|
||||
u32 reg32;
|
||||
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
|
||||
/**
|
||||
* aer_enable_rootport - enable Root Port's interrupts when receiving messages
|
||||
* @rpc: pointer to a Root Port data structure
|
||||
@ -1253,10 +1275,7 @@ static void aer_enable_rootport(struct aer_rpc *rpc)
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, ®32);
|
||||
pci_write_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS, reg32);
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
aer_enable_irq(pdev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1271,10 +1290,7 @@ static void aer_disable_rootport(struct aer_rpc *rpc)
|
||||
int aer = pdev->aer_cap;
|
||||
u32 reg32;
|
||||
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(pdev, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
aer_disable_irq(pdev);
|
||||
|
||||
/* Clear Root's error status reg */
|
||||
pci_read_config_dword(pdev, aer + PCI_ERR_ROOT_STATUS, ®32);
|
||||
@ -1369,12 +1385,8 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
||||
*/
|
||||
aer = root ? root->aer_cap : 0;
|
||||
|
||||
if ((host->native_aer || pcie_ports_native) && aer) {
|
||||
/* Disable Root's interrupt in response to error messages */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
}
|
||||
if ((host->native_aer || pcie_ports_native) && aer)
|
||||
aer_disable_irq(root);
|
||||
|
||||
if (type == PCI_EXP_TYPE_RC_EC || type == PCI_EXP_TYPE_RC_END) {
|
||||
rc = pcie_reset_flr(dev, PCI_RESET_DO_RESET);
|
||||
@ -1393,10 +1405,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_STATUS, ®32);
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_STATUS, reg32);
|
||||
|
||||
/* Enable Root Port's interrupt in response to error messages */
|
||||
pci_read_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, ®32);
|
||||
reg32 |= ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(root, aer + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
aer_enable_irq(root);
|
||||
}
|
||||
|
||||
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
|
||||
|
@ -7,7 +7,9 @@
|
||||
* Copyright (C) Shaohua Li (shaohua.li@intel.com)
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -16,9 +18,10 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include "../pci.h"
|
||||
|
||||
#ifdef MODULE_PARAM_PREFIX
|
||||
@ -267,10 +270,10 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
||||
/* Convert L0s latency encoding to ns */
|
||||
static u32 calc_l0s_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L0SEL) >> 12;
|
||||
u32 encoding = FIELD_GET(PCI_EXP_LNKCAP_L0SEL, lnkcap);
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (5 * 1000); /* > 4us */
|
||||
return 5 * NSEC_PER_USEC; /* > 4us */
|
||||
return (64 << encoding);
|
||||
}
|
||||
|
||||
@ -278,26 +281,26 @@ static u32 calc_l0s_latency(u32 lnkcap)
|
||||
static u32 calc_l0s_acceptable(u32 encoding)
|
||||
{
|
||||
if (encoding == 0x7)
|
||||
return -1U;
|
||||
return U32_MAX;
|
||||
return (64 << encoding);
|
||||
}
|
||||
|
||||
/* Convert L1 latency encoding to ns */
|
||||
static u32 calc_l1_latency(u32 lnkcap)
|
||||
{
|
||||
u32 encoding = (lnkcap & PCI_EXP_LNKCAP_L1EL) >> 15;
|
||||
u32 encoding = FIELD_GET(PCI_EXP_LNKCAP_L1EL, lnkcap);
|
||||
|
||||
if (encoding == 0x7)
|
||||
return (65 * 1000); /* > 64us */
|
||||
return (1000 << encoding);
|
||||
return 65 * NSEC_PER_USEC; /* > 64us */
|
||||
return NSEC_PER_USEC << encoding;
|
||||
}
|
||||
|
||||
/* Convert L1 acceptable latency encoding to ns */
|
||||
static u32 calc_l1_acceptable(u32 encoding)
|
||||
{
|
||||
if (encoding == 0x7)
|
||||
return -1U;
|
||||
return (1000 << encoding);
|
||||
return U32_MAX;
|
||||
return NSEC_PER_USEC << encoding;
|
||||
}
|
||||
|
||||
/* Convert L1SS T_pwr encoding to usec */
|
||||
@ -325,33 +328,33 @@ static u32 calc_l12_pwron(struct pci_dev *pdev, u32 scale, u32 val)
|
||||
*/
|
||||
static void encode_l12_threshold(u32 threshold_us, u32 *scale, u32 *value)
|
||||
{
|
||||
u64 threshold_ns = (u64) threshold_us * 1000;
|
||||
u64 threshold_ns = (u64)threshold_us * NSEC_PER_USEC;
|
||||
|
||||
/*
|
||||
* LTR_L1.2_THRESHOLD_Value ("value") is a 10-bit field with max
|
||||
* value of 0x3ff.
|
||||
*/
|
||||
if (threshold_ns <= 0x3ff * 1) {
|
||||
if (threshold_ns <= 1 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 0; /* Value times 1ns */
|
||||
*value = threshold_ns;
|
||||
} else if (threshold_ns <= 0x3ff * 32) {
|
||||
} else if (threshold_ns <= 32 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 1; /* Value times 32ns */
|
||||
*value = roundup(threshold_ns, 32) / 32;
|
||||
} else if (threshold_ns <= 0x3ff * 1024) {
|
||||
} else if (threshold_ns <= 1024 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 2; /* Value times 1024ns */
|
||||
*value = roundup(threshold_ns, 1024) / 1024;
|
||||
} else if (threshold_ns <= 0x3ff * 32768) {
|
||||
} else if (threshold_ns <= 32768 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 3; /* Value times 32768ns */
|
||||
*value = roundup(threshold_ns, 32768) / 32768;
|
||||
} else if (threshold_ns <= 0x3ff * 1048576) {
|
||||
} else if (threshold_ns <= 1048576 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 4; /* Value times 1048576ns */
|
||||
*value = roundup(threshold_ns, 1048576) / 1048576;
|
||||
} else if (threshold_ns <= 0x3ff * (u64) 33554432) {
|
||||
} else if (threshold_ns <= (u64)33554432 * FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE)) {
|
||||
*scale = 5; /* Value times 33554432ns */
|
||||
*value = roundup(threshold_ns, 33554432) / 33554432;
|
||||
} else {
|
||||
*scale = 5;
|
||||
*value = 0x3ff; /* Max representable value */
|
||||
*value = FIELD_MAX(PCI_L1SS_CTL1_LTR_L12_TH_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,11 +374,11 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
|
||||
link = endpoint->bus->self->link_state;
|
||||
|
||||
/* Calculate endpoint L0s acceptable latency */
|
||||
encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L0S) >> 6;
|
||||
encoding = FIELD_GET(PCI_EXP_DEVCAP_L0S, endpoint->devcap);
|
||||
acceptable_l0s = calc_l0s_acceptable(encoding);
|
||||
|
||||
/* Calculate endpoint L1 acceptable latency */
|
||||
encoding = (endpoint->devcap & PCI_EXP_DEVCAP_L1) >> 9;
|
||||
encoding = FIELD_GET(PCI_EXP_DEVCAP_L1, endpoint->devcap);
|
||||
acceptable_l1 = calc_l1_acceptable(encoding);
|
||||
|
||||
while (link) {
|
||||
@ -417,7 +420,7 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint)
|
||||
if ((link->aspm_capable & ASPM_STATE_L1) &&
|
||||
(latency + l1_switch_latency > acceptable_l1))
|
||||
link->aspm_capable &= ~ASPM_STATE_L1;
|
||||
l1_switch_latency += 1000;
|
||||
l1_switch_latency += NSEC_PER_USEC;
|
||||
|
||||
link = link->parent;
|
||||
}
|
||||
@ -446,22 +449,24 @@ static void aspm_calc_l12_info(struct pcie_link_state *link,
|
||||
u32 pl1_2_enables, cl1_2_enables;
|
||||
|
||||
/* Choose the greater of the two Port Common_Mode_Restore_Times */
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_CM_RESTORE_TIME) >> 8;
|
||||
val1 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, parent_l1ss_cap);
|
||||
val2 = FIELD_GET(PCI_L1SS_CAP_CM_RESTORE_TIME, child_l1ss_cap);
|
||||
t_common_mode = max(val1, val2);
|
||||
|
||||
/* Choose the greater of the two Port T_POWER_ON times */
|
||||
val1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale1 = (parent_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_VALUE) >> 19;
|
||||
scale2 = (child_l1ss_cap & PCI_L1SS_CAP_P_PWR_ON_SCALE) >> 16;
|
||||
val1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, parent_l1ss_cap);
|
||||
scale1 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, parent_l1ss_cap);
|
||||
val2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_VALUE, child_l1ss_cap);
|
||||
scale2 = FIELD_GET(PCI_L1SS_CAP_P_PWR_ON_SCALE, child_l1ss_cap);
|
||||
|
||||
if (calc_l12_pwron(parent, scale1, val1) >
|
||||
calc_l12_pwron(child, scale2, val2)) {
|
||||
ctl2 |= scale1 | (val1 << 3);
|
||||
ctl2 |= FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_SCALE, scale1) |
|
||||
FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_VALUE, val1);
|
||||
t_power_on = calc_l12_pwron(parent, scale1, val1);
|
||||
} else {
|
||||
ctl2 |= scale2 | (val2 << 3);
|
||||
ctl2 |= FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_SCALE, scale2) |
|
||||
FIELD_PREP(PCI_L1SS_CTL2_T_PWR_ON_VALUE, val2);
|
||||
t_power_on = calc_l12_pwron(child, scale2, val2);
|
||||
}
|
||||
|
||||
@ -477,7 +482,9 @@ static void aspm_calc_l12_info(struct pcie_link_state *link,
|
||||
*/
|
||||
l1_2_threshold = 2 + 4 + t_common_mode + t_power_on;
|
||||
encode_l12_threshold(l1_2_threshold, &scale, &value);
|
||||
ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
|
||||
ctl1 |= FIELD_PREP(PCI_L1SS_CTL1_CM_RESTORE_TIME, t_common_mode) |
|
||||
FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_VALUE, value) |
|
||||
FIELD_PREP(PCI_L1SS_CTL1_LTR_L12_TH_SCALE, scale);
|
||||
|
||||
/* Some broken devices only support dword access to L1 SS */
|
||||
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
|
||||
@ -689,10 +696,10 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state)
|
||||
* in pcie_config_aspm_link().
|
||||
*/
|
||||
if (enable_req & (ASPM_STATE_L1_1 | ASPM_STATE_L1_2)) {
|
||||
pcie_capability_clear_and_set_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1, 0);
|
||||
pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1, 0);
|
||||
pcie_capability_clear_word(child, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1);
|
||||
pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPM_L1);
|
||||
}
|
||||
|
||||
val = 0;
|
||||
@ -1059,7 +1066,8 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
|
||||
if (state & PCIE_LINK_STATE_L0S)
|
||||
link->aspm_disable |= ASPM_STATE_L0S;
|
||||
if (state & PCIE_LINK_STATE_L1)
|
||||
link->aspm_disable |= ASPM_STATE_L1;
|
||||
/* L1 PM substates require L1 */
|
||||
link->aspm_disable |= ASPM_STATE_L1 | ASPM_STATE_L1SS;
|
||||
if (state & PCIE_LINK_STATE_L1_1)
|
||||
link->aspm_disable |= ASPM_STATE_L1_1;
|
||||
if (state & PCIE_LINK_STATE_L1_2)
|
||||
@ -1247,6 +1255,8 @@ static ssize_t aspm_attr_store_common(struct device *dev,
|
||||
link->aspm_disable &= ~ASPM_STATE_L1;
|
||||
} else {
|
||||
link->aspm_disable |= state;
|
||||
if (state & ASPM_STATE_L1)
|
||||
link->aspm_disable |= ASPM_STATE_L1SS;
|
||||
}
|
||||
|
||||
pcie_config_aspm_link(link, policy_to_aspm_state(link));
|
||||
@ -1361,10 +1371,10 @@ static int __init pcie_aspm_disable(char *str)
|
||||
aspm_policy = POLICY_DEFAULT;
|
||||
aspm_disabled = 1;
|
||||
aspm_support_enabled = false;
|
||||
printk(KERN_INFO "PCIe ASPM is disabled\n");
|
||||
pr_info("PCIe ASPM is disabled\n");
|
||||
} else if (!strcmp(str, "force")) {
|
||||
aspm_force = 1;
|
||||
printk(KERN_INFO "PCIe ASPM is forcibly enabled\n");
|
||||
pr_info("PCIe ASPM is forcibly enabled\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define dev_fmt(fmt) "DPC: " fmt
|
||||
|
||||
#include <linux/aer.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
@ -17,6 +18,9 @@
|
||||
#include "portdrv.h"
|
||||
#include "../pci.h"
|
||||
|
||||
#define PCI_EXP_DPC_CTL_EN_MASK (PCI_EXP_DPC_CTL_EN_FATAL | \
|
||||
PCI_EXP_DPC_CTL_EN_NONFATAL)
|
||||
|
||||
static const char * const rp_pio_error_string[] = {
|
||||
"Configuration Request received UR Completion", /* Bit Position 0 */
|
||||
"Configuration Request received CA Completion", /* Bit Position 1 */
|
||||
@ -202,7 +206,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev)
|
||||
|
||||
/* Get First Error Pointer */
|
||||
pci_read_config_word(pdev, cap + PCI_EXP_DPC_STATUS, &dpc_status);
|
||||
first_error = (dpc_status & 0x1f00) >> 8;
|
||||
first_error = FIELD_GET(PCI_EXP_DPC_RP_PIO_FEP, dpc_status);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rp_pio_error_string); i++) {
|
||||
if ((status & ~mask) & (1 << i))
|
||||
@ -270,20 +274,27 @@ void dpc_process_error(struct pci_dev *pdev)
|
||||
pci_info(pdev, "containment event, status:%#06x source:%#06x\n",
|
||||
status, source);
|
||||
|
||||
reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN) >> 1;
|
||||
ext_reason = (status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT) >> 5;
|
||||
reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN;
|
||||
ext_reason = status & PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT;
|
||||
pci_warn(pdev, "%s detected\n",
|
||||
(reason == 0) ? "unmasked uncorrectable error" :
|
||||
(reason == 1) ? "ERR_NONFATAL" :
|
||||
(reason == 2) ? "ERR_FATAL" :
|
||||
(ext_reason == 0) ? "RP PIO error" :
|
||||
(ext_reason == 1) ? "software trigger" :
|
||||
"reserved error");
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR) ?
|
||||
"unmasked uncorrectable error" :
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE) ?
|
||||
"ERR_NONFATAL" :
|
||||
(reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE) ?
|
||||
"ERR_FATAL" :
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO) ?
|
||||
"RP PIO error" :
|
||||
(ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER) ?
|
||||
"software trigger" :
|
||||
"reserved error");
|
||||
|
||||
/* show RP PIO error detail information */
|
||||
if (pdev->dpc_rp_extensions && reason == 3 && ext_reason == 0)
|
||||
if (pdev->dpc_rp_extensions &&
|
||||
reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT &&
|
||||
ext_reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO)
|
||||
dpc_process_rp_pio_error(pdev);
|
||||
else if (reason == 0 &&
|
||||
else if (reason == PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR &&
|
||||
dpc_get_aer_uncorrect_severity(pdev, &info) &&
|
||||
aer_get_device_error_info(pdev, &info)) {
|
||||
aer_print_error(pdev, &info);
|
||||
@ -338,7 +349,7 @@ void pci_dpc_init(struct pci_dev *pdev)
|
||||
/* Quirks may set dpc_rp_log_size if device or firmware is buggy */
|
||||
if (!pdev->dpc_rp_log_size) {
|
||||
pdev->dpc_rp_log_size =
|
||||
(cap & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8;
|
||||
FIELD_GET(PCI_EXP_DPC_RP_PIO_LOG_SIZE, cap);
|
||||
if (pdev->dpc_rp_log_size < 4 || pdev->dpc_rp_log_size > 9) {
|
||||
pci_err(pdev, "RP PIO log size %u is invalid\n",
|
||||
pdev->dpc_rp_log_size);
|
||||
@ -368,12 +379,13 @@ static int dpc_probe(struct pcie_device *dev)
|
||||
}
|
||||
|
||||
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CAP, &cap);
|
||||
|
||||
pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, &ctl);
|
||||
|
||||
ctl = (ctl & 0xfff4) | PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
|
||||
ctl &= ~PCI_EXP_DPC_CTL_EN_MASK;
|
||||
ctl |= PCI_EXP_DPC_CTL_EN_FATAL | PCI_EXP_DPC_CTL_INT_EN;
|
||||
pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_CTL, ctl);
|
||||
pci_info(pdev, "enabled with IRQ %d\n", dev->irq);
|
||||
|
||||
pci_info(pdev, "enabled with IRQ %d\n", dev->irq);
|
||||
pci_info(pdev, "error containment capabilities: Int Msg #%d, RPExt%c PoisonedTLP%c SwTrigger%c RP PIO Log %d, DL_ActiveErr%c\n",
|
||||
cap & PCI_EXP_DPC_IRQ, FLAG(cap, PCI_EXP_DPC_CAP_RP_EXT),
|
||||
FLAG(cap, PCI_EXP_DPC_CAP_POISONED_TLP),
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#define dev_fmt(fmt) "PME: " fmt
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
@ -235,7 +236,8 @@ static void pcie_pme_work_fn(struct work_struct *work)
|
||||
pcie_clear_root_pme_status(port);
|
||||
|
||||
spin_unlock_irq(&data->lock);
|
||||
pcie_pme_handle_request(port, rtsta & 0xffff);
|
||||
pcie_pme_handle_request(port,
|
||||
FIELD_GET(PCI_EXP_RTSTA_PME_RQ_ID, rtsta));
|
||||
spin_lock_irq(&data->lock);
|
||||
|
||||
continue;
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
@ -69,7 +70,7 @@ static int pcie_message_numbers(struct pci_dev *dev, int mask,
|
||||
if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP |
|
||||
PCIE_PORT_SERVICE_BWNOTIF)) {
|
||||
pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16);
|
||||
*pme = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
|
||||
*pme = FIELD_GET(PCI_EXP_FLAGS_IRQ, reg16);
|
||||
nvec = *pme + 1;
|
||||
}
|
||||
|
||||
@ -81,7 +82,7 @@ static int pcie_message_numbers(struct pci_dev *dev, int mask,
|
||||
if (pos) {
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS,
|
||||
®32);
|
||||
*aer = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
|
||||
*aer = FIELD_GET(PCI_ERR_ROOT_AER_IRQ, reg32);
|
||||
nvec = max(nvec, *aer + 1);
|
||||
}
|
||||
}
|
||||
@ -92,7 +93,7 @@ static int pcie_message_numbers(struct pci_dev *dev, int mask,
|
||||
if (pos) {
|
||||
pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP,
|
||||
®16);
|
||||
*dpc = reg16 & PCI_EXP_DPC_IRQ;
|
||||
*dpc = FIELD_GET(PCI_EXP_DPC_IRQ, reg16);
|
||||
nvec = max(nvec, *dpc + 1);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
@ -53,7 +54,7 @@ void pci_ptm_init(struct pci_dev *dev)
|
||||
pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_PTM, sizeof(u32));
|
||||
|
||||
pci_read_config_dword(dev, ptm + PCI_PTM_CAP, &cap);
|
||||
dev->ptm_granularity = (cap & PCI_PTM_GRANULARITY_MASK) >> 8;
|
||||
dev->ptm_granularity = FIELD_GET(PCI_PTM_GRANULARITY_MASK, cap);
|
||||
|
||||
/*
|
||||
* Per the spec recommendation (PCIe r6.0, sec 7.9.15.3), select the
|
||||
@ -146,7 +147,7 @@ static int __pci_enable_ptm(struct pci_dev *dev)
|
||||
|
||||
ctrl |= PCI_PTM_CTRL_ENABLE;
|
||||
ctrl &= ~PCI_PTM_GRANULARITY_MASK;
|
||||
ctrl |= dev->ptm_granularity << 8;
|
||||
ctrl |= FIELD_PREP(PCI_PTM_GRANULARITY_MASK, dev->ptm_granularity);
|
||||
if (dev->ptm_root)
|
||||
ctrl |= PCI_PTM_CTRL_ROOT;
|
||||
|
||||
|
@ -807,8 +807,8 @@ static void pci_set_bus_speed(struct pci_bus *bus)
|
||||
}
|
||||
|
||||
bus->max_bus_speed = max;
|
||||
bus->cur_bus_speed = pcix_bus_speed[
|
||||
(status & PCI_X_SSTATUS_FREQ) >> 6];
|
||||
bus->cur_bus_speed =
|
||||
pcix_bus_speed[FIELD_GET(PCI_X_SSTATUS_FREQ, status)];
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1217,8 +1217,8 @@ static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
|
||||
|
||||
offset = ea + PCI_EA_FIRST_ENT;
|
||||
pci_read_config_dword(dev, offset, &dw);
|
||||
ea_sec = dw & PCI_EA_SEC_BUS_MASK;
|
||||
ea_sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
|
||||
ea_sec = FIELD_GET(PCI_EA_SEC_BUS_MASK, dw);
|
||||
ea_sub = FIELD_GET(PCI_EA_SUB_BUS_MASK, dw);
|
||||
if (ea_sec == 0 || ea_sub < ea_sec)
|
||||
return false;
|
||||
|
||||
@ -1652,15 +1652,15 @@ static void pci_set_removable(struct pci_dev *dev)
|
||||
static bool pci_ext_cfg_is_aliased(struct pci_dev *dev)
|
||||
{
|
||||
#ifdef CONFIG_PCI_QUIRKS
|
||||
int pos;
|
||||
int pos, ret;
|
||||
u32 header, tmp;
|
||||
|
||||
pci_read_config_dword(dev, PCI_VENDOR_ID, &header);
|
||||
|
||||
for (pos = PCI_CFG_SPACE_SIZE;
|
||||
pos < PCI_CFG_SPACE_EXP_SIZE; pos += PCI_CFG_SPACE_SIZE) {
|
||||
if (pci_read_config_dword(dev, pos, &tmp) != PCIBIOS_SUCCESSFUL
|
||||
|| header != tmp)
|
||||
ret = pci_read_config_dword(dev, pos, &tmp);
|
||||
if ((ret != PCIBIOS_SUCCESSFUL) || (header != tmp))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -690,7 +690,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
|
||||
/*
|
||||
* In the AMD NL platform, this device ([1022:7912]) has a class code of
|
||||
* PCI_CLASS_SERIAL_USB_XHCI (0x0c0330), which means the xhci driver will
|
||||
* claim it.
|
||||
* claim it. The same applies on the VanGogh platform device ([1022:163a]).
|
||||
*
|
||||
* But the dwc3 driver is a more specific driver for this device, and we'd
|
||||
* prefer to use it instead of xhci. To prevent xhci from claiming the
|
||||
@ -698,7 +698,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
|
||||
* defines as "USB device (not host controller)". The dwc3 driver can then
|
||||
* claim it based on its Vendor and Device ID.
|
||||
*/
|
||||
static void quirk_amd_nl_class(struct pci_dev *pdev)
|
||||
static void quirk_amd_dwc_class(struct pci_dev *pdev)
|
||||
{
|
||||
u32 class = pdev->class;
|
||||
|
||||
@ -708,7 +708,9 @@ static void quirk_amd_nl_class(struct pci_dev *pdev)
|
||||
class, pdev->class);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB,
|
||||
quirk_amd_nl_class);
|
||||
quirk_amd_dwc_class);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VANGOGH_USB,
|
||||
quirk_amd_dwc_class);
|
||||
|
||||
/*
|
||||
* Synopsys USB 3.x host HAPS platform has a class code of
|
||||
@ -1844,8 +1846,8 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
|
||||
|
||||
/* Update pdev accordingly */
|
||||
pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr);
|
||||
pdev->hdr_type = hdr & 0x7f;
|
||||
pdev->multifunction = !!(hdr & 0x80);
|
||||
pdev->hdr_type = hdr & PCI_HEADER_TYPE_MASK;
|
||||
pdev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class);
|
||||
pdev->class = class >> 8;
|
||||
@ -4553,9 +4555,9 @@ static void quirk_disable_root_port_attributes(struct pci_dev *pdev)
|
||||
|
||||
pci_info(root_port, "Disabling No Snoop/Relaxed Ordering Attributes to avoid PCIe Completion erratum in %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
pcie_capability_clear_and_set_word(root_port, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_RELAX_EN |
|
||||
PCI_EXP_DEVCTL_NOSNOOP_EN, 0);
|
||||
pcie_capability_clear_word(root_port, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_RELAX_EN |
|
||||
PCI_EXP_DEVCTL_NOSNOOP_EN);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5383,7 +5385,7 @@ int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
|
||||
*/
|
||||
static void quirk_intel_qat_vf_cap(struct pci_dev *pdev)
|
||||
{
|
||||
int pos, i = 0;
|
||||
int pos, i = 0, ret;
|
||||
u8 next_cap;
|
||||
u16 reg16, *cap;
|
||||
struct pci_cap_saved_state *state;
|
||||
@ -5429,8 +5431,8 @@ static void quirk_intel_qat_vf_cap(struct pci_dev *pdev)
|
||||
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
|
||||
|
||||
pdev->cfg_size = PCI_CFG_SPACE_EXP_SIZE;
|
||||
if (pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &status) !=
|
||||
PCIBIOS_SUCCESSFUL || (status == 0xffffffff))
|
||||
ret = pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &status);
|
||||
if ((ret != PCIBIOS_SUCCESSFUL) || (PCI_POSSIBLE_ERROR(status)))
|
||||
pdev->cfg_size = PCI_CFG_SPACE_SIZE;
|
||||
|
||||
if (pci_find_saved_cap(pdev, PCI_CAP_ID_EXP))
|
||||
@ -5507,6 +5509,12 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0420, quirk_no_ext_tags);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags);
|
||||
|
||||
#ifdef CONFIG_PCI_ATS
|
||||
static void quirk_no_ats(struct pci_dev *pdev)
|
||||
{
|
||||
pci_info(pdev, "disabling ATS\n");
|
||||
pdev->ats_cap = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some devices require additional driver setup to enable ATS. Don't use
|
||||
* ATS for those devices as ATS will be enabled before the driver has had a
|
||||
@ -5520,14 +5528,10 @@ static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
|
||||
(pdev->subsystem_device == 0xce19 ||
|
||||
pdev->subsystem_device == 0xcc10 ||
|
||||
pdev->subsystem_device == 0xcc08))
|
||||
goto no_ats;
|
||||
else
|
||||
return;
|
||||
quirk_no_ats(pdev);
|
||||
} else {
|
||||
quirk_no_ats(pdev);
|
||||
}
|
||||
|
||||
no_ats:
|
||||
pci_info(pdev, "disabling ATS\n");
|
||||
pdev->ats_cap = 0;
|
||||
}
|
||||
|
||||
/* AMD Stoney platform GPU */
|
||||
@ -5550,6 +5554,25 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7347, quirk_amd_harvest_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x734f, quirk_amd_harvest_no_ats);
|
||||
/* AMD Raven platform iGPU */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
|
||||
|
||||
/*
|
||||
* Intel IPU E2000 revisions before C0 implement incorrect endianness
|
||||
* in ATS Invalidate Request message body. Disable ATS for those devices.
|
||||
*/
|
||||
static void quirk_intel_e2000_no_ats(struct pci_dev *pdev)
|
||||
{
|
||||
if (pdev->revision < 0x20)
|
||||
quirk_no_ats(pdev);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1451, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1452, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1453, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1454, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1455, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1459, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145a, quirk_intel_e2000_no_ats);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145c, quirk_intel_e2000_no_ats);
|
||||
#endif /* CONFIG_PCI_ATS */
|
||||
|
||||
/* Freescale PCIe doesn't support MSI in RC mode */
|
||||
@ -5666,7 +5689,7 @@ static void quirk_nvidia_hda(struct pci_dev *gpu)
|
||||
|
||||
/* The GPU becomes a multi-function device when the HDA is enabled */
|
||||
pci_read_config_byte(gpu, PCI_HEADER_TYPE, &hdr_type);
|
||||
gpu->multifunction = !!(hdr_type & 0x80);
|
||||
gpu->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
|
||||
PCI_BASE_CLASS_DISPLAY, 16, quirk_nvidia_hda);
|
||||
@ -6154,7 +6177,7 @@ static void dpc_log_size(struct pci_dev *dev)
|
||||
if (!(val & PCI_EXP_DPC_CAP_RP_EXT))
|
||||
return;
|
||||
|
||||
if (!((val & PCI_EXP_DPC_RP_PIO_LOG_SIZE) >> 8)) {
|
||||
if (FIELD_GET(PCI_EXP_DPC_RP_PIO_LOG_SIZE, val) == 0) {
|
||||
pci_info(dev, "Overriding RP PIO Log Size to 4\n");
|
||||
dev->dpc_rp_log_size = 4;
|
||||
}
|
||||
@ -6188,3 +6211,15 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5020, of_pci_make_dev_node);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_XILINX, 0x5021, of_pci_make_dev_node);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REDHAT, 0x0005, of_pci_make_dev_node);
|
||||
|
||||
/*
|
||||
* Devices known to require a longer delay before first config space access
|
||||
* after reset recovery or resume from D3cold:
|
||||
*
|
||||
* VideoPropulsion (aka Genroco) Torrent QN16e MPEG QAM Modulator
|
||||
*/
|
||||
static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev)
|
||||
{
|
||||
pdev->d3cold_delay = 1000;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec);
|
||||
|
@ -363,6 +363,37 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from)
|
||||
}
|
||||
EXPORT_SYMBOL(pci_get_class);
|
||||
|
||||
/**
|
||||
* pci_get_base_class - searching for a PCI device by matching against the base class code only
|
||||
* @class: search for a PCI device with this base class code
|
||||
* @from: Previous PCI device found in search, or %NULL for new search.
|
||||
*
|
||||
* Iterates through the list of known PCI devices. If a PCI device is found
|
||||
* with a matching base class code, the reference count to the device is
|
||||
* incremented. See pci_match_one_device() to figure out how does this works.
|
||||
* A new search is initiated by passing %NULL as the @from argument.
|
||||
* Otherwise if @from is not %NULL, searches continue from next device on the
|
||||
* global list. The reference count for @from is always decremented if it is
|
||||
* not %NULL.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to a matched PCI device, %NULL Otherwise.
|
||||
*/
|
||||
struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from)
|
||||
{
|
||||
struct pci_device_id id = {
|
||||
.vendor = PCI_ANY_ID,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.class_mask = 0xFF0000,
|
||||
.class = class << 16,
|
||||
};
|
||||
|
||||
return pci_get_dev_by_id(&id, from);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_get_base_class);
|
||||
|
||||
/**
|
||||
* pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
|
||||
* @ids: A pointer to a null terminated list of struct pci_device_id structures
|
||||
|
@ -2129,7 +2129,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
|
||||
pci_bus_dump_resources(bus);
|
||||
}
|
||||
|
||||
void __init pci_assign_unassigned_resources(void)
|
||||
void pci_assign_unassigned_resources(void)
|
||||
{
|
||||
struct pci_bus *root_bus;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Author: Alex Williamson <alex.williamson@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@ -201,9 +202,9 @@ static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos,
|
||||
/* Extended VC Count (not counting VC0) */
|
||||
evcc = cap1 & PCI_VC_CAP1_EVCC;
|
||||
/* Low Priority Extended VC Count (not counting VC0) */
|
||||
lpevcc = (cap1 & PCI_VC_CAP1_LPEVCC) >> 4;
|
||||
lpevcc = FIELD_GET(PCI_VC_CAP1_LPEVCC, cap1);
|
||||
/* Port Arbitration Table Entry Size (bits) */
|
||||
parb_size = 1 << ((cap1 & PCI_VC_CAP1_ARB_SIZE) >> 10);
|
||||
parb_size = 1 << FIELD_GET(PCI_VC_CAP1_ARB_SIZE, cap1);
|
||||
|
||||
/*
|
||||
* Port VC Control Register contains VC Arbitration Select, which
|
||||
@ -231,7 +232,7 @@ static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos,
|
||||
int vcarb_offset;
|
||||
|
||||
pci_read_config_dword(dev, pos + PCI_VC_PORT_CAP2, &cap2);
|
||||
vcarb_offset = ((cap2 & PCI_VC_CAP2_ARB_OFF) >> 24) * 16;
|
||||
vcarb_offset = FIELD_GET(PCI_VC_CAP2_ARB_OFF, cap2) * 16;
|
||||
|
||||
if (vcarb_offset) {
|
||||
int size, vcarb_phases = 0;
|
||||
@ -277,7 +278,7 @@ static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos,
|
||||
|
||||
pci_read_config_dword(dev, pos + PCI_VC_RES_CAP +
|
||||
(i * PCI_CAP_VC_PER_VC_SIZEOF), &cap);
|
||||
parb_offset = ((cap & PCI_VC_RES_CAP_ARB_OFF) >> 24) * 16;
|
||||
parb_offset = FIELD_GET(PCI_VC_RES_CAP_ARB_OFF, cap) * 16;
|
||||
if (parb_offset) {
|
||||
int size, parb_phases = 0;
|
||||
|
||||
|
@ -764,10 +764,6 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
|
||||
struct pci_dev *bridge;
|
||||
u16 cmd;
|
||||
|
||||
/* Only deal with VGA class devices */
|
||||
if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
|
||||
return false;
|
||||
|
||||
/* Allocate structure */
|
||||
vgadev = kzalloc(sizeof(struct vga_device), GFP_KERNEL);
|
||||
if (vgadev == NULL) {
|
||||
@ -1503,6 +1499,10 @@ static int pci_notify(struct notifier_block *nb, unsigned long action,
|
||||
|
||||
vgaarb_dbg(dev, "%s\n", __func__);
|
||||
|
||||
/* Only deal with VGA class devices */
|
||||
if (!pci_is_vga(pdev))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* For now, we're only interested in devices added and removed.
|
||||
* I didn't test this thing here, so someone needs to double check
|
||||
@ -1550,8 +1550,10 @@ static int __init vga_arb_device_init(void)
|
||||
pdev = NULL;
|
||||
while ((pdev =
|
||||
pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_ANY_ID, pdev)) != NULL)
|
||||
vga_arbiter_add_pci_device(pdev);
|
||||
PCI_ANY_ID, pdev)) != NULL) {
|
||||
if (pci_is_vga(pdev))
|
||||
vga_arbiter_add_pci_device(pdev);
|
||||
}
|
||||
|
||||
pr_info("loaded\n");
|
||||
return rc;
|
||||
|
@ -761,12 +761,14 @@ static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,
|
||||
static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
|
||||
{
|
||||
int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
|
||||
int rc;
|
||||
|
||||
if (pcix_cmd_reg == 0)
|
||||
return 0;
|
||||
|
||||
if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
|
||||
&ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
|
||||
rc = pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
|
||||
&ioa_cfg->saved_pcix_cmd_reg);
|
||||
if (rc != PCIBIOS_SUCCESSFUL) {
|
||||
dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");
|
||||
return -EIO;
|
||||
}
|
||||
@ -785,10 +787,12 @@ static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
|
||||
static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
|
||||
{
|
||||
int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
|
||||
int rc;
|
||||
|
||||
if (pcix_cmd_reg) {
|
||||
if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
|
||||
ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
|
||||
rc = pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
|
||||
ioa_cfg->saved_pcix_cmd_reg);
|
||||
if (rc != PCIBIOS_SUCCESSFUL) {
|
||||
dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -39,9 +39,6 @@ struct logic_pio_host_ops {
|
||||
|
||||
#ifdef CONFIG_INDIRECT_PIO
|
||||
u8 logic_inb(unsigned long addr);
|
||||
void logic_outb(u8 value, unsigned long addr);
|
||||
void logic_outw(u16 value, unsigned long addr);
|
||||
void logic_outl(u32 value, unsigned long addr);
|
||||
u16 logic_inw(unsigned long addr);
|
||||
u32 logic_inl(unsigned long addr);
|
||||
void logic_outb(u8 value, unsigned long addr);
|
||||
|
@ -713,6 +713,30 @@ static inline bool pci_is_bridge(struct pci_dev *dev)
|
||||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_is_vga - check if the PCI device is a VGA device
|
||||
*
|
||||
* The PCI Code and ID Assignment spec, r1.15, secs 1.4 and 1.1, define
|
||||
* VGA Base Class and Sub-Classes:
|
||||
*
|
||||
* 03 00 PCI_CLASS_DISPLAY_VGA VGA-compatible or 8514-compatible
|
||||
* 00 01 PCI_CLASS_NOT_DEFINED_VGA VGA-compatible (before Class Code)
|
||||
*
|
||||
* Return true if the PCI device is a VGA device and uses the legacy VGA
|
||||
* resources ([mem 0xa0000-0xbffff], [io 0x3b0-0x3bb], [io 0x3c0-0x3df] and
|
||||
* aliases).
|
||||
*/
|
||||
static inline bool pci_is_vga(struct pci_dev *pdev)
|
||||
{
|
||||
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
|
||||
return true;
|
||||
|
||||
if ((pdev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#define for_each_pci_bridge(dev, bus) \
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) \
|
||||
if (!pci_is_bridge(dev)) {} else
|
||||
@ -1181,6 +1205,8 @@ struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
|
||||
struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
|
||||
unsigned int devfn);
|
||||
struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
|
||||
struct pci_dev *pci_get_base_class(unsigned int class, struct pci_dev *from);
|
||||
|
||||
int pci_dev_present(const struct pci_device_id *ids);
|
||||
|
||||
int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
|
||||
@ -1950,6 +1976,9 @@ static inline struct pci_dev *pci_get_class(unsigned int class,
|
||||
struct pci_dev *from)
|
||||
{ return NULL; }
|
||||
|
||||
static inline struct pci_dev *pci_get_base_class(unsigned int class,
|
||||
struct pci_dev *from)
|
||||
{ return NULL; }
|
||||
|
||||
static inline int pci_dev_present(const struct pci_device_id *ids)
|
||||
{ return 0; }
|
||||
|
@ -582,6 +582,7 @@
|
||||
#define PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3 0x16fb
|
||||
#define PCI_DEVICE_ID_AMD_MI200_DF_F3 0x14d3
|
||||
#define PCI_DEVICE_ID_AMD_MI300_DF_F3 0x152b
|
||||
#define PCI_DEVICE_ID_AMD_VANGOGH_USB 0x163a
|
||||
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
|
||||
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
|
||||
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
|
||||
|
@ -80,6 +80,7 @@
|
||||
#define PCI_HEADER_TYPE_NORMAL 0
|
||||
#define PCI_HEADER_TYPE_BRIDGE 1
|
||||
#define PCI_HEADER_TYPE_CARDBUS 2
|
||||
#define PCI_HEADER_TYPE_MFD 0x80 /* Multi-Function Device (possible) */
|
||||
|
||||
#define PCI_BIST 0x0f /* 8 bits */
|
||||
#define PCI_BIST_CODE_MASK 0x0f /* Return result */
|
||||
@ -637,6 +638,7 @@
|
||||
#define PCI_EXP_RTCAP 0x1e /* Root Capabilities */
|
||||
#define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */
|
||||
#define PCI_EXP_RTSTA 0x20 /* Root Status */
|
||||
#define PCI_EXP_RTSTA_PME_RQ_ID 0x0000ffff /* PME Requester ID */
|
||||
#define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */
|
||||
#define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */
|
||||
/*
|
||||
@ -930,12 +932,13 @@
|
||||
|
||||
/* Process Address Space ID */
|
||||
#define PCI_PASID_CAP 0x04 /* PASID feature register */
|
||||
#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */
|
||||
#define PCI_PASID_CAP_PRIV 0x04 /* Privilege Mode Supported */
|
||||
#define PCI_PASID_CAP_EXEC 0x0002 /* Exec permissions Supported */
|
||||
#define PCI_PASID_CAP_PRIV 0x0004 /* Privilege Mode Supported */
|
||||
#define PCI_PASID_CAP_WIDTH 0x1f00
|
||||
#define PCI_PASID_CTRL 0x06 /* PASID control register */
|
||||
#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */
|
||||
#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */
|
||||
#define PCI_PASID_CTRL_PRIV 0x04 /* Privilege Mode Enable */
|
||||
#define PCI_PASID_CTRL_ENABLE 0x0001 /* Enable bit */
|
||||
#define PCI_PASID_CTRL_EXEC 0x0002 /* Exec permissions Enable */
|
||||
#define PCI_PASID_CTRL_PRIV 0x0004 /* Privilege Mode Enable */
|
||||
#define PCI_EXT_CAP_PASID_SIZEOF 8
|
||||
|
||||
/* Single Root I/O Virtualization */
|
||||
@ -975,6 +978,8 @@
|
||||
#define PCI_LTR_VALUE_MASK 0x000003ff
|
||||
#define PCI_LTR_SCALE_MASK 0x00001c00
|
||||
#define PCI_LTR_SCALE_SHIFT 10
|
||||
#define PCI_LTR_NOSNOOP_VALUE 0x03ff0000 /* Max No-Snoop Latency Value */
|
||||
#define PCI_LTR_NOSNOOP_SCALE 0x1c000000 /* Scale for Max Value */
|
||||
#define PCI_EXT_CAP_LTR_SIZEOF 8
|
||||
|
||||
/* Access Control Service */
|
||||
@ -1042,9 +1047,16 @@
|
||||
#define PCI_EXP_DPC_STATUS 0x08 /* DPC Status */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER 0x0001 /* Trigger Status */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN 0x0006 /* Trigger Reason */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_UNCOR 0x0000 /* Uncorrectable error */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_NFE 0x0002 /* Rcvd ERR_NONFATAL */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_FE 0x0004 /* Rcvd ERR_FATAL */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_IN_EXT 0x0006 /* Reason in Trig Reason Extension field */
|
||||
#define PCI_EXP_DPC_STATUS_INTERRUPT 0x0008 /* Interrupt Status */
|
||||
#define PCI_EXP_DPC_RP_BUSY 0x0010 /* Root Port Busy */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_EXT 0x0060 /* Trig Reason Extension */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_RP_PIO 0x0000 /* RP PIO error */
|
||||
#define PCI_EXP_DPC_STATUS_TRIGGER_RSN_SW_TRIGGER 0x0020 /* DPC SW Trigger bit */
|
||||
#define PCI_EXP_DPC_RP_PIO_FEP 0x1f00 /* RP PIO First Err Ptr */
|
||||
|
||||
#define PCI_EXP_DPC_SOURCE_ID 0x0A /* DPC Source Identifier */
|
||||
|
||||
@ -1088,6 +1100,8 @@
|
||||
#define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */
|
||||
#define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */
|
||||
#define PCI_L1SS_CTL2 0x0c /* Control 2 Register */
|
||||
#define PCI_L1SS_CTL2_T_PWR_ON_SCALE 0x00000003 /* T_POWER_ON Scale */
|
||||
#define PCI_L1SS_CTL2_T_PWR_ON_VALUE 0x000000f8 /* T_POWER_ON Value */
|
||||
|
||||
/* Designated Vendor-Specific (DVSEC, PCI_EXT_CAP_ID_DVSEC) */
|
||||
#define PCI_DVSEC_HEADER1 0x4 /* Designated Vendor-Specific Header1 */
|
||||
|
@ -1417,17 +1417,11 @@ static bool atpx_present(void)
|
||||
acpi_handle dhandle, atpx_handle;
|
||||
acpi_status status;
|
||||
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (dhandle) {
|
||||
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
pci_dev_put(pdev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
|
||||
while ((pdev = pci_get_base_class(PCI_BASE_CLASS_DISPLAY, pdev))) {
|
||||
if ((pdev->class != PCI_CLASS_DISPLAY_VGA << 8) &&
|
||||
(pdev->class != PCI_CLASS_DISPLAY_OTHER << 8))
|
||||
continue;
|
||||
|
||||
dhandle = ACPI_HANDLE(&pdev->dev);
|
||||
if (dhandle) {
|
||||
status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
|
||||
|
Loading…
Reference in New Issue
Block a user