pci-v5.6-changes
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAl40PWgUHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vwclA/+Id/7Uc5S0r7xgFQRr3lbn0hHcx7f oBgmm6kGl8bu77MDiY32WLmPsp9e4BlK2M765cKQL5n20y8CzJ+kthZM8tZEDba4 pnrZnWZ0A2xaBKzJqqYDtCqAeP97noCs4zBLo3JCA6jYCYI5bkvmdMQRlRjTUofO tkenGE+vexaJsLB7ghNskL3xGMueXLtLf/hXvaC6WGbSI9/zUmliHDL53DoKDPRo /9TGYDMwItZz+BhmBJz8hAL4naQIhIcDk2mz7CzWkY9xDhCJ1yeEwFvtvJwq0uM2 Nmtq1g6yCB3sjlx+bRzrioLnouflztK1PGRbNugrMkR5XM9HIFmNwaDrqpU11ffA LQabMpbS3RWH3hbh4LYVMW13hbO+ld7/NG8jMFce2LHBWaGj6YejUQGdifz6vGRk JnDOgP19v5gWw08ibwkdfYzznPfMXp5IzFdJQFKhK+ugGDSJ8VeXiQ/pWtzghl3z P/puRw0BiL7ob/FUmhwn4J1Ytml7PZE+cJVN2l4C/CwKxR583GRUDgSHNL7Dky+o GcH9Tmjt4hQMNYRP01PACUmFYJwDfB+zgQ64a+uJsQwl/j+yfMnc1t/kqdM6yC9J GgkqLp989G/a3n9w5IC1P8aDYiwRqABvAFzlP9OZcIMUwmWbrhH175Qf6skKYIhH q9RKcLVXZdRS3mc= =fQ0E -----END PGP SIGNATURE----- Merge tag 'pci-v5.6-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: "Resource management: - Improve resource assignment for hot-added nested bridges, e.g., Thunderbolt (Nicholas Johnson) Power management: - Optionally print config space of devices before suspend (Chen Yu) - Increase D3 delay for AMD Ryzen5/7 XHCI controllers (Daniel Drake) Virtualization: - Generalize DMA alias quirks (James Sewart) - Add DMA alias quirk for PLX PEX NTB (James Sewart) - Fix IOV memory leak (Navid Emamdoost) AER: - Log which device prevents error recovery (Yicong Yang) Peer-to-peer DMA: - Whitelist Intel SkyLake-E (Armen Baloyan) Broadcom iProc host bridge driver: - Apply PAXC quirk whether driver is built-in or module (Wei Liu) Broadcom STB host bridge driver: - Add Broadcom STB PCIe host controller driver (Jim Quinlan) Intel Gateway SoC host bridge driver: - Add driver for Intel Gateway SoC (Dilip Kota) Intel VMD host bridge driver: - Add support for DMA aliases on other buses (Jon Derrick) - Remove dma_map_ops overrides (Jon Derrick) - Remove now-unused X86_DEV_DMA_OPS (Christoph Hellwig) NVIDIA Tegra host bridge driver: - Fix Tegra30 afi_pex2_ctrl register offset (Marcel Ziswiler) Panasonic UniPhier host bridge driver: - Remove module code since driver can't be built as a module (Masahiro Yamada) Qualcomm host bridge driver: - Add support for SDM845 PCIe controller (Bjorn Andersson) TI Keystone host bridge driver: - Fix "num-viewport" DT property error handling (Kishon Vijay Abraham I) - Fix link training retries initiation (Yurii Monakov) - Fix outbound region mapping (Yurii Monakov) Misc: - Add Switchtec Gen4 support (Kelvin Cao) - Add Switchtec Intercomm Notify and Upstream Error Containment support (Logan Gunthorpe) - Use dma_set_mask_and_coherent() since Switchtec supports 64-bit addressing (Wesley Sheng)" * tag 'pci-v5.6-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (60 commits) PCI: Allow adjust_bridge_window() to shrink resource if necessary PCI: Set resource size directly in adjust_bridge_window() PCI: Rename extend_bridge_window() to adjust_bridge_window() PCI: Rename extend_bridge_window() parameter PCI: Consider alignment of hot-added bridges when assigning resources PCI: Remove local variable usage in pci_bus_distribute_available_resources() PCI: Pass size + alignment to pci_bus_distribute_available_resources() PCI: Rename variables PCI: vmd: Add two VMD Device IDs PCI: Remove unnecessary braces PCI: brcmstb: Add MSI support PCI: brcmstb: Add Broadcom STB PCIe host controller driver x86/PCI: Remove X86_DEV_DMA_OPS PCI: vmd: Remove dma_map_ops overrides iommu/vt-d: Remove VMD child device sanity check iommu/vt-d: Use pci_real_dma_dev() for mapping PCI: Introduce pci_real_dma_dev() x86/PCI: Expose VMD's pci_dev in struct pci_sysdata x86/PCI: Add to_pci_sysdata() helper PCI/AER: Initialize aer_fifo ...
This commit is contained in:
commit
26dca6dbd6
2
.mailmap
2
.mailmap
|
@ -27,6 +27,8 @@ Andi Shyti <andi@etezian.org> <andi.shyti@samsung.com>
|
|||
Andreas Herrmann <aherrman@de.ibm.com>
|
||||
Andrey Ryabinin <ryabinin.a.a@gmail.com> <a.ryabinin@samsung.com>
|
||||
Andrew Morton <akpm@linux-foundation.org>
|
||||
Andrew Murray <amurray@thegoodpenguin.co.uk> <andrew.murray@arm.com>
|
||||
Andrew Murray <amurray@thegoodpenguin.co.uk> <amurray@embedded-bits.co.uk>
|
||||
Andrew Vasquez <andrew.vasquez@qlogic.com>
|
||||
Andy Adamson <andros@citi.umich.edu>
|
||||
Antoine Tenart <antoine.tenart@free-electrons.com>
|
||||
|
|
|
@ -283,5 +283,5 @@ or disabled (0). If 0 is found in any of the msi_bus files belonging
|
|||
to bridges between the PCI root and the device, MSIs are disabled.
|
||||
|
||||
It is also worth checking the device driver to see whether it supports MSIs.
|
||||
For example, it may contain calls to pci_irq_alloc_vectors() with the
|
||||
For example, it may contain calls to pci_alloc_irq_vectors() with the
|
||||
PCI_IRQ_MSI or PCI_IRQ_MSIX flags.
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/brcm,stb-pcie.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Brcmstb PCIe Host Controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/pci/pci-bus.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: brcm,bcm2711-pcie # The Raspberry Pi 4
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- description: PCIe host controller
|
||||
- description: builtin MSI controller
|
||||
|
||||
interrupt-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: pcie
|
||||
- const: msi
|
||||
|
||||
ranges:
|
||||
maxItems: 1
|
||||
|
||||
dma-ranges:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: sw_pcie
|
||||
|
||||
msi-controller:
|
||||
description: Identifies the node as an MSI controller.
|
||||
|
||||
msi-parent:
|
||||
description: MSI controller the device is capable of using.
|
||||
|
||||
brcm,enable-ssc:
|
||||
description: Indicates usage of spread-spectrum clocking.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- reg
|
||||
- dma-ranges
|
||||
- "#interrupt-cells"
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- interrupt-map-mask
|
||||
- interrupt-map
|
||||
- msi-controller
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
scb {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
pcie0: pcie@7d500000 {
|
||||
compatible = "brcm,bcm2711-pcie";
|
||||
reg = <0x0 0x7d500000 0x9310>;
|
||||
device_type = "pci";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "pcie", "msi";
|
||||
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
|
||||
msi-parent = <&pcie0>;
|
||||
msi-controller;
|
||||
ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 0x0 0x04000000>;
|
||||
dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 0x0 0x80000000>;
|
||||
brcm,enable-ssc;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,138 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pci/intel-gw-pcie.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: PCIe RC controller on Intel Gateway SoCs
|
||||
|
||||
maintainers:
|
||||
- Dilip Kota <eswara.kota@linux.intel.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: intel,lgm-pcie
|
||||
- const: snps,dw-pcie
|
||||
|
||||
device_type:
|
||||
const: pci
|
||||
|
||||
"#address-cells":
|
||||
const: 3
|
||||
|
||||
"#size-cells":
|
||||
const: 2
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Controller control and status registers.
|
||||
- description: PCIe configuration registers.
|
||||
- description: Controller application registers.
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: config
|
||||
- const: app
|
||||
|
||||
ranges:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
const: pcie
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
linux,pci-domain: true
|
||||
|
||||
num-lanes:
|
||||
maximum: 2
|
||||
description: Number of lanes to use for this port.
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 1
|
||||
|
||||
interrupt-map-mask:
|
||||
description: Standard PCI IRQ mapping properties.
|
||||
|
||||
interrupt-map:
|
||||
description: Standard PCI IRQ mapping properties.
|
||||
|
||||
max-link-speed:
|
||||
description: Specify PCI Gen for link capability.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum: [ 1, 2, 3, 4 ]
|
||||
- default: 1
|
||||
|
||||
bus-range:
|
||||
description: Range of bus numbers associated with this controller.
|
||||
|
||||
reset-assert-ms:
|
||||
description: |
|
||||
Delay after asserting reset to the PCIe device.
|
||||
maximum: 500
|
||||
default: 100
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- device_type
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
- reg
|
||||
- reg-names
|
||||
- ranges
|
||||
- resets
|
||||
- clocks
|
||||
- phys
|
||||
- phy-names
|
||||
- reset-gpios
|
||||
- '#interrupt-cells'
|
||||
- interrupt-map
|
||||
- interrupt-map-mask
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/intel,lgm-clk.h>
|
||||
pcie10: pcie@d0e00000 {
|
||||
compatible = "intel,lgm-pcie", "snps,dw-pcie";
|
||||
device_type = "pci";
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
reg = <0xd0e00000 0x1000>,
|
||||
<0xd2000000 0x800000>,
|
||||
<0xd0a41000 0x1000>;
|
||||
reg-names = "dbi", "config", "app";
|
||||
linux,pci-domain = <0>;
|
||||
max-link-speed = <4>;
|
||||
bus-range = <0x00 0x08>;
|
||||
interrupt-parent = <&ioapic1>;
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0x7>;
|
||||
interrupt-map = <0 0 0 1 &ioapic1 27 1>,
|
||||
<0 0 0 2 &ioapic1 28 1>,
|
||||
<0 0 0 3 &ioapic1 29 1>,
|
||||
<0 0 0 4 &ioapic1 30 1>;
|
||||
ranges = <0x02000000 0 0xd4000000 0xd4000000 0 0x04000000>;
|
||||
resets = <&rcu0 0x50 0>;
|
||||
clocks = <&cgu0 LGM_GCLK_PCIE10>;
|
||||
phys = <&cb0phy0>;
|
||||
phy-names = "pcie";
|
||||
reset-assert-ms = <500>;
|
||||
reset-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
|
||||
num-lanes = <2>;
|
||||
};
|
|
@ -11,6 +11,7 @@
|
|||
- "qcom,pcie-ipq4019" for ipq4019
|
||||
- "qcom,pcie-ipq8074" for ipq8074
|
||||
- "qcom,pcie-qcs404" for qcs404
|
||||
- "qcom,pcie-sdm845" for sdm845
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
|
@ -126,6 +127,18 @@
|
|||
- "master_bus" AXI Master clock
|
||||
- "slave_bus" AXI Slave clock
|
||||
|
||||
-clock-names:
|
||||
Usage: required for sdm845
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "aux" Auxiliary clock
|
||||
- "cfg" Configuration clock
|
||||
- "bus_master" Master AXI clock
|
||||
- "bus_slave" Slave AXI clock
|
||||
- "slave_q2a" Slave Q2A clock
|
||||
- "tbu" PCIe TBU clock
|
||||
- "pipe" PIPE clock
|
||||
|
||||
- resets:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
|
@ -188,6 +201,12 @@
|
|||
- "pwr" PWR reset
|
||||
- "ahb" AHB reset
|
||||
|
||||
- reset-names:
|
||||
Usage: required for sdm845
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain the following entries
|
||||
- "pci" PCIe core reset
|
||||
|
||||
- power-domains:
|
||||
Usage: required for apq8084 and msm8996/apq8096
|
||||
Value type: <prop-encoded-array>
|
||||
|
|
|
@ -12914,7 +12914,7 @@ F: arch/x86/kernel/early-quirks.c
|
|||
|
||||
PCI NATIVE HOST BRIDGE AND ENDPOINT DRIVERS
|
||||
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
|
||||
R: Andrew Murray <andrew.murray@arm.com>
|
||||
R: Andrew Murray <amurray@thegoodpenguin.co.uk>
|
||||
L: linux-pci@vger.kernel.org
|
||||
Q: http://patchwork.ozlabs.org/project/linux-pci/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/pci.git/
|
||||
|
|
|
@ -2931,9 +2931,6 @@ config HAVE_ATOMIC_IOMAP
|
|||
def_bool y
|
||||
depends on X86_32
|
||||
|
||||
config X86_DEV_DMA_OPS
|
||||
bool
|
||||
|
||||
source "drivers/firmware/Kconfig"
|
||||
|
||||
source "arch/x86/kvm/Kconfig"
|
||||
|
|
|
@ -8,16 +8,6 @@ struct dev_archdata {
|
|||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
|
||||
struct dma_domain {
|
||||
struct list_head node;
|
||||
const struct dma_map_ops *dma_ops;
|
||||
int domain_nr;
|
||||
};
|
||||
void add_dma_domain(struct dma_domain *domain);
|
||||
void del_dma_domain(struct dma_domain *domain);
|
||||
#endif
|
||||
|
||||
struct pdev_archdata {
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ struct pci_sysdata {
|
|||
void *fwnode; /* IRQ domain for MSI assignment */
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_VMD)
|
||||
bool vmd_domain; /* True if in Intel VMD domain */
|
||||
struct pci_dev *vmd_dev; /* VMD Device if in Intel VMD domain */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -35,12 +35,15 @@ extern int noioapicreroute;
|
|||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
static inline struct pci_sysdata *to_pci_sysdata(const struct pci_bus *bus)
|
||||
{
|
||||
return bus->sysdata;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_DOMAINS
|
||||
static inline int pci_domain_nr(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_sysdata *sd = bus->sysdata;
|
||||
|
||||
return sd->domain;
|
||||
return to_pci_sysdata(bus)->domain;
|
||||
}
|
||||
|
||||
static inline int pci_proc_domain(struct pci_bus *bus)
|
||||
|
@ -52,24 +55,20 @@ static inline int pci_proc_domain(struct pci_bus *bus)
|
|||
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
|
||||
static inline void *_pci_root_bus_fwnode(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_sysdata *sd = bus->sysdata;
|
||||
|
||||
return sd->fwnode;
|
||||
return to_pci_sysdata(bus)->fwnode;
|
||||
}
|
||||
|
||||
#define pci_root_bus_fwnode _pci_root_bus_fwnode
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_VMD)
|
||||
static inline bool is_vmd(struct pci_bus *bus)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_VMD)
|
||||
struct pci_sysdata *sd = bus->sysdata;
|
||||
|
||||
return sd->vmd_domain;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return to_pci_sysdata(bus)->vmd_dev != NULL;
|
||||
}
|
||||
#else
|
||||
#define is_vmd(bus) false
|
||||
#endif /* CONFIG_VMD */
|
||||
|
||||
/* Can be used to override the logic in pci_scan_bus for skipping
|
||||
already-configured bus numbers - to be used for buggy BIOSes
|
||||
|
@ -124,9 +123,7 @@ void native_restore_msi_irqs(struct pci_dev *dev);
|
|||
/* Returns the node based on pci bus */
|
||||
static inline int __pcibus_to_node(const struct pci_bus *bus)
|
||||
{
|
||||
const struct pci_sysdata *sd = bus->sysdata;
|
||||
|
||||
return sd->node;
|
||||
return to_pci_sysdata(bus)->node;
|
||||
}
|
||||
|
||||
static inline const struct cpumask *
|
||||
|
|
|
@ -625,43 +625,6 @@ unsigned int pcibios_assign_all_busses(void)
|
|||
return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS)
|
||||
static LIST_HEAD(dma_domain_list);
|
||||
static DEFINE_SPINLOCK(dma_domain_list_lock);
|
||||
|
||||
void add_dma_domain(struct dma_domain *domain)
|
||||
{
|
||||
spin_lock(&dma_domain_list_lock);
|
||||
list_add(&domain->node, &dma_domain_list);
|
||||
spin_unlock(&dma_domain_list_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(add_dma_domain);
|
||||
|
||||
void del_dma_domain(struct dma_domain *domain)
|
||||
{
|
||||
spin_lock(&dma_domain_list_lock);
|
||||
list_del(&domain->node);
|
||||
spin_unlock(&dma_domain_list_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(del_dma_domain);
|
||||
|
||||
static void set_dma_domain_ops(struct pci_dev *pdev)
|
||||
{
|
||||
struct dma_domain *domain;
|
||||
|
||||
spin_lock(&dma_domain_list_lock);
|
||||
list_for_each_entry(domain, &dma_domain_list, node) {
|
||||
if (pci_domain_nr(pdev->bus) == domain->domain_nr) {
|
||||
pdev->dev.dma_ops = domain->dma_ops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&dma_domain_list_lock);
|
||||
}
|
||||
#else
|
||||
static void set_dma_domain_ops(struct pci_dev *pdev) {}
|
||||
#endif
|
||||
|
||||
static void set_dev_domain_options(struct pci_dev *pdev)
|
||||
{
|
||||
if (is_vmd(pdev->bus))
|
||||
|
@ -697,7 +660,6 @@ int pcibios_add_device(struct pci_dev *dev)
|
|||
pa_data = data->next;
|
||||
memunmap(data);
|
||||
}
|
||||
set_dma_domain_ops(dev);
|
||||
set_dev_domain_options(dev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -736,3 +698,13 @@ int pci_ext_cfg_avail(void)
|
|||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_VMD)
|
||||
struct pci_dev *pci_real_dma_dev(struct pci_dev *dev)
|
||||
{
|
||||
if (is_vmd(dev->bus))
|
||||
return to_pci_sysdata(dev->bus)->vmd_dev;
|
||||
|
||||
return dev;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -230,11 +230,8 @@ static struct pci_dev *setup_aliases(struct device *dev)
|
|||
*/
|
||||
ivrs_alias = amd_iommu_alias_table[pci_dev_id(pdev)];
|
||||
if (ivrs_alias != pci_dev_id(pdev) &&
|
||||
PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
|
||||
pci_add_dma_alias(pdev, ivrs_alias & 0xff);
|
||||
pci_info(pdev, "Added PCI DMA alias %02x.%d\n",
|
||||
PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias));
|
||||
}
|
||||
PCI_BUS_NUM(ivrs_alias) == pdev->bus->number)
|
||||
pci_add_dma_alias(pdev, ivrs_alias & 0xff, 1);
|
||||
|
||||
clone_aliases(pdev);
|
||||
|
||||
|
|
|
@ -774,13 +774,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
|
|||
if (dev_is_pci(dev)) {
|
||||
struct pci_dev *pf_pdev;
|
||||
|
||||
pdev = to_pci_dev(dev);
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* VMD child devices currently cannot be handled individually */
|
||||
if (is_vmd(pdev->bus))
|
||||
return NULL;
|
||||
#endif
|
||||
pdev = pci_real_dma_dev(to_pci_dev(dev));
|
||||
|
||||
/* VFs aren't listed in scope tables; we need to look up
|
||||
* the PF instead to find the IOMMU. */
|
||||
|
@ -2428,6 +2422,9 @@ static struct dmar_domain *find_domain(struct device *dev)
|
|||
dev->archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO))
|
||||
return NULL;
|
||||
|
||||
if (dev_is_pci(dev))
|
||||
dev = &pci_real_dma_dev(to_pci_dev(dev))->dev;
|
||||
|
||||
/* No lock here, assumes no domain exit in normal case */
|
||||
info = dev->archdata.iommu;
|
||||
if (likely(info))
|
||||
|
|
|
@ -239,7 +239,6 @@ config PCIE_TANGO_SMP8759
|
|||
|
||||
config VMD
|
||||
depends on PCI_MSI && X86_64 && SRCU
|
||||
select X86_DEV_DMA_OPS
|
||||
tristate "Intel Volume Management Device Driver"
|
||||
---help---
|
||||
Adds support for the Intel Volume Management Device (VMD). VMD is a
|
||||
|
@ -253,6 +252,15 @@ config VMD
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called vmd.
|
||||
|
||||
config PCIE_BRCMSTB
|
||||
tristate "Broadcom Brcmstb PCIe host controller"
|
||||
depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
help
|
||||
Say Y here to enable PCIe host controller support for
|
||||
Broadcom STB based SoCs, like the Raspberry Pi 4.
|
||||
|
||||
config PCI_HYPERV_INTERFACE
|
||||
tristate "Hyper-V PCI Interface"
|
||||
depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64
|
||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
|
|||
obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
|
||||
obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
|
||||
obj-$(CONFIG_VMD) += vmd.o
|
||||
obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
|
||||
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
|
||||
obj-y += dwc/
|
||||
|
||||
|
|
|
@ -209,6 +209,17 @@ config PCIE_ARTPEC6_EP
|
|||
Enables support for the PCIe controller in the ARTPEC-6 SoC to work in
|
||||
endpoint mode. This uses the DesignWare core.
|
||||
|
||||
config PCIE_INTEL_GW
|
||||
bool "Intel Gateway PCIe host controller support"
|
||||
depends on OF && (X86 || COMPILE_TEST)
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
help
|
||||
Say 'Y' here to enable PCIe Host controller support on Intel
|
||||
Gateway SoCs.
|
||||
The PCIe controller uses the DesignWare core plus Intel-specific
|
||||
hardware wrappers.
|
||||
|
||||
config PCIE_KIRIN
|
||||
depends on OF && (ARM64 || COMPILE_TEST)
|
||||
bool "HiSilicon Kirin series SoCs PCIe controllers"
|
||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_PCI_LAYERSCAPE_EP) += pci-layerscape-ep.o
|
|||
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
|
||||
obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
|
||||
obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o
|
||||
obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
|
||||
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
||||
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
||||
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Samsung EXYNOS SoCs
|
||||
* PCIe host controller driver for Samsung Exynos SoCs
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
|
|
|
@ -422,7 +422,7 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
|||
lower_32_bits(start) | OB_ENABLEN);
|
||||
ks_pcie_app_writel(ks_pcie, OB_OFFSET_HI(i),
|
||||
upper_32_bits(start));
|
||||
start += OB_WIN_SIZE;
|
||||
start += OB_WIN_SIZE * SZ_1M;
|
||||
}
|
||||
|
||||
val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
|
||||
|
@ -510,7 +510,7 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
|
|||
/* Disable Link training */
|
||||
val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
|
||||
val &= ~LTSSM_EN_VAL;
|
||||
ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
|
||||
ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
|
||||
}
|
||||
|
||||
static int ks_pcie_start_link(struct dw_pcie *pci)
|
||||
|
@ -1354,7 +1354,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
|||
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to read *num-viewport* property\n");
|
||||
return ret;
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -51,9 +51,6 @@ static const struct of_device_id artpec6_pcie_of_match[];
|
|||
#define ACK_N_FTS_MASK GENMASK(15, 8)
|
||||
#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK)
|
||||
|
||||
#define FAST_TRAINING_SEQ_MASK GENMASK(7, 0)
|
||||
#define FAST_TRAINING_SEQ(x) (((x) << 0) & FAST_TRAINING_SEQ_MASK)
|
||||
|
||||
/* ARTPEC-6 specific registers */
|
||||
#define PCIECFG 0x18
|
||||
#define PCIECFG_DBG_OEN BIT(24)
|
||||
|
@ -313,10 +310,7 @@ static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie)
|
|||
* Set the Number of Fast Training Sequences that the core
|
||||
* advertises as its N_FTS during Gen2 or Gen3 link training.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~FAST_TRAINING_SEQ_MASK;
|
||||
val |= FAST_TRAINING_SEQ(180);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
dw_pcie_link_set_n_fts(pci, 180);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
/*
|
||||
|
@ -474,6 +475,61 @@ int dw_pcie_link_up(struct dw_pcie *pci)
|
|||
(!(val & PCIE_PORT_DEBUG1_LINK_IN_TRAINING)));
|
||||
}
|
||||
|
||||
void dw_pcie_upconfig_setup(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL);
|
||||
val |= PORT_MLTI_UPCFG_SUPPORT;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_MULTI_LANE_CTRL, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
|
||||
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
{
|
||||
u32 reg, val;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
|
||||
reg &= ~PCI_EXP_LNKCTL2_TLS;
|
||||
|
||||
switch (pcie_link_speed[link_gen]) {
|
||||
case PCIE_SPEED_2_5GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_2_5GT;
|
||||
break;
|
||||
case PCIE_SPEED_5_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_5_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_8_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_8_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_16_0GT;
|
||||
break;
|
||||
default:
|
||||
/* Use hardware capability */
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
reg &= ~PCI_EXP_LNKCTL2_HASD;
|
||||
reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val);
|
||||
break;
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed);
|
||||
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_N_FTS_MASK;
|
||||
val |= n_fts & PORT_LOGIC_N_FTS_MASK;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts);
|
||||
|
||||
static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val;
|
||||
|
|
|
@ -30,7 +30,12 @@
|
|||
#define LINK_WAIT_IATU 9
|
||||
|
||||
/* Synopsys-specific PCIe configuration registers */
|
||||
#define PCIE_PORT_AFR 0x70C
|
||||
#define PORT_AFR_N_FTS_MASK GENMASK(15, 8)
|
||||
#define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16)
|
||||
|
||||
#define PCIE_PORT_LINK_CONTROL 0x710
|
||||
#define PORT_LINK_DLL_LINK_EN BIT(5)
|
||||
#define PORT_LINK_MODE_MASK GENMASK(21, 16)
|
||||
#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
|
||||
#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
|
||||
|
@ -46,6 +51,7 @@
|
|||
#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29)
|
||||
|
||||
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
|
||||
#define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0)
|
||||
#define PORT_LOGIC_SPEED_CHANGE BIT(17)
|
||||
#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
|
||||
|
@ -60,6 +66,9 @@
|
|||
#define PCIE_MSI_INTR0_MASK 0x82C
|
||||
#define PCIE_MSI_INTR0_STATUS 0x830
|
||||
|
||||
#define PCIE_PORT_MULTI_LANE_CTRL 0x8C0
|
||||
#define PORT_MLTI_UPCFG_SUPPORT BIT(7)
|
||||
|
||||
#define PCIE_ATU_VIEWPORT 0x900
|
||||
#define PCIE_ATU_REGION_INBOUND BIT(31)
|
||||
#define PCIE_ATU_REGION_OUTBOUND 0
|
||||
|
@ -273,6 +282,9 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
|||
u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
int dw_pcie_link_up(struct dw_pcie *pci);
|
||||
void dw_pcie_upconfig_setup(struct dw_pcie *pci);
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen);
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
|
|
|
@ -0,0 +1,545 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Intel Gateway SoCs
|
||||
*
|
||||
* Copyright (c) 2019 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/pci_regs.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define PORT_AFR_N_FTS_GEN12_DFT (SZ_128 - 1)
|
||||
#define PORT_AFR_N_FTS_GEN3 180
|
||||
#define PORT_AFR_N_FTS_GEN4 196
|
||||
|
||||
/* PCIe Application logic Registers */
|
||||
#define PCIE_APP_CCR 0x10
|
||||
#define PCIE_APP_CCR_LTSSM_ENABLE BIT(0)
|
||||
|
||||
#define PCIE_APP_MSG_CR 0x30
|
||||
#define PCIE_APP_MSG_XMT_PM_TURNOFF BIT(0)
|
||||
|
||||
#define PCIE_APP_PMC 0x44
|
||||
#define PCIE_APP_PMC_IN_L2 BIT(20)
|
||||
|
||||
#define PCIE_APP_IRNEN 0xF4
|
||||
#define PCIE_APP_IRNCR 0xF8
|
||||
#define PCIE_APP_IRN_AER_REPORT BIT(0)
|
||||
#define PCIE_APP_IRN_PME BIT(2)
|
||||
#define PCIE_APP_IRN_RX_VDM_MSG BIT(4)
|
||||
#define PCIE_APP_IRN_PM_TO_ACK BIT(9)
|
||||
#define PCIE_APP_IRN_LINK_AUTO_BW_STAT BIT(11)
|
||||
#define PCIE_APP_IRN_BW_MGT BIT(12)
|
||||
#define PCIE_APP_IRN_MSG_LTR BIT(18)
|
||||
#define PCIE_APP_IRN_SYS_ERR_RC BIT(29)
|
||||
#define PCIE_APP_INTX_OFST 12
|
||||
|
||||
#define PCIE_APP_IRN_INT \
|
||||
(PCIE_APP_IRN_AER_REPORT | PCIE_APP_IRN_PME | \
|
||||
PCIE_APP_IRN_RX_VDM_MSG | PCIE_APP_IRN_SYS_ERR_RC | \
|
||||
PCIE_APP_IRN_PM_TO_ACK | PCIE_APP_IRN_MSG_LTR | \
|
||||
PCIE_APP_IRN_BW_MGT | PCIE_APP_IRN_LINK_AUTO_BW_STAT | \
|
||||
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTA) | \
|
||||
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTB) | \
|
||||
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTC) | \
|
||||
(PCIE_APP_INTX_OFST + PCI_INTERRUPT_INTD))
|
||||
|
||||
#define BUS_IATU_OFFSET SZ_256M
|
||||
#define RESET_INTERVAL_MS 100
|
||||
|
||||
struct intel_pcie_soc {
|
||||
unsigned int pcie_ver;
|
||||
unsigned int pcie_atu_offset;
|
||||
u32 num_viewport;
|
||||
};
|
||||
|
||||
struct intel_pcie_port {
|
||||
struct dw_pcie pci;
|
||||
void __iomem *app_base;
|
||||
struct gpio_desc *reset_gpio;
|
||||
u32 rst_intrvl;
|
||||
u32 max_speed;
|
||||
u32 link_gen;
|
||||
u32 max_width;
|
||||
u32 n_fts;
|
||||
struct clk *core_clk;
|
||||
struct reset_control *core_rst;
|
||||
struct phy *phy;
|
||||
u8 pcie_cap_ofst;
|
||||
};
|
||||
|
||||
static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val)
|
||||
{
|
||||
u32 old;
|
||||
|
||||
old = readl(base + ofs);
|
||||
val = (old & ~mask) | (val & mask);
|
||||
|
||||
if (val != old)
|
||||
writel(val, base + ofs);
|
||||
}
|
||||
|
||||
static inline u32 pcie_app_rd(struct intel_pcie_port *lpp, u32 ofs)
|
||||
{
|
||||
return readl(lpp->app_base + ofs);
|
||||
}
|
||||
|
||||
static inline void pcie_app_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val)
|
||||
{
|
||||
writel(val, lpp->app_base + ofs);
|
||||
}
|
||||
|
||||
static void pcie_app_wr_mask(struct intel_pcie_port *lpp, u32 ofs,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
pcie_update_bits(lpp->app_base, ofs, mask, val);
|
||||
}
|
||||
|
||||
static inline u32 pcie_rc_cfg_rd(struct intel_pcie_port *lpp, u32 ofs)
|
||||
{
|
||||
return dw_pcie_readl_dbi(&lpp->pci, ofs);
|
||||
}
|
||||
|
||||
static inline void pcie_rc_cfg_wr(struct intel_pcie_port *lpp, u32 ofs, u32 val)
|
||||
{
|
||||
dw_pcie_writel_dbi(&lpp->pci, ofs, val);
|
||||
}
|
||||
|
||||
static void pcie_rc_cfg_wr_mask(struct intel_pcie_port *lpp, u32 ofs,
|
||||
u32 mask, u32 val)
|
||||
{
|
||||
pcie_update_bits(lpp->pci.dbi_base, ofs, mask, val);
|
||||
}
|
||||
|
||||
static void intel_pcie_ltssm_enable(struct intel_pcie_port *lpp)
|
||||
{
|
||||
pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE,
|
||||
PCIE_APP_CCR_LTSSM_ENABLE);
|
||||
}
|
||||
|
||||
static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp)
|
||||
{
|
||||
pcie_app_wr_mask(lpp, PCIE_APP_CCR, PCIE_APP_CCR_LTSSM_ENABLE, 0);
|
||||
}
|
||||
|
||||
static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 val;
|
||||
u8 offset = lpp->pcie_cap_ofst;
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP);
|
||||
lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val);
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL);
|
||||
|
||||
val &= ~(PCI_EXP_LNKCTL_LD | PCI_EXP_LNKCTL_ASPMC);
|
||||
pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val);
|
||||
}
|
||||
|
||||
static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 val, mask;
|
||||
|
||||
switch (pcie_link_speed[lpp->max_speed]) {
|
||||
case PCIE_SPEED_8_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN3;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN4;
|
||||
break;
|
||||
default:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
break;
|
||||
}
|
||||
|
||||
mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK;
|
||||
val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) |
|
||||
FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts);
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val);
|
||||
|
||||
/* Port Link Control Register */
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN,
|
||||
PORT_LINK_DLL_LINK_EN);
|
||||
}
|
||||
|
||||
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_ltssm_disable(lpp);
|
||||
intel_pcie_link_setup(lpp);
|
||||
dw_pcie_setup_rc(&lpp->pci.pp);
|
||||
dw_pcie_upconfig_setup(&lpp->pci);
|
||||
intel_pcie_port_logic_setup(lpp);
|
||||
dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen);
|
||||
dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts);
|
||||
}
|
||||
|
||||
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
|
||||
{
|
||||
struct device *dev = lpp->pci.dev;
|
||||
int ret;
|
||||
|
||||
lpp->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lpp->reset_gpio)) {
|
||||
ret = PTR_ERR(lpp->reset_gpio);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to request PCIe GPIO: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Make initial reset last for 100us */
|
||||
usleep_range(100, 200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_pcie_core_rst_assert(struct intel_pcie_port *lpp)
|
||||
{
|
||||
reset_control_assert(lpp->core_rst);
|
||||
}
|
||||
|
||||
static void intel_pcie_core_rst_deassert(struct intel_pcie_port *lpp)
|
||||
{
|
||||
/*
|
||||
* One micro-second delay to make sure the reset pulse
|
||||
* wide enough so that core reset is clean.
|
||||
*/
|
||||
udelay(1);
|
||||
reset_control_deassert(lpp->core_rst);
|
||||
|
||||
/*
|
||||
* Some SoC core reset also reset PHY, more delay needed
|
||||
* to make sure the reset process is done.
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
static void intel_pcie_device_rst_assert(struct intel_pcie_port *lpp)
|
||||
{
|
||||
gpiod_set_value_cansleep(lpp->reset_gpio, 1);
|
||||
}
|
||||
|
||||
static void intel_pcie_device_rst_deassert(struct intel_pcie_port *lpp)
|
||||
{
|
||||
msleep(lpp->rst_intrvl);
|
||||
gpiod_set_value_cansleep(lpp->reset_gpio, 0);
|
||||
}
|
||||
|
||||
static int intel_pcie_app_logic_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_device_rst_deassert(lpp);
|
||||
intel_pcie_ltssm_enable(lpp);
|
||||
|
||||
return dw_pcie_wait_for_link(&lpp->pci);
|
||||
}
|
||||
|
||||
static void intel_pcie_core_irq_disable(struct intel_pcie_port *lpp)
|
||||
{
|
||||
pcie_app_wr(lpp, PCIE_APP_IRNEN, 0);
|
||||
pcie_app_wr(lpp, PCIE_APP_IRNCR, PCIE_APP_IRN_INT);
|
||||
}
|
||||
|
||||
static int intel_pcie_get_resources(struct platform_device *pdev)
|
||||
{
|
||||
struct intel_pcie_port *lpp = platform_get_drvdata(pdev);
|
||||
struct dw_pcie *pci = &lpp->pci;
|
||||
struct device *dev = pci->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
lpp->core_clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(lpp->core_clk)) {
|
||||
ret = PTR_ERR(lpp->core_clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get clks: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lpp->core_rst = devm_reset_control_get(dev, NULL);
|
||||
if (IS_ERR(lpp->core_rst)) {
|
||||
ret = PTR_ERR(lpp->core_rst);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Failed to get resets: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_match_string(dev, "device_type", "pci");
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to find pci device type: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(dev, "reset-assert-ms",
|
||||
&lpp->rst_intrvl);
|
||||
if (ret)
|
||||
lpp->rst_intrvl = RESET_INTERVAL_MS;
|
||||
|
||||
ret = of_pci_get_max_link_speed(dev->of_node);
|
||||
lpp->link_gen = ret < 0 ? 0 : ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "app");
|
||||
lpp->app_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(lpp->app_base))
|
||||
return PTR_ERR(lpp->app_base);
|
||||
|
||||
lpp->phy = devm_phy_get(dev, "pcie");
|
||||
if (IS_ERR(lpp->phy)) {
|
||||
ret = PTR_ERR(lpp->phy);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "Couldn't get pcie-phy: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_pcie_deinit_phy(struct intel_pcie_port *lpp)
|
||||
{
|
||||
phy_exit(lpp->phy);
|
||||
}
|
||||
|
||||
static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT)
|
||||
return 0;
|
||||
|
||||
/* Send PME_TURN_OFF message */
|
||||
pcie_app_wr_mask(lpp, PCIE_APP_MSG_CR, PCIE_APP_MSG_XMT_PM_TURNOFF,
|
||||
PCIE_APP_MSG_XMT_PM_TURNOFF);
|
||||
|
||||
/* Read PMC status and wait for falling into L2 link state */
|
||||
ret = readl_poll_timeout(lpp->app_base + PCIE_APP_PMC, value,
|
||||
value & PCIE_APP_PMC_IN_L2, 20,
|
||||
jiffies_to_usecs(5 * HZ));
|
||||
if (ret)
|
||||
dev_err(lpp->pci.dev, "PCIe link enter L2 timeout!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
|
||||
{
|
||||
if (dw_pcie_link_up(&lpp->pci))
|
||||
intel_pcie_wait_l2(lpp);
|
||||
|
||||
/* Put endpoint device in reset state */
|
||||
intel_pcie_device_rst_assert(lpp);
|
||||
pcie_rc_cfg_wr_mask(lpp, PCI_COMMAND, PCI_COMMAND_MEMORY, 0);
|
||||
}
|
||||
|
||||
static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
struct device *dev = lpp->pci.dev;
|
||||
int ret;
|
||||
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_device_rst_assert(lpp);
|
||||
|
||||
ret = phy_init(lpp->phy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_pcie_core_rst_deassert(lpp);
|
||||
|
||||
ret = clk_prepare_enable(lpp->core_clk);
|
||||
if (ret) {
|
||||
dev_err(lpp->pci.dev, "Core clock enable failed: %d\n", ret);
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
if (!lpp->pcie_cap_ofst) {
|
||||
ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
|
||||
if (!ret) {
|
||||
ret = -ENXIO;
|
||||
dev_err(dev, "Invalid PCIe capability offset\n");
|
||||
goto app_init_err;
|
||||
}
|
||||
|
||||
lpp->pcie_cap_ofst = ret;
|
||||
}
|
||||
|
||||
intel_pcie_rc_setup(lpp);
|
||||
ret = intel_pcie_app_logic_setup(lpp);
|
||||
if (ret)
|
||||
goto app_init_err;
|
||||
|
||||
/* Enable integrated interrupts */
|
||||
pcie_app_wr_mask(lpp, PCIE_APP_IRNEN, PCIE_APP_IRN_INT,
|
||||
PCIE_APP_IRN_INT);
|
||||
|
||||
return 0;
|
||||
|
||||
app_init_err:
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
clk_err:
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __intel_pcie_remove(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_core_irq_disable(lpp);
|
||||
intel_pcie_turn_off(lpp);
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
}
|
||||
|
||||
static int intel_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct intel_pcie_port *lpp = platform_get_drvdata(pdev);
|
||||
struct pcie_port *pp = &lpp->pci.pp;
|
||||
|
||||
dw_pcie_host_deinit(pp);
|
||||
__intel_pcie_remove(lpp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused intel_pcie_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct intel_pcie_port *lpp = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
intel_pcie_core_irq_disable(lpp);
|
||||
ret = intel_pcie_wait_l2(lpp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
intel_pcie_deinit_phy(lpp);
|
||||
clk_disable_unprepare(lpp->core_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __maybe_unused intel_pcie_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct intel_pcie_port *lpp = dev_get_drvdata(dev);
|
||||
|
||||
return intel_pcie_host_setup(lpp);
|
||||
}
|
||||
|
||||
static int intel_pcie_rc_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct intel_pcie_port *lpp = dev_get_drvdata(pci->dev);
|
||||
|
||||
return intel_pcie_host_setup(lpp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy function so that DW core doesn't configure MSI
|
||||
*/
|
||||
static int intel_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
|
||||
{
|
||||
return cpu_addr + BUS_IATU_OFFSET;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops intel_pcie_ops = {
|
||||
.cpu_addr_fixup = intel_pcie_cpu_addr,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
|
||||
.host_init = intel_pcie_rc_init,
|
||||
.msi_host_init = intel_pcie_msi_init,
|
||||
};
|
||||
|
||||
static const struct intel_pcie_soc pcie_data = {
|
||||
.pcie_ver = 0x520A,
|
||||
.pcie_atu_offset = 0xC0000,
|
||||
.num_viewport = 3,
|
||||
};
|
||||
|
||||
static int intel_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct intel_pcie_soc *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct intel_pcie_port *lpp;
|
||||
struct pcie_port *pp;
|
||||
struct dw_pcie *pci;
|
||||
int ret;
|
||||
|
||||
lpp = devm_kzalloc(dev, sizeof(*lpp), GFP_KERNEL);
|
||||
if (!lpp)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, lpp);
|
||||
pci = &lpp->pci;
|
||||
pci->dev = dev;
|
||||
pp = &pci->pp;
|
||||
|
||||
ret = intel_pcie_get_resources(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_pcie_ep_rst_init(lpp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
pci->ops = &intel_pcie_ops;
|
||||
pci->version = data->pcie_ver;
|
||||
pci->atu_base = pci->dbi_base + data->pcie_atu_offset;
|
||||
pp->ops = &intel_pcie_dw_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Intel PCIe doesn't configure IO region, so set viewport
|
||||
* to not perform IO region access.
|
||||
*/
|
||||
pci->num_viewport = data->num_viewport;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops intel_pcie_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(intel_pcie_suspend_noirq,
|
||||
intel_pcie_resume_noirq)
|
||||
};
|
||||
|
||||
static const struct of_device_id of_intel_pcie_match[] = {
|
||||
{ .compatible = "intel,lgm-pcie", .data = &pcie_data },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver intel_pcie_driver = {
|
||||
.probe = intel_pcie_probe,
|
||||
.remove = intel_pcie_remove,
|
||||
.driver = {
|
||||
.name = "intel-gw-pcie",
|
||||
.of_match_table = of_intel_pcie_match,
|
||||
.pm = &intel_pcie_pm_ops,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(intel_pcie_driver);
|
|
@ -54,6 +54,7 @@
|
|||
#define PCIE20_PARF_LTSSM 0x1B0
|
||||
#define PCIE20_PARF_SID_OFFSET 0x234
|
||||
#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C
|
||||
#define PCIE20_PARF_DEVICE_TYPE 0x1000
|
||||
|
||||
#define PCIE20_ELBI_SYS_CTRL 0x04
|
||||
#define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0)
|
||||
|
@ -80,6 +81,8 @@
|
|||
#define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE 0x358
|
||||
#define SLV_ADDR_SPACE_SZ 0x10000000
|
||||
|
||||
#define DEVICE_TYPE_RC 0x4
|
||||
|
||||
#define QCOM_PCIE_2_1_0_MAX_SUPPLY 3
|
||||
struct qcom_pcie_resources_2_1_0 {
|
||||
struct clk *iface_clk;
|
||||
|
@ -139,12 +142,20 @@ struct qcom_pcie_resources_2_3_3 {
|
|||
struct reset_control *rst[7];
|
||||
};
|
||||
|
||||
struct qcom_pcie_resources_2_7_0 {
|
||||
struct clk_bulk_data clks[6];
|
||||
struct regulator_bulk_data supplies[2];
|
||||
struct reset_control *pci_reset;
|
||||
struct clk *pipe_clk;
|
||||
};
|
||||
|
||||
union qcom_pcie_resources {
|
||||
struct qcom_pcie_resources_1_0_0 v1_0_0;
|
||||
struct qcom_pcie_resources_2_1_0 v2_1_0;
|
||||
struct qcom_pcie_resources_2_3_2 v2_3_2;
|
||||
struct qcom_pcie_resources_2_3_3 v2_3_3;
|
||||
struct qcom_pcie_resources_2_4_0 v2_4_0;
|
||||
struct qcom_pcie_resources_2_7_0 v2_7_0;
|
||||
};
|
||||
|
||||
struct qcom_pcie;
|
||||
|
@ -1068,6 +1079,134 @@ err_clk_iface:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
int ret;
|
||||
|
||||
res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
|
||||
if (IS_ERR(res->pci_reset))
|
||||
return PTR_ERR(res->pci_reset);
|
||||
|
||||
res->supplies[0].supply = "vdda";
|
||||
res->supplies[1].supply = "vddpe-3v3";
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
|
||||
res->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res->clks[0].id = "aux";
|
||||
res->clks[1].id = "cfg";
|
||||
res->clks[2].id = "bus_master";
|
||||
res->clks[3].id = "bus_slave";
|
||||
res->clks[4].id = "slave_q2a";
|
||||
res->clks[5].id = "tbu";
|
||||
|
||||
ret = devm_clk_bulk_get(dev, ARRAY_SIZE(res->clks), res->clks);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
res->pipe_clk = devm_clk_get(dev, "pipe");
|
||||
return PTR_ERR_OR_ZERO(res->pipe_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(res->supplies), res->supplies);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(res->clks), res->clks);
|
||||
if (ret < 0)
|
||||
goto err_disable_regulators;
|
||||
|
||||
ret = reset_control_assert(res->pci_reset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot deassert pci reset\n");
|
||||
goto err_disable_clocks;
|
||||
}
|
||||
|
||||
usleep_range(1000, 1500);
|
||||
|
||||
ret = reset_control_deassert(res->pci_reset);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot deassert pci reset\n");
|
||||
goto err_disable_clocks;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(res->pipe_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot prepare/enable pipe clock\n");
|
||||
goto err_disable_clocks;
|
||||
}
|
||||
|
||||
/* configure PCIe to RC mode */
|
||||
writel(DEVICE_TYPE_RC, pcie->parf + PCIE20_PARF_DEVICE_TYPE);
|
||||
|
||||
/* enable PCIe clocks and resets */
|
||||
val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
val &= ~BIT(0);
|
||||
writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
|
||||
|
||||
/* change DBI base address */
|
||||
writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
|
||||
|
||||
/* MAC PHY_POWERDOWN MUX DISABLE */
|
||||
val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL);
|
||||
val &= ~BIT(29);
|
||||
writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL);
|
||||
|
||||
val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
|
||||
val |= BIT(4);
|
||||
writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
|
||||
val |= BIT(31);
|
||||
writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_disable_clocks:
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
|
||||
err_disable_regulators:
|
||||
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(res->clks), res->clks);
|
||||
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
|
||||
}
|
||||
|
||||
static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
|
||||
|
||||
return clk_prepare_enable(res->pipe_clk);
|
||||
}
|
||||
|
||||
static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
|
||||
{
|
||||
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
|
||||
|
||||
clk_disable_unprepare(res->pipe_clk);
|
||||
}
|
||||
|
||||
static int qcom_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
|
||||
|
@ -1167,6 +1306,16 @@ static const struct qcom_pcie_ops ops_2_3_3 = {
|
|||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
};
|
||||
|
||||
/* Qcom IP rev.: 2.7.0 Synopsys IP rev.: 4.30a */
|
||||
static const struct qcom_pcie_ops ops_2_7_0 = {
|
||||
.get_resources = qcom_pcie_get_resources_2_7_0,
|
||||
.init = qcom_pcie_init_2_7_0,
|
||||
.deinit = qcom_pcie_deinit_2_7_0,
|
||||
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
|
||||
.post_init = qcom_pcie_post_init_2_7_0,
|
||||
.post_deinit = qcom_pcie_post_deinit_2_7_0,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.link_up = qcom_pcie_link_up,
|
||||
};
|
||||
|
@ -1282,6 +1431,7 @@ static const struct of_device_id qcom_pcie_match[] = {
|
|||
{ .compatible = "qcom,pcie-ipq8074", .data = &ops_2_3_3 },
|
||||
{ .compatible = "qcom,pcie-ipq4019", .data = &ops_2_4_0 },
|
||||
{ .compatible = "qcom,pcie-qcs404", .data = &ops_2_4_0 },
|
||||
{ .compatible = "qcom,pcie-sdm845", .data = &ops_2_7_0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
@ -171,12 +171,6 @@ static void uniphier_pcie_irq_enable(struct uniphier_pcie_priv *priv)
|
|||
writel(PCL_RCV_INTX_ALL_ENABLE, priv->base + PCL_RCV_INTX);
|
||||
}
|
||||
|
||||
static void uniphier_pcie_irq_disable(struct uniphier_pcie_priv *priv)
|
||||
{
|
||||
writel(0, priv->base + PCL_RCV_INT);
|
||||
writel(0, priv->base + PCL_RCV_INTX);
|
||||
}
|
||||
|
||||
static void uniphier_pcie_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
|
@ -397,14 +391,6 @@ out_clk_disable:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void uniphier_pcie_host_disable(struct uniphier_pcie_priv *priv)
|
||||
{
|
||||
uniphier_pcie_irq_disable(priv);
|
||||
phy_exit(priv->phy);
|
||||
reset_control_assert(priv->rst);
|
||||
clk_disable_unprepare(priv->clk);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.start_link = uniphier_pcie_establish_link,
|
||||
.stop_link = uniphier_pcie_stop_link,
|
||||
|
@ -456,31 +442,16 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
|
|||
return uniphier_add_pcie_port(priv, pdev);
|
||||
}
|
||||
|
||||
static int uniphier_pcie_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_pcie_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
uniphier_pcie_host_disable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id uniphier_pcie_match[] = {
|
||||
{ .compatible = "socionext,uniphier-pcie", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, uniphier_pcie_match);
|
||||
|
||||
static struct platform_driver uniphier_pcie_driver = {
|
||||
.probe = uniphier_pcie_probe,
|
||||
.remove = uniphier_pcie_remove,
|
||||
.driver = {
|
||||
.name = "uniphier-pcie",
|
||||
.of_match_table = uniphier_pcie_match,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(uniphier_pcie_driver);
|
||||
|
||||
MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
|
||||
MODULE_DESCRIPTION("UniPhier PCIe host controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -2499,7 +2499,6 @@ static const struct tegra_pcie_soc tegra20_pcie = {
|
|||
.num_ports = 2,
|
||||
.ports = tegra20_pcie_ports,
|
||||
.msi_base_shift = 0,
|
||||
.afi_pex2_ctrl = 0x128,
|
||||
.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
|
||||
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
|
||||
.pads_refclk_cfg0 = 0xfa5cfa5c,
|
||||
|
@ -2528,6 +2527,7 @@ static const struct tegra_pcie_soc tegra30_pcie = {
|
|||
.num_ports = 3,
|
||||
.ports = tegra30_pcie_ports,
|
||||
.msi_base_shift = 8,
|
||||
.afi_pex2_ctrl = 0x128,
|
||||
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
|
||||
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
|
||||
.pads_refclk_cfg0 = 0xfa5cfa5c,
|
||||
|
@ -2798,7 +2798,7 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
pm_runtime_enable(pcie->dev);
|
||||
err = pm_runtime_get_sync(pcie->dev);
|
||||
if (err) {
|
||||
if (err < 0) {
|
||||
dev_err(dev, "fail to enable pcie controller: %d\n", err);
|
||||
goto teardown_msi;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1588,6 +1588,30 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802,
|
|||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804,
|
||||
quirk_paxc_disable_msi_parsing);
|
||||
|
||||
static void quirk_paxc_bridge(struct pci_dev *pdev)
|
||||
{
|
||||
/*
|
||||
* The PCI config space is shared with the PAXC root port and the first
|
||||
* Ethernet device. So, we need to workaround this by telling the PCI
|
||||
* code that the bridge is not an Ethernet device.
|
||||
*/
|
||||
if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
|
||||
pdev->class = PCI_CLASS_BRIDGE_PCI << 8;
|
||||
|
||||
/*
|
||||
* MPSS is not being set properly (as it is currently 0). This is
|
||||
* because that area of the PCI config space is hard coded to zero, and
|
||||
* is not modifiable by firmware. Set this to 2 (e.g., 512 byte MPS)
|
||||
* so that the MPS can be set to the real max value.
|
||||
*/
|
||||
pdev->pcie_mpss = 2;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16cd, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd750, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, quirk_paxc_bridge);
|
||||
|
||||
MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
|
||||
MODULE_DESCRIPTION("Broadcom iPROC PCIe common driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -98,9 +98,6 @@ struct vmd_dev {
|
|||
struct irq_domain *irq_domain;
|
||||
struct pci_bus *bus;
|
||||
u8 busn_start;
|
||||
|
||||
struct dma_map_ops dma_ops;
|
||||
struct dma_domain dma_domain;
|
||||
};
|
||||
|
||||
static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
|
||||
|
@ -295,151 +292,6 @@ static struct msi_domain_info vmd_msi_domain_info = {
|
|||
.chip = &vmd_msi_controller,
|
||||
};
|
||||
|
||||
/*
|
||||
* VMD replaces the requester ID with its own. DMA mappings for devices in a
|
||||
* VMD domain need to be mapped for the VMD, not the device requiring
|
||||
* the mapping.
|
||||
*/
|
||||
static struct device *to_vmd_dev(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct vmd_dev *vmd = vmd_from_bus(pdev->bus);
|
||||
|
||||
return &vmd->dev->dev;
|
||||
}
|
||||
|
||||
static void *vmd_alloc(struct device *dev, size_t size, dma_addr_t *addr,
|
||||
gfp_t flag, unsigned long attrs)
|
||||
{
|
||||
return dma_alloc_attrs(to_vmd_dev(dev), size, addr, flag, attrs);
|
||||
}
|
||||
|
||||
static void vmd_free(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t addr, unsigned long attrs)
|
||||
{
|
||||
return dma_free_attrs(to_vmd_dev(dev), size, vaddr, addr, attrs);
|
||||
}
|
||||
|
||||
static int vmd_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return dma_mmap_attrs(to_vmd_dev(dev), vma, cpu_addr, addr, size,
|
||||
attrs);
|
||||
}
|
||||
|
||||
static int vmd_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t addr, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return dma_get_sgtable_attrs(to_vmd_dev(dev), sgt, cpu_addr, addr, size,
|
||||
attrs);
|
||||
}
|
||||
|
||||
static dma_addr_t vmd_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return dma_map_page_attrs(to_vmd_dev(dev), page, offset, size, dir,
|
||||
attrs);
|
||||
}
|
||||
|
||||
static void vmd_unmap_page(struct device *dev, dma_addr_t addr, size_t size,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
dma_unmap_page_attrs(to_vmd_dev(dev), addr, size, dir, attrs);
|
||||
}
|
||||
|
||||
static int vmd_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
return dma_map_sg_attrs(to_vmd_dev(dev), sg, nents, dir, attrs);
|
||||
}
|
||||
|
||||
static void vmd_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
dma_unmap_sg_attrs(to_vmd_dev(dev), sg, nents, dir, attrs);
|
||||
}
|
||||
|
||||
static void vmd_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_for_cpu(to_vmd_dev(dev), addr, size, dir);
|
||||
}
|
||||
|
||||
static void vmd_sync_single_for_device(struct device *dev, dma_addr_t addr,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_for_device(to_vmd_dev(dev), addr, size, dir);
|
||||
}
|
||||
|
||||
static void vmd_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_sg_for_cpu(to_vmd_dev(dev), sg, nents, dir);
|
||||
}
|
||||
|
||||
static void vmd_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_sg_for_device(to_vmd_dev(dev), sg, nents, dir);
|
||||
}
|
||||
|
||||
static int vmd_dma_supported(struct device *dev, u64 mask)
|
||||
{
|
||||
return dma_supported(to_vmd_dev(dev), mask);
|
||||
}
|
||||
|
||||
static u64 vmd_get_required_mask(struct device *dev)
|
||||
{
|
||||
return dma_get_required_mask(to_vmd_dev(dev));
|
||||
}
|
||||
|
||||
static void vmd_teardown_dma_ops(struct vmd_dev *vmd)
|
||||
{
|
||||
struct dma_domain *domain = &vmd->dma_domain;
|
||||
|
||||
if (get_dma_ops(&vmd->dev->dev))
|
||||
del_dma_domain(domain);
|
||||
}
|
||||
|
||||
#define ASSIGN_VMD_DMA_OPS(source, dest, fn) \
|
||||
do { \
|
||||
if (source->fn) \
|
||||
dest->fn = vmd_##fn; \
|
||||
} while (0)
|
||||
|
||||
static void vmd_setup_dma_ops(struct vmd_dev *vmd)
|
||||
{
|
||||
const struct dma_map_ops *source = get_dma_ops(&vmd->dev->dev);
|
||||
struct dma_map_ops *dest = &vmd->dma_ops;
|
||||
struct dma_domain *domain = &vmd->dma_domain;
|
||||
|
||||
domain->domain_nr = vmd->sysdata.domain;
|
||||
domain->dma_ops = dest;
|
||||
|
||||
if (!source)
|
||||
return;
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, alloc);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, free);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, mmap);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, get_sgtable);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, map_page);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, unmap_page);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, map_sg);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, unmap_sg);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, sync_single_for_cpu);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, sync_single_for_device);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_cpu);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, sync_sg_for_device);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, dma_supported);
|
||||
ASSIGN_VMD_DMA_OPS(source, dest, get_required_mask);
|
||||
add_dma_domain(domain);
|
||||
}
|
||||
#undef ASSIGN_VMD_DMA_OPS
|
||||
|
||||
static char __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
|
||||
unsigned int devfn, int reg, int len)
|
||||
{
|
||||
|
@ -679,7 +531,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
|||
.parent = res,
|
||||
};
|
||||
|
||||
sd->vmd_domain = true;
|
||||
sd->vmd_dev = vmd->dev;
|
||||
sd->domain = vmd_find_free_domain();
|
||||
if (sd->domain < 0)
|
||||
return sd->domain;
|
||||
|
@ -709,7 +561,6 @@ static int vmd_enable_domain(struct vmd_dev *vmd, unsigned long features)
|
|||
}
|
||||
|
||||
vmd_attach_resources(vmd);
|
||||
vmd_setup_dma_ops(vmd);
|
||||
dev_set_msi_domain(&vmd->bus->dev, vmd->irq_domain);
|
||||
|
||||
pci_scan_child_bus(vmd->bus);
|
||||
|
@ -824,7 +675,6 @@ static void vmd_remove(struct pci_dev *dev)
|
|||
pci_stop_root_bus(vmd->bus);
|
||||
pci_remove_root_bus(vmd->bus);
|
||||
vmd_cleanup_srcu(vmd);
|
||||
vmd_teardown_dma_ops(vmd);
|
||||
vmd_detach_resources(vmd);
|
||||
irq_domain_remove(vmd->irq_domain);
|
||||
}
|
||||
|
@ -868,6 +718,10 @@ static const struct pci_device_id vmd_ids[] = {
|
|||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_28C0),
|
||||
.driver_data = VMD_FEAT_HAS_MEMBAR_SHADOW |
|
||||
VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x467f),
|
||||
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4c3d),
|
||||
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_VMD_9A0B),
|
||||
.driver_data = VMD_FEAT_HAS_BUS_RESTRICTIONS,},
|
||||
{0,}
|
||||
|
|
|
@ -186,10 +186,10 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|||
sprintf(buf, "virtfn%u", id);
|
||||
rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
|
||||
if (rc)
|
||||
goto failed2;
|
||||
goto failed1;
|
||||
rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
|
||||
if (rc)
|
||||
goto failed3;
|
||||
goto failed2;
|
||||
|
||||
kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
|
||||
|
||||
|
@ -197,11 +197,10 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
|
|||
|
||||
return 0;
|
||||
|
||||
failed3:
|
||||
sysfs_remove_link(&dev->dev.kobj, buf);
|
||||
failed2:
|
||||
pci_stop_and_remove_bus_device(virtfn);
|
||||
sysfs_remove_link(&dev->dev.kobj, buf);
|
||||
failed1:
|
||||
pci_stop_and_remove_bus_device(virtfn);
|
||||
pci_dev_put(dev);
|
||||
failed0:
|
||||
virtfn_remove_bus(dev->bus, bus);
|
||||
|
|
|
@ -289,6 +289,9 @@ static const struct pci_p2pdma_whitelist_entry {
|
|||
/* Intel Xeon E7 v3/Xeon E5 v3/Core i7 */
|
||||
{PCI_VENDOR_ID_INTEL, 0x2f00, REQ_SAME_HOST_BRIDGE},
|
||||
{PCI_VENDOR_ID_INTEL, 0x2f01, REQ_SAME_HOST_BRIDGE},
|
||||
/* Intel SkyLake-E */
|
||||
{PCI_VENDOR_ID_INTEL, 0x2030, 0},
|
||||
{PCI_VENDOR_ID_INTEL, 0x2020, 0},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -1372,8 +1372,11 @@ int pci_save_state(struct pci_dev *dev)
|
|||
{
|
||||
int i;
|
||||
/* XXX: 100% dword access ok here? */
|
||||
for (i = 0; i < 16; i++)
|
||||
for (i = 0; i < 16; i++) {
|
||||
pci_read_config_dword(dev, i * 4, &dev->saved_config_space[i]);
|
||||
pci_dbg(dev, "saving config space at offset %#x (reading %#x)\n",
|
||||
i * 4, dev->saved_config_space[i]);
|
||||
}
|
||||
dev->state_saved = true;
|
||||
|
||||
i = pci_save_pcie_state(dev);
|
||||
|
@ -5998,7 +6001,8 @@ EXPORT_SYMBOL_GPL(pci_pr3_present);
|
|||
/**
|
||||
* pci_add_dma_alias - Add a DMA devfn alias for a device
|
||||
* @dev: the PCI device for which alias is added
|
||||
* @devfn: alias slot and function
|
||||
* @devfn_from: alias slot and function
|
||||
* @nr_devfns: number of subsequent devfns to alias
|
||||
*
|
||||
* This helper encodes an 8-bit devfn as a bit number in dma_alias_mask
|
||||
* which is used to program permissible bus-devfn source addresses for DMA
|
||||
|
@ -6014,18 +6018,29 @@ EXPORT_SYMBOL_GPL(pci_pr3_present);
|
|||
* cannot be left as a userspace activity). DMA aliases should therefore
|
||||
* be configured via quirks, such as the PCI fixup header quirk.
|
||||
*/
|
||||
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn)
|
||||
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn_from, unsigned nr_devfns)
|
||||
{
|
||||
int devfn_to;
|
||||
|
||||
nr_devfns = min(nr_devfns, (unsigned) MAX_NR_DEVFNS - devfn_from);
|
||||
devfn_to = devfn_from + nr_devfns - 1;
|
||||
|
||||
if (!dev->dma_alias_mask)
|
||||
dev->dma_alias_mask = bitmap_zalloc(U8_MAX, GFP_KERNEL);
|
||||
dev->dma_alias_mask = bitmap_zalloc(MAX_NR_DEVFNS, GFP_KERNEL);
|
||||
if (!dev->dma_alias_mask) {
|
||||
pci_warn(dev, "Unable to allocate DMA alias mask\n");
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(devfn, dev->dma_alias_mask);
|
||||
pci_info(dev, "Enabling fixed DMA alias to %02x.%d\n",
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||
bitmap_set(dev->dma_alias_mask, devfn_from, nr_devfns);
|
||||
|
||||
if (nr_devfns == 1)
|
||||
pci_info(dev, "Enabling fixed DMA alias to %02x.%d\n",
|
||||
PCI_SLOT(devfn_from), PCI_FUNC(devfn_from));
|
||||
else if (nr_devfns > 1)
|
||||
pci_info(dev, "Enabling fixed DMA alias for devfn range from %02x.%d to %02x.%d\n",
|
||||
PCI_SLOT(devfn_from), PCI_FUNC(devfn_from),
|
||||
PCI_SLOT(devfn_to), PCI_FUNC(devfn_to));
|
||||
}
|
||||
|
||||
bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2)
|
||||
|
@ -6033,7 +6048,9 @@ bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2)
|
|||
return (dev1->dma_alias_mask &&
|
||||
test_bit(dev2->devfn, dev1->dma_alias_mask)) ||
|
||||
(dev2->dma_alias_mask &&
|
||||
test_bit(dev1->devfn, dev2->dma_alias_mask));
|
||||
test_bit(dev1->devfn, dev2->dma_alias_mask)) ||
|
||||
pci_real_dma_dev(dev1) == dev2 ||
|
||||
pci_real_dma_dev(dev2) == dev1;
|
||||
}
|
||||
|
||||
bool pci_device_is_present(struct pci_dev *pdev)
|
||||
|
@ -6057,6 +6074,21 @@ void pci_ignore_hotplug(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pci_ignore_hotplug);
|
||||
|
||||
/**
|
||||
* pci_real_dma_dev - Get PCI DMA device for PCI device
|
||||
* @dev: the PCI device that may have a PCI DMA alias
|
||||
*
|
||||
* Permits the platform to provide architecture-specific functionality to
|
||||
* devices needing to alias DMA to another PCI device on another PCI bus. If
|
||||
* the PCI device is on the same bus, it is recommended to use
|
||||
* pci_add_dma_alias(). This is the default implementation. Architecture
|
||||
* implementations can override this.
|
||||
*/
|
||||
struct pci_dev __weak *pci_real_dma_dev(struct pci_dev *dev)
|
||||
{
|
||||
return dev;
|
||||
}
|
||||
|
||||
resource_size_t __weak pcibios_default_alignment(void)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* Number of possible devfns: 0.0 to 1f.7 inclusive */
|
||||
#define MAX_NR_DEVFNS 256
|
||||
|
||||
#define PCI_FIND_CAP_TTL 48
|
||||
|
||||
#define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */
|
||||
|
|
|
@ -1445,6 +1445,7 @@ static int aer_probe(struct pcie_device *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
rpc->rpd = port;
|
||||
INIT_KFIFO(rpc->aer_fifo);
|
||||
set_service_data(dev, rpc);
|
||||
|
||||
status = devm_request_threaded_irq(device, dev->irq, aer_irq, aer_isr,
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
* Zhang Yanmin (yanmin.zhang@intel.com)
|
||||
*/
|
||||
|
||||
#define dev_fmt(fmt) "AER: " fmt
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -61,10 +63,12 @@ static int report_error_detected(struct pci_dev *dev,
|
|||
* error callbacks of "any" device in the subtree, and will
|
||||
* exit in the disconnected error state.
|
||||
*/
|
||||
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
|
||||
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
|
||||
vote = PCI_ERS_RESULT_NO_AER_DRIVER;
|
||||
else
|
||||
pci_info(dev, "can't recover (no error_detected callback)\n");
|
||||
} else {
|
||||
vote = PCI_ERS_RESULT_NONE;
|
||||
}
|
||||
} else {
|
||||
err_handler = dev->driver->err_handler;
|
||||
vote = err_handler->error_detected(dev, state);
|
||||
|
@ -233,12 +237,12 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
|
|||
|
||||
pci_aer_clear_device_status(dev);
|
||||
pci_cleanup_aer_uncorrect_error_status(dev);
|
||||
pci_info(dev, "AER: Device recovery successful\n");
|
||||
pci_info(dev, "device recovery successful\n");
|
||||
return;
|
||||
|
||||
failed:
|
||||
pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT);
|
||||
|
||||
/* TODO: Should kernel panic here? */
|
||||
pci_info(dev, "AER: Device recovery failed\n");
|
||||
pci_info(dev, "device recovery failed\n");
|
||||
}
|
||||
|
|
|
@ -1871,19 +1871,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
|
|||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
|
||||
|
||||
static void quirk_d3hot_delay(struct pci_dev *dev, unsigned int delay)
|
||||
{
|
||||
if (dev->d3_delay >= delay)
|
||||
return;
|
||||
|
||||
dev->d3_delay = delay;
|
||||
pci_info(dev, "extending delay after power-on from D3hot to %d msec\n",
|
||||
dev->d3_delay);
|
||||
}
|
||||
|
||||
static void quirk_radeon_pm(struct pci_dev *dev)
|
||||
{
|
||||
if (dev->subsystem_vendor == PCI_VENDOR_ID_APPLE &&
|
||||
dev->subsystem_device == 0x00e2) {
|
||||
if (dev->d3_delay < 20) {
|
||||
dev->d3_delay = 20;
|
||||
pci_info(dev, "extending delay after power-on from D3 to %d msec\n",
|
||||
dev->d3_delay);
|
||||
}
|
||||
}
|
||||
dev->subsystem_device == 0x00e2)
|
||||
quirk_d3hot_delay(dev, 20);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6741, quirk_radeon_pm);
|
||||
|
||||
/*
|
||||
* Ryzen5/7 XHCI controllers fail upon resume from runtime suspend or s2idle.
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=205587
|
||||
*
|
||||
* The kernel attempts to transition these devices to D3cold, but that seems
|
||||
* to be ineffective on the platforms in question; the PCI device appears to
|
||||
* remain on in D3hot state. The D3hot-to-D0 transition then requires an
|
||||
* extended delay in order to succeed.
|
||||
*/
|
||||
static void quirk_ryzen_xhci_d3hot(struct pci_dev *dev)
|
||||
{
|
||||
quirk_d3hot_delay(dev, 20);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15e0, quirk_ryzen_xhci_d3hot);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15e1, quirk_ryzen_xhci_d3hot);
|
||||
|
||||
#ifdef CONFIG_X86_IO_APIC
|
||||
static int dmi_disable_ioapicreroute(const struct dmi_system_id *d)
|
||||
{
|
||||
|
@ -2381,32 +2402,6 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_BROADCOM,
|
|||
PCI_DEVICE_ID_TIGON3_5719,
|
||||
quirk_brcm_5719_limit_mrrs);
|
||||
|
||||
#ifdef CONFIG_PCIE_IPROC_PLATFORM
|
||||
static void quirk_paxc_bridge(struct pci_dev *pdev)
|
||||
{
|
||||
/*
|
||||
* The PCI config space is shared with the PAXC root port and the first
|
||||
* Ethernet device. So, we need to workaround this by telling the PCI
|
||||
* code that the bridge is not an Ethernet device.
|
||||
*/
|
||||
if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
|
||||
pdev->class = PCI_CLASS_BRIDGE_PCI << 8;
|
||||
|
||||
/*
|
||||
* MPSS is not being set properly (as it is currently 0). This is
|
||||
* because that area of the PCI config space is hard coded to zero, and
|
||||
* is not modifiable by firmware. Set this to 2 (e.g., 512 byte MPS)
|
||||
* so that the MPS can be set to the real max value.
|
||||
*/
|
||||
pdev->pcie_mpss = 2;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16cd, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x16f0, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd750, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd802, quirk_paxc_bridge);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0xd804, quirk_paxc_bridge);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Originally in EDAC sources for i82875P: Intel tells BIOS developers to
|
||||
* hide device 6 which configures the overflow device access containing the
|
||||
|
@ -3932,7 +3927,7 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
|
|||
static void quirk_dma_func0_alias(struct pci_dev *dev)
|
||||
{
|
||||
if (PCI_FUNC(dev->devfn) != 0)
|
||||
pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
|
||||
pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 0), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3946,7 +3941,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_RICOH, 0xe476, quirk_dma_func0_alias);
|
|||
static void quirk_dma_func1_alias(struct pci_dev *dev)
|
||||
{
|
||||
if (PCI_FUNC(dev->devfn) != 1)
|
||||
pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
|
||||
pci_add_dma_alias(dev, PCI_DEVFN(PCI_SLOT(dev->devfn), 1), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4031,7 +4026,7 @@ static void quirk_fixed_dma_alias(struct pci_dev *dev)
|
|||
|
||||
id = pci_match_id(fixed_dma_alias_tbl, dev);
|
||||
if (id)
|
||||
pci_add_dma_alias(dev, id->driver_data);
|
||||
pci_add_dma_alias(dev, id->driver_data, 1);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
|
||||
|
||||
|
@ -4072,9 +4067,9 @@ DECLARE_PCI_FIXUP_HEADER(0x8086, 0x244e, quirk_use_pcie_bridge_dma_alias);
|
|||
*/
|
||||
static void quirk_mic_x200_dma_alias(struct pci_dev *pdev)
|
||||
{
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x10, 0x0), 1);
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x11, 0x0), 1);
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(0x12, 0x3), 1);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias);
|
||||
|
@ -4098,13 +4093,8 @@ static void quirk_pex_vca_alias(struct pci_dev *pdev)
|
|||
const unsigned int num_pci_slots = 0x20;
|
||||
unsigned int slot;
|
||||
|
||||
for (slot = 0; slot < num_pci_slots; slot++) {
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x1));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x2));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x3));
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x4));
|
||||
}
|
||||
for (slot = 0; slot < num_pci_slots; slot++)
|
||||
pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0), 5);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2954, quirk_pex_vca_alias);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2955, quirk_pex_vca_alias);
|
||||
|
@ -5339,7 +5329,7 @@ static void quirk_switchtec_ntb_dma_alias(struct pci_dev *pdev)
|
|||
pci_dbg(pdev,
|
||||
"Aliasing Partition %d Proxy ID %02x.%d\n",
|
||||
pp, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
||||
pci_add_dma_alias(pdev, devfn);
|
||||
pci_add_dma_alias(pdev, devfn, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5380,6 +5370,39 @@ SWITCHTEC_QUIRK(0x8573); /* PFXI 48XG3 */
|
|||
SWITCHTEC_QUIRK(0x8574); /* PFXI 64XG3 */
|
||||
SWITCHTEC_QUIRK(0x8575); /* PFXI 80XG3 */
|
||||
SWITCHTEC_QUIRK(0x8576); /* PFXI 96XG3 */
|
||||
SWITCHTEC_QUIRK(0x4000); /* PFX 100XG4 */
|
||||
SWITCHTEC_QUIRK(0x4084); /* PFX 84XG4 */
|
||||
SWITCHTEC_QUIRK(0x4068); /* PFX 68XG4 */
|
||||
SWITCHTEC_QUIRK(0x4052); /* PFX 52XG4 */
|
||||
SWITCHTEC_QUIRK(0x4036); /* PFX 36XG4 */
|
||||
SWITCHTEC_QUIRK(0x4028); /* PFX 28XG4 */
|
||||
SWITCHTEC_QUIRK(0x4100); /* PSX 100XG4 */
|
||||
SWITCHTEC_QUIRK(0x4184); /* PSX 84XG4 */
|
||||
SWITCHTEC_QUIRK(0x4168); /* PSX 68XG4 */
|
||||
SWITCHTEC_QUIRK(0x4152); /* PSX 52XG4 */
|
||||
SWITCHTEC_QUIRK(0x4136); /* PSX 36XG4 */
|
||||
SWITCHTEC_QUIRK(0x4128); /* PSX 28XG4 */
|
||||
SWITCHTEC_QUIRK(0x4200); /* PAX 100XG4 */
|
||||
SWITCHTEC_QUIRK(0x4284); /* PAX 84XG4 */
|
||||
SWITCHTEC_QUIRK(0x4268); /* PAX 68XG4 */
|
||||
SWITCHTEC_QUIRK(0x4252); /* PAX 52XG4 */
|
||||
SWITCHTEC_QUIRK(0x4236); /* PAX 36XG4 */
|
||||
SWITCHTEC_QUIRK(0x4228); /* PAX 28XG4 */
|
||||
|
||||
/*
|
||||
* The PLX NTB uses devfn proxy IDs to move TLPs between NT endpoints.
|
||||
* These IDs are used to forward responses to the originator on the other
|
||||
* side of the NTB. Alias all possible IDs to the NTB to permit access when
|
||||
* the IOMMU is turned on.
|
||||
*/
|
||||
static void quirk_plx_ntb_dma_alias(struct pci_dev *pdev)
|
||||
{
|
||||
pci_info(pdev, "Setting PLX NTB proxy ID aliases\n");
|
||||
/* PLX NTB may use all 256 devfns */
|
||||
pci_add_dma_alias(pdev, 0, 256);
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, 0x87b0, quirk_plx_ntb_dma_alias);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_PLX, 0x87b1, quirk_plx_ntb_dma_alias);
|
||||
|
||||
/*
|
||||
* On Lenovo Thinkpad P50 SKUs with a Nvidia Quadro M1000M, the BIOS does
|
||||
|
|
|
@ -32,6 +32,12 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
|
|||
struct pci_bus *bus;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The device may have an explicit alias requester ID for DMA where the
|
||||
* requester is on another PCI bus.
|
||||
*/
|
||||
pdev = pci_real_dma_dev(pdev);
|
||||
|
||||
ret = fn(pdev, pci_dev_id(pdev), data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -41,9 +47,9 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
|
|||
* DMA, iterate over that too.
|
||||
*/
|
||||
if (unlikely(pdev->dma_alias_mask)) {
|
||||
u8 devfn;
|
||||
unsigned int devfn;
|
||||
|
||||
for_each_set_bit(devfn, pdev->dma_alias_mask, U8_MAX) {
|
||||
for_each_set_bit(devfn, pdev->dma_alias_mask, MAX_NR_DEVFNS) {
|
||||
ret = fn(pdev, PCI_DEVID(pdev->bus->number, devfn),
|
||||
data);
|
||||
if (ret)
|
||||
|
|
|
@ -1803,12 +1803,18 @@ again:
|
|||
/* Restore size and flags */
|
||||
list_for_each_entry(fail_res, &fail_head, list) {
|
||||
struct resource *res = fail_res->res;
|
||||
int idx;
|
||||
|
||||
res->start = fail_res->start;
|
||||
res->end = fail_res->end;
|
||||
res->flags = fail_res->flags;
|
||||
if (fail_res->dev->subordinate)
|
||||
res->flags = 0;
|
||||
|
||||
if (pci_is_bridge(fail_res->dev)) {
|
||||
idx = res - &fail_res->dev->resource[0];
|
||||
if (idx >= PCI_BRIDGE_RESOURCES &&
|
||||
idx <= PCI_BRIDGE_RESOURCE_END)
|
||||
res->flags = 0;
|
||||
}
|
||||
}
|
||||
free_list(&fail_head);
|
||||
|
||||
|
@ -1832,56 +1838,72 @@ void __init pci_assign_unassigned_resources(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void extend_bridge_window(struct pci_dev *bridge, struct resource *res,
|
||||
static void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
|
||||
struct list_head *add_list,
|
||||
resource_size_t available)
|
||||
resource_size_t new_size)
|
||||
{
|
||||
struct pci_dev_resource *dev_res;
|
||||
resource_size_t add_size, size = resource_size(res);
|
||||
|
||||
if (res->parent)
|
||||
return;
|
||||
|
||||
if (resource_size(res) >= available)
|
||||
if (!new_size)
|
||||
return;
|
||||
|
||||
dev_res = res_to_dev_res(add_list, res);
|
||||
if (!dev_res)
|
||||
return;
|
||||
if (new_size > size) {
|
||||
add_size = new_size - size;
|
||||
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
|
||||
&add_size);
|
||||
} else if (new_size < size) {
|
||||
add_size = size - new_size;
|
||||
pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
|
||||
&add_size);
|
||||
}
|
||||
|
||||
/* Is there room to extend the window? */
|
||||
if (available - resource_size(res) <= dev_res->add_size)
|
||||
return;
|
||||
|
||||
dev_res->add_size = available - resource_size(res);
|
||||
pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
|
||||
&dev_res->add_size);
|
||||
res->end = res->start + new_size - 1;
|
||||
remove_from_list(add_list, res);
|
||||
}
|
||||
|
||||
static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
struct list_head *add_list,
|
||||
resource_size_t available_io,
|
||||
resource_size_t available_mmio,
|
||||
resource_size_t available_mmio_pref)
|
||||
struct resource io,
|
||||
struct resource mmio,
|
||||
struct resource mmio_pref)
|
||||
{
|
||||
resource_size_t remaining_io, remaining_mmio, remaining_mmio_pref;
|
||||
unsigned int normal_bridges = 0, hotplug_bridges = 0;
|
||||
struct resource *io_res, *mmio_res, *mmio_pref_res;
|
||||
struct pci_dev *dev, *bridge = bus->self;
|
||||
resource_size_t io_per_hp, mmio_per_hp, mmio_pref_per_hp, align;
|
||||
|
||||
io_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
mmio_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
mmio_pref_res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
|
||||
/*
|
||||
* Update additional resource list (add_list) to fill all the
|
||||
* extra resource space available for this port except the space
|
||||
* calculated in __pci_bus_size_bridges() which covers all the
|
||||
* devices currently connected to the port and below.
|
||||
* The alignment of this bridge is yet to be considered, hence it must
|
||||
* be done now before extending its bridge window.
|
||||
*/
|
||||
extend_bridge_window(bridge, io_res, add_list, available_io);
|
||||
extend_bridge_window(bridge, mmio_res, add_list, available_mmio);
|
||||
extend_bridge_window(bridge, mmio_pref_res, add_list,
|
||||
available_mmio_pref);
|
||||
align = pci_resource_alignment(bridge, io_res);
|
||||
if (!io_res->parent && align)
|
||||
io.start = min(ALIGN(io.start, align), io.end + 1);
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_res);
|
||||
if (!mmio_res->parent && align)
|
||||
mmio.start = min(ALIGN(mmio.start, align), mmio.end + 1);
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
if (!mmio_pref_res->parent && align)
|
||||
mmio_pref.start = min(ALIGN(mmio_pref.start, align),
|
||||
mmio_pref.end + 1);
|
||||
|
||||
/*
|
||||
* Now that we have adjusted for alignment, update the bridge window
|
||||
* resources to fill as much remaining resource space as possible.
|
||||
*/
|
||||
adjust_bridge_window(bridge, io_res, add_list, resource_size(&io));
|
||||
adjust_bridge_window(bridge, mmio_res, add_list, resource_size(&mmio));
|
||||
adjust_bridge_window(bridge, mmio_pref_res, add_list,
|
||||
resource_size(&mmio_pref));
|
||||
|
||||
/*
|
||||
* Calculate how many hotplug bridges and normal bridges there
|
||||
|
@ -1902,11 +1924,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
|||
*/
|
||||
if (hotplug_bridges + normal_bridges == 1) {
|
||||
dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
|
||||
if (dev->subordinate) {
|
||||
if (dev->subordinate)
|
||||
pci_bus_distribute_available_resources(dev->subordinate,
|
||||
add_list, available_io, available_mmio,
|
||||
available_mmio_pref);
|
||||
}
|
||||
add_list, io, mmio, mmio_pref);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1919,12 +1939,9 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
|||
* extra space reduced by the minimal required space for the
|
||||
* non-hotplug bridges.
|
||||
*/
|
||||
remaining_io = available_io;
|
||||
remaining_mmio = available_mmio;
|
||||
remaining_mmio_pref = available_mmio_pref;
|
||||
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
const struct resource *res;
|
||||
resource_size_t used_size;
|
||||
struct resource *res;
|
||||
|
||||
if (dev->is_hotplug_bridge)
|
||||
continue;
|
||||
|
@ -1934,24 +1951,39 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
|||
* bridge and devices below it occupy.
|
||||
*/
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
if (!res->parent && available_io > resource_size(res))
|
||||
remaining_io -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(io.start, align) - io.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
io.start = min(io.start + used_size, io.end + 1);
|
||||
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
if (!res->parent && available_mmio > resource_size(res))
|
||||
remaining_mmio -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(mmio.start, align) - mmio.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
mmio.start = min(mmio.start + used_size, mmio.end + 1);
|
||||
|
||||
res = &dev->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
if (!res->parent && available_mmio_pref > resource_size(res))
|
||||
remaining_mmio_pref -= resource_size(res);
|
||||
align = pci_resource_alignment(dev, res);
|
||||
align = align ? ALIGN(mmio_pref.start, align) -
|
||||
mmio_pref.start : 0;
|
||||
used_size = align + resource_size(res);
|
||||
if (!res->parent)
|
||||
mmio_pref.start = min(mmio_pref.start + used_size,
|
||||
mmio_pref.end + 1);
|
||||
}
|
||||
|
||||
io_per_hp = div64_ul(resource_size(&io), hotplug_bridges);
|
||||
mmio_per_hp = div64_ul(resource_size(&mmio), hotplug_bridges);
|
||||
mmio_pref_per_hp = div64_ul(resource_size(&mmio_pref),
|
||||
hotplug_bridges);
|
||||
|
||||
/*
|
||||
* Go over devices on this bus and distribute the remaining
|
||||
* resource space between hotplug bridges.
|
||||
*/
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
resource_size_t align, io, mmio, mmio_pref;
|
||||
struct pci_bus *b;
|
||||
|
||||
b = dev->subordinate;
|
||||
|
@ -1963,42 +1995,31 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
|||
* hotplug-capable downstream ports taking alignment into
|
||||
* account.
|
||||
*/
|
||||
align = pci_resource_alignment(bridge, io_res);
|
||||
io = div64_ul(available_io, hotplug_bridges);
|
||||
io = min(ALIGN(io, align), remaining_io);
|
||||
remaining_io -= io;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_res);
|
||||
mmio = div64_ul(available_mmio, hotplug_bridges);
|
||||
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
||||
remaining_mmio -= mmio;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
mmio_pref = div64_ul(available_mmio_pref, hotplug_bridges);
|
||||
mmio_pref = min(ALIGN(mmio_pref, align), remaining_mmio_pref);
|
||||
remaining_mmio_pref -= mmio_pref;
|
||||
io.end = io.start + io_per_hp - 1;
|
||||
mmio.end = mmio.start + mmio_per_hp - 1;
|
||||
mmio_pref.end = mmio_pref.start + mmio_pref_per_hp - 1;
|
||||
|
||||
pci_bus_distribute_available_resources(b, add_list, io, mmio,
|
||||
mmio_pref);
|
||||
|
||||
io.start += io_per_hp;
|
||||
mmio.start += mmio_per_hp;
|
||||
mmio_pref.start += mmio_pref_per_hp;
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
|
||||
struct list_head *add_list)
|
||||
{
|
||||
resource_size_t available_io, available_mmio, available_mmio_pref;
|
||||
const struct resource *res;
|
||||
struct resource available_io, available_mmio, available_mmio_pref;
|
||||
|
||||
if (!bridge->is_hotplug_bridge)
|
||||
return;
|
||||
|
||||
/* Take the initial extra resources from the hotplug port */
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
available_io = resource_size(res);
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
available_mmio = resource_size(res);
|
||||
res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
available_mmio_pref = resource_size(res);
|
||||
available_io = bridge->resource[PCI_BRIDGE_RESOURCES + 0];
|
||||
available_mmio = bridge->resource[PCI_BRIDGE_RESOURCES + 1];
|
||||
available_mmio_pref = bridge->resource[PCI_BRIDGE_RESOURCES + 2];
|
||||
|
||||
pci_bus_distribute_available_resources(bridge->subordinate,
|
||||
add_list, available_io,
|
||||
|
@ -2055,12 +2076,18 @@ again:
|
|||
/* Restore size and flags */
|
||||
list_for_each_entry(fail_res, &fail_head, list) {
|
||||
struct resource *res = fail_res->res;
|
||||
int idx;
|
||||
|
||||
res->start = fail_res->start;
|
||||
res->end = fail_res->end;
|
||||
res->flags = fail_res->flags;
|
||||
if (fail_res->dev->subordinate)
|
||||
res->flags = 0;
|
||||
|
||||
if (pci_is_bridge(fail_res->dev)) {
|
||||
idx = res - &fail_res->dev->resource[0];
|
||||
if (idx >= PCI_BRIDGE_RESOURCES &&
|
||||
idx <= PCI_BRIDGE_RESOURCE_END)
|
||||
res->flags = 0;
|
||||
}
|
||||
}
|
||||
free_list(&fail_head);
|
||||
|
||||
|
|
|
@ -317,8 +317,15 @@ static ssize_t field ## _show(struct device *dev, \
|
|||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct switchtec_dev *stdev = to_stdev(dev); \
|
||||
return io_string_show(buf, &stdev->mmio_sys_info->field, \
|
||||
sizeof(stdev->mmio_sys_info->field)); \
|
||||
struct sys_info_regs __iomem *si = stdev->mmio_sys_info; \
|
||||
if (stdev->gen == SWITCHTEC_GEN3) \
|
||||
return io_string_show(buf, &si->gen3.field, \
|
||||
sizeof(si->gen3.field)); \
|
||||
else if (stdev->gen == SWITCHTEC_GEN4) \
|
||||
return io_string_show(buf, &si->gen4.field, \
|
||||
sizeof(si->gen4.field)); \
|
||||
else \
|
||||
return -ENOTSUPP; \
|
||||
} \
|
||||
\
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
@ -326,13 +333,31 @@ static DEVICE_ATTR_RO(field)
|
|||
DEVICE_ATTR_SYS_INFO_STR(vendor_id);
|
||||
DEVICE_ATTR_SYS_INFO_STR(product_id);
|
||||
DEVICE_ATTR_SYS_INFO_STR(product_revision);
|
||||
DEVICE_ATTR_SYS_INFO_STR(component_vendor);
|
||||
|
||||
static ssize_t component_vendor_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct switchtec_dev *stdev = to_stdev(dev);
|
||||
struct sys_info_regs __iomem *si = stdev->mmio_sys_info;
|
||||
|
||||
/* component_vendor field not supported after gen3 */
|
||||
if (stdev->gen != SWITCHTEC_GEN3)
|
||||
return sprintf(buf, "none\n");
|
||||
|
||||
return io_string_show(buf, &si->gen3.component_vendor,
|
||||
sizeof(si->gen3.component_vendor));
|
||||
}
|
||||
static DEVICE_ATTR_RO(component_vendor);
|
||||
|
||||
static ssize_t component_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct switchtec_dev *stdev = to_stdev(dev);
|
||||
int id = ioread16(&stdev->mmio_sys_info->component_id);
|
||||
int id = ioread16(&stdev->mmio_sys_info->gen3.component_id);
|
||||
|
||||
/* component_id field not supported after gen3 */
|
||||
if (stdev->gen != SWITCHTEC_GEN3)
|
||||
return sprintf(buf, "none\n");
|
||||
|
||||
return sprintf(buf, "PM%04X\n", id);
|
||||
}
|
||||
|
@ -342,7 +367,11 @@ static ssize_t component_revision_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct switchtec_dev *stdev = to_stdev(dev);
|
||||
int rev = ioread8(&stdev->mmio_sys_info->component_revision);
|
||||
int rev = ioread8(&stdev->mmio_sys_info->gen3.component_revision);
|
||||
|
||||
/* component_revision field not supported after gen3 */
|
||||
if (stdev->gen != SWITCHTEC_GEN3)
|
||||
return sprintf(buf, "255\n");
|
||||
|
||||
return sprintf(buf, "%d\n", rev);
|
||||
}
|
||||
|
@ -450,6 +479,12 @@ static ssize_t switchtec_dev_write(struct file *filp, const char __user *data,
|
|||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (((MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_WRITE) ||
|
||||
(MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_READ)) &&
|
||||
!capable(CAP_SYS_ADMIN)) {
|
||||
rc = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
data += sizeof(stuser->cmd);
|
||||
rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd));
|
||||
|
@ -568,8 +603,15 @@ static int ioctl_flash_info(struct switchtec_dev *stdev,
|
|||
struct switchtec_ioctl_flash_info info = {0};
|
||||
struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;
|
||||
|
||||
info.flash_length = ioread32(&fi->flash_length);
|
||||
info.num_partitions = SWITCHTEC_IOCTL_NUM_PARTITIONS;
|
||||
if (stdev->gen == SWITCHTEC_GEN3) {
|
||||
info.flash_length = ioread32(&fi->gen3.flash_length);
|
||||
info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN3;
|
||||
} else if (stdev->gen == SWITCHTEC_GEN4) {
|
||||
info.flash_length = ioread32(&fi->gen4.flash_length);
|
||||
info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN4;
|
||||
} else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (copy_to_user(uinfo, &info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
|
@ -584,75 +626,200 @@ static void set_fw_info_part(struct switchtec_ioctl_flash_part_info *info,
|
|||
info->length = ioread32(&pi->length);
|
||||
}
|
||||
|
||||
static int ioctl_flash_part_info(struct switchtec_dev *stdev,
|
||||
struct switchtec_ioctl_flash_part_info __user *uinfo)
|
||||
static int flash_part_info_gen3(struct switchtec_dev *stdev,
|
||||
struct switchtec_ioctl_flash_part_info *info)
|
||||
{
|
||||
struct switchtec_ioctl_flash_part_info info = {0};
|
||||
struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;
|
||||
struct sys_info_regs __iomem *si = stdev->mmio_sys_info;
|
||||
struct flash_info_regs_gen3 __iomem *fi =
|
||||
&stdev->mmio_flash_info->gen3;
|
||||
struct sys_info_regs_gen3 __iomem *si = &stdev->mmio_sys_info->gen3;
|
||||
u32 active_addr = -1;
|
||||
|
||||
if (copy_from_user(&info, uinfo, sizeof(info)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (info.flash_partition) {
|
||||
switch (info->flash_partition) {
|
||||
case SWITCHTEC_IOCTL_PART_CFG0:
|
||||
active_addr = ioread32(&fi->active_cfg);
|
||||
set_fw_info_part(&info, &fi->cfg0);
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_CFG0_RUNNING)
|
||||
info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
set_fw_info_part(info, &fi->cfg0);
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_CFG1:
|
||||
active_addr = ioread32(&fi->active_cfg);
|
||||
set_fw_info_part(&info, &fi->cfg1);
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_CFG1_RUNNING)
|
||||
info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
set_fw_info_part(info, &fi->cfg1);
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_IMG0:
|
||||
active_addr = ioread32(&fi->active_img);
|
||||
set_fw_info_part(&info, &fi->img0);
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_IMG0_RUNNING)
|
||||
info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
set_fw_info_part(info, &fi->img0);
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_IMG1:
|
||||
active_addr = ioread32(&fi->active_img);
|
||||
set_fw_info_part(&info, &fi->img1);
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_IMG1_RUNNING)
|
||||
info.active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
set_fw_info_part(info, &fi->img1);
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_NVLOG:
|
||||
set_fw_info_part(&info, &fi->nvlog);
|
||||
set_fw_info_part(info, &fi->nvlog);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR0:
|
||||
set_fw_info_part(&info, &fi->vendor[0]);
|
||||
set_fw_info_part(info, &fi->vendor[0]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR1:
|
||||
set_fw_info_part(&info, &fi->vendor[1]);
|
||||
set_fw_info_part(info, &fi->vendor[1]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR2:
|
||||
set_fw_info_part(&info, &fi->vendor[2]);
|
||||
set_fw_info_part(info, &fi->vendor[2]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR3:
|
||||
set_fw_info_part(&info, &fi->vendor[3]);
|
||||
set_fw_info_part(info, &fi->vendor[3]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR4:
|
||||
set_fw_info_part(&info, &fi->vendor[4]);
|
||||
set_fw_info_part(info, &fi->vendor[4]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR5:
|
||||
set_fw_info_part(&info, &fi->vendor[5]);
|
||||
set_fw_info_part(info, &fi->vendor[5]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR6:
|
||||
set_fw_info_part(&info, &fi->vendor[6]);
|
||||
set_fw_info_part(info, &fi->vendor[6]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR7:
|
||||
set_fw_info_part(&info, &fi->vendor[7]);
|
||||
set_fw_info_part(info, &fi->vendor[7]);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info.address == active_addr)
|
||||
info.active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (info->address == active_addr)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_part_info_gen4(struct switchtec_dev *stdev,
|
||||
struct switchtec_ioctl_flash_part_info *info)
|
||||
{
|
||||
struct flash_info_regs_gen4 __iomem *fi = &stdev->mmio_flash_info->gen4;
|
||||
struct sys_info_regs_gen4 __iomem *si = &stdev->mmio_sys_info->gen4;
|
||||
struct active_partition_info_gen4 __iomem *af = &fi->active_flag;
|
||||
|
||||
switch (info->flash_partition) {
|
||||
case SWITCHTEC_IOCTL_PART_MAP_0:
|
||||
set_fw_info_part(info, &fi->map0);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_MAP_1:
|
||||
set_fw_info_part(info, &fi->map1);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_KEY_0:
|
||||
set_fw_info_part(info, &fi->key0);
|
||||
if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY0_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_KEY_1:
|
||||
set_fw_info_part(info, &fi->key1);
|
||||
if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY1_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_BL2_0:
|
||||
set_fw_info_part(info, &fi->bl2_0);
|
||||
if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_0_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_BL2_1:
|
||||
set_fw_info_part(info, &fi->bl2_1);
|
||||
if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_1_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_CFG0:
|
||||
set_fw_info_part(info, &fi->cfg0);
|
||||
if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG0_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_CFG1:
|
||||
set_fw_info_part(info, &fi->cfg1);
|
||||
if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG1_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_IMG0:
|
||||
set_fw_info_part(info, &fi->img0);
|
||||
if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG0_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG0_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_IMG1:
|
||||
set_fw_info_part(info, &fi->img1);
|
||||
if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG1_ACTIVE)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;
|
||||
if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG1_RUNNING)
|
||||
info->active |= SWITCHTEC_IOCTL_PART_RUNNING;
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_NVLOG:
|
||||
set_fw_info_part(info, &fi->nvlog);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR0:
|
||||
set_fw_info_part(info, &fi->vendor[0]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR1:
|
||||
set_fw_info_part(info, &fi->vendor[1]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR2:
|
||||
set_fw_info_part(info, &fi->vendor[2]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR3:
|
||||
set_fw_info_part(info, &fi->vendor[3]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR4:
|
||||
set_fw_info_part(info, &fi->vendor[4]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR5:
|
||||
set_fw_info_part(info, &fi->vendor[5]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR6:
|
||||
set_fw_info_part(info, &fi->vendor[6]);
|
||||
break;
|
||||
case SWITCHTEC_IOCTL_PART_VENDOR7:
|
||||
set_fw_info_part(info, &fi->vendor[7]);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioctl_flash_part_info(struct switchtec_dev *stdev,
|
||||
struct switchtec_ioctl_flash_part_info __user *uinfo)
|
||||
{
|
||||
int ret;
|
||||
struct switchtec_ioctl_flash_part_info info = {0};
|
||||
|
||||
if (copy_from_user(&info, uinfo, sizeof(info)))
|
||||
return -EFAULT;
|
||||
|
||||
if (stdev->gen == SWITCHTEC_GEN3) {
|
||||
ret = flash_part_info_gen3(stdev, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (stdev->gen == SWITCHTEC_GEN4) {
|
||||
ret = flash_part_info_gen4(stdev, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (copy_to_user(uinfo, &info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
|
@ -683,11 +850,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev,
|
|||
s->part[i] = reg;
|
||||
}
|
||||
|
||||
for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {
|
||||
reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);
|
||||
if (reg != PCI_VENDOR_ID_MICROSEMI)
|
||||
break;
|
||||
|
||||
for (i = 0; i < stdev->pff_csr_count; i++) {
|
||||
reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary);
|
||||
s->pff[i] = reg;
|
||||
}
|
||||
|
@ -751,10 +914,13 @@ static const struct event_reg {
|
|||
EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP, mrpc_comp_hdr),
|
||||
EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC, mrpc_comp_async_hdr),
|
||||
EV_PAR(SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP, dyn_binding_hdr),
|
||||
EV_PAR(SWITCHTEC_IOCTL_EVENT_INTERCOMM_REQ_NOTIFY,
|
||||
intercomm_notify_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_P2P, aer_in_p2p_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_VEP, aer_in_vep_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_DPC, dpc_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_CTS, cts_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_UEC, uec_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_HOTPLUG, hotplug_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_IER, ier_hdr),
|
||||
EV_PFF(SWITCHTEC_IOCTL_EVENT_THRESH, threshold_hdr),
|
||||
|
@ -1181,10 +1347,6 @@ static int mask_event(struct switchtec_dev *stdev, int eid, int idx)
|
|||
if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))
|
||||
return 0;
|
||||
|
||||
if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE ||
|
||||
eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP)
|
||||
return 0;
|
||||
|
||||
dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr);
|
||||
hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED);
|
||||
iowrite32(hdr, hdr_reg);
|
||||
|
@ -1231,8 +1393,13 @@ static irqreturn_t switchtec_event_isr(int irq, void *dev)
|
|||
|
||||
check_link_state_events(stdev);
|
||||
|
||||
for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++)
|
||||
for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++) {
|
||||
if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE ||
|
||||
eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP)
|
||||
continue;
|
||||
|
||||
event_count += mask_all_events(stdev, eid);
|
||||
}
|
||||
|
||||
if (event_count) {
|
||||
atomic_inc(&stdev->event_cnt);
|
||||
|
@ -1276,7 +1443,7 @@ static int switchtec_init_isr(struct switchtec_dev *stdev)
|
|||
if (nvecs < 0)
|
||||
return nvecs;
|
||||
|
||||
event_irq = ioread32(&stdev->mmio_part_cfg->vep_vector_number);
|
||||
event_irq = ioread16(&stdev->mmio_part_cfg->vep_vector_number);
|
||||
if (event_irq < 0 || event_irq >= nvecs)
|
||||
return -EFAULT;
|
||||
|
||||
|
@ -1324,16 +1491,16 @@ static void init_pff(struct switchtec_dev *stdev)
|
|||
stdev->pff_csr_count = i;
|
||||
|
||||
reg = ioread32(&pcfg->usp_pff_inst_id);
|
||||
if (reg < SWITCHTEC_MAX_PFF_CSR)
|
||||
if (reg < stdev->pff_csr_count)
|
||||
stdev->pff_local[reg] = 1;
|
||||
|
||||
reg = ioread32(&pcfg->vep_pff_inst_id);
|
||||
if (reg < SWITCHTEC_MAX_PFF_CSR)
|
||||
if (reg < stdev->pff_csr_count)
|
||||
stdev->pff_local[reg] = 1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) {
|
||||
reg = ioread32(&pcfg->dsp_pff_inst_id[i]);
|
||||
if (reg < SWITCHTEC_MAX_PFF_CSR)
|
||||
if (reg < stdev->pff_csr_count)
|
||||
stdev->pff_local[reg] = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1344,12 +1511,13 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
|
|||
int rc;
|
||||
void __iomem *map;
|
||||
unsigned long res_start, res_len;
|
||||
u32 __iomem *part_id;
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
|
||||
rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1378,7 +1546,15 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
|
|||
stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;
|
||||
stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET;
|
||||
stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET;
|
||||
stdev->partition = ioread8(&stdev->mmio_sys_info->partition_id);
|
||||
|
||||
if (stdev->gen == SWITCHTEC_GEN3)
|
||||
part_id = &stdev->mmio_sys_info->gen3.partition_id;
|
||||
else if (stdev->gen == SWITCHTEC_GEN4)
|
||||
part_id = &stdev->mmio_sys_info->gen4.partition_id;
|
||||
else
|
||||
return -ENOTSUPP;
|
||||
|
||||
stdev->partition = ioread8(part_id);
|
||||
stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count);
|
||||
stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET;
|
||||
stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition];
|
||||
|
@ -1420,6 +1596,8 @@ static int switchtec_pci_probe(struct pci_dev *pdev,
|
|||
if (IS_ERR(stdev))
|
||||
return PTR_ERR(stdev);
|
||||
|
||||
stdev->gen = id->driver_data;
|
||||
|
||||
rc = switchtec_init_pci(stdev, pdev);
|
||||
if (rc)
|
||||
goto err_put;
|
||||
|
@ -1467,7 +1645,7 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
|
|||
put_device(&stdev->dev);
|
||||
}
|
||||
|
||||
#define SWITCHTEC_PCI_DEVICE(device_id) \
|
||||
#define SWITCHTEC_PCI_DEVICE(device_id, gen) \
|
||||
{ \
|
||||
.vendor = PCI_VENDOR_ID_MICROSEMI, \
|
||||
.device = device_id, \
|
||||
|
@ -1475,6 +1653,7 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
|
|||
.subdevice = PCI_ANY_ID, \
|
||||
.class = (PCI_CLASS_MEMORY_OTHER << 8), \
|
||||
.class_mask = 0xFFFFFFFF, \
|
||||
.driver_data = gen, \
|
||||
}, \
|
||||
{ \
|
||||
.vendor = PCI_VENDOR_ID_MICROSEMI, \
|
||||
|
@ -1483,39 +1662,58 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
|
|||
.subdevice = PCI_ANY_ID, \
|
||||
.class = (PCI_CLASS_BRIDGE_OTHER << 8), \
|
||||
.class_mask = 0xFFFFFFFF, \
|
||||
.driver_data = gen, \
|
||||
}
|
||||
|
||||
static const struct pci_device_id switchtec_pci_tbl[] = {
|
||||
SWITCHTEC_PCI_DEVICE(0x8531), //PFX 24xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8532), //PFX 32xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8533), //PFX 48xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8534), //PFX 64xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8535), //PFX 80xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8536), //PFX 96xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8541), //PSX 24xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8542), //PSX 32xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8543), //PSX 48xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8544), //PSX 64xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8545), //PSX 80xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8546), //PSX 96xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8551), //PAX 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8552), //PAX 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8553), //PAX 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8554), //PAX 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8555), //PAX 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8556), //PAX 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8561), //PFXL 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8562), //PFXL 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8563), //PFXL 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8564), //PFXL 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8565), //PFXL 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8566), //PFXL 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8571), //PFXI 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8572), //PFXI 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8573), //PFXI 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8574), //PFXI 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8575), //PFXI 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8576), //PFXI 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8531, SWITCHTEC_GEN3), //PFX 24xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8532, SWITCHTEC_GEN3), //PFX 32xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8533, SWITCHTEC_GEN3), //PFX 48xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8534, SWITCHTEC_GEN3), //PFX 64xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8535, SWITCHTEC_GEN3), //PFX 80xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8536, SWITCHTEC_GEN3), //PFX 96xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8541, SWITCHTEC_GEN3), //PSX 24xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8542, SWITCHTEC_GEN3), //PSX 32xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8543, SWITCHTEC_GEN3), //PSX 48xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8544, SWITCHTEC_GEN3), //PSX 64xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8545, SWITCHTEC_GEN3), //PSX 80xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8546, SWITCHTEC_GEN3), //PSX 96xG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8551, SWITCHTEC_GEN3), //PAX 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8552, SWITCHTEC_GEN3), //PAX 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8553, SWITCHTEC_GEN3), //PAX 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8554, SWITCHTEC_GEN3), //PAX 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8555, SWITCHTEC_GEN3), //PAX 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8556, SWITCHTEC_GEN3), //PAX 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8561, SWITCHTEC_GEN3), //PFXL 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8562, SWITCHTEC_GEN3), //PFXL 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8563, SWITCHTEC_GEN3), //PFXL 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8564, SWITCHTEC_GEN3), //PFXL 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8565, SWITCHTEC_GEN3), //PFXL 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8566, SWITCHTEC_GEN3), //PFXL 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8571, SWITCHTEC_GEN3), //PFXI 24XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8572, SWITCHTEC_GEN3), //PFXI 32XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8573, SWITCHTEC_GEN3), //PFXI 48XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8574, SWITCHTEC_GEN3), //PFXI 64XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8575, SWITCHTEC_GEN3), //PFXI 80XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x8576, SWITCHTEC_GEN3), //PFXI 96XG3
|
||||
SWITCHTEC_PCI_DEVICE(0x4000, SWITCHTEC_GEN4), //PFX 100XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4084, SWITCHTEC_GEN4), //PFX 84XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4068, SWITCHTEC_GEN4), //PFX 68XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4052, SWITCHTEC_GEN4), //PFX 52XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4036, SWITCHTEC_GEN4), //PFX 36XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4028, SWITCHTEC_GEN4), //PFX 28XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4100, SWITCHTEC_GEN4), //PSX 100XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4184, SWITCHTEC_GEN4), //PSX 84XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4168, SWITCHTEC_GEN4), //PSX 68XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4152, SWITCHTEC_GEN4), //PSX 52XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4136, SWITCHTEC_GEN4), //PSX 36XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4128, SWITCHTEC_GEN4), //PSX 28XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4200, SWITCHTEC_GEN4), //PAX 100XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4284, SWITCHTEC_GEN4), //PAX 84XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4268, SWITCHTEC_GEN4), //PAX 68XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4252, SWITCHTEC_GEN4), //PAX 52XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4236, SWITCHTEC_GEN4), //PAX 36XG4
|
||||
SWITCHTEC_PCI_DEVICE(0x4228, SWITCHTEC_GEN4), //PAX 28XG4
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl);
|
||||
|
|
|
@ -1202,6 +1202,7 @@ int __must_check pci_resize_resource(struct pci_dev *dev, int i, int size);
|
|||
int pci_select_bars(struct pci_dev *dev, unsigned long flags);
|
||||
bool pci_device_is_present(struct pci_dev *pdev);
|
||||
void pci_ignore_hotplug(struct pci_dev *dev);
|
||||
struct pci_dev *pci_real_dma_dev(struct pci_dev *dev);
|
||||
|
||||
int __printf(6, 7) pci_request_irq(struct pci_dev *dev, unsigned int nr,
|
||||
irq_handler_t handler, irq_handler_t thread_fn, void *dev_id,
|
||||
|
@ -2310,7 +2311,7 @@ static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
|
|||
}
|
||||
#endif
|
||||
|
||||
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn);
|
||||
void pci_add_dma_alias(struct pci_dev *dev, u8 devfn_from, unsigned nr_devfns);
|
||||
bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2);
|
||||
int pci_for_each_dma_alias(struct pci_dev *pdev,
|
||||
int (*fn)(struct pci_dev *pdev,
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
#define SWITCHTEC_EVENT_FATAL BIT(4)
|
||||
|
||||
#define SWITCHTEC_DMA_MRPC_EN BIT(0)
|
||||
|
||||
#define MRPC_GAS_READ 0x29
|
||||
#define MRPC_GAS_WRITE 0x87
|
||||
#define MRPC_CMD_ID(x) ((x) & 0xffff)
|
||||
|
||||
enum {
|
||||
SWITCHTEC_GAS_MRPC_OFFSET = 0x0000,
|
||||
SWITCHTEC_GAS_TOP_CFG_OFFSET = 0x1000,
|
||||
|
@ -32,6 +37,11 @@ enum {
|
|||
SWITCHTEC_GAS_PFF_CSR_OFFSET = 0x134000,
|
||||
};
|
||||
|
||||
enum switchtec_gen {
|
||||
SWITCHTEC_GEN3,
|
||||
SWITCHTEC_GEN4,
|
||||
};
|
||||
|
||||
struct mrpc_regs {
|
||||
u8 input_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
|
||||
u8 output_data[SWITCHTEC_MRPC_PAYLOAD_SIZE];
|
||||
|
@ -98,16 +108,37 @@ struct sw_event_regs {
|
|||
} __packed;
|
||||
|
||||
enum {
|
||||
SWITCHTEC_CFG0_RUNNING = 0x04,
|
||||
SWITCHTEC_CFG1_RUNNING = 0x05,
|
||||
SWITCHTEC_IMG0_RUNNING = 0x03,
|
||||
SWITCHTEC_IMG1_RUNNING = 0x07,
|
||||
SWITCHTEC_GEN3_CFG0_RUNNING = 0x04,
|
||||
SWITCHTEC_GEN3_CFG1_RUNNING = 0x05,
|
||||
SWITCHTEC_GEN3_IMG0_RUNNING = 0x03,
|
||||
SWITCHTEC_GEN3_IMG1_RUNNING = 0x07,
|
||||
};
|
||||
|
||||
struct sys_info_regs {
|
||||
u32 device_id;
|
||||
u32 device_version;
|
||||
u32 firmware_version;
|
||||
enum {
|
||||
SWITCHTEC_GEN4_MAP0_RUNNING = 0x00,
|
||||
SWITCHTEC_GEN4_MAP1_RUNNING = 0x01,
|
||||
SWITCHTEC_GEN4_KEY0_RUNNING = 0x02,
|
||||
SWITCHTEC_GEN4_KEY1_RUNNING = 0x03,
|
||||
SWITCHTEC_GEN4_BL2_0_RUNNING = 0x04,
|
||||
SWITCHTEC_GEN4_BL2_1_RUNNING = 0x05,
|
||||
SWITCHTEC_GEN4_CFG0_RUNNING = 0x06,
|
||||
SWITCHTEC_GEN4_CFG1_RUNNING = 0x07,
|
||||
SWITCHTEC_GEN4_IMG0_RUNNING = 0x08,
|
||||
SWITCHTEC_GEN4_IMG1_RUNNING = 0x09,
|
||||
};
|
||||
|
||||
enum {
|
||||
SWITCHTEC_GEN4_KEY0_ACTIVE = 0,
|
||||
SWITCHTEC_GEN4_KEY1_ACTIVE = 1,
|
||||
SWITCHTEC_GEN4_BL2_0_ACTIVE = 0,
|
||||
SWITCHTEC_GEN4_BL2_1_ACTIVE = 1,
|
||||
SWITCHTEC_GEN4_CFG0_ACTIVE = 0,
|
||||
SWITCHTEC_GEN4_CFG1_ACTIVE = 1,
|
||||
SWITCHTEC_GEN4_IMG0_ACTIVE = 0,
|
||||
SWITCHTEC_GEN4_IMG1_ACTIVE = 1,
|
||||
};
|
||||
|
||||
struct sys_info_regs_gen3 {
|
||||
u32 reserved1;
|
||||
u32 vendor_table_revision;
|
||||
u32 table_format_version;
|
||||
|
@ -124,26 +155,78 @@ struct sys_info_regs {
|
|||
u8 component_revision;
|
||||
} __packed;
|
||||
|
||||
struct flash_info_regs {
|
||||
struct sys_info_regs_gen4 {
|
||||
u16 gas_layout_ver;
|
||||
u8 evlist_ver;
|
||||
u8 reserved1;
|
||||
u16 mgmt_cmd_set_ver;
|
||||
u16 fabric_cmd_set_ver;
|
||||
u32 reserved2[2];
|
||||
u8 mrpc_uart_ver;
|
||||
u8 mrpc_twi_ver;
|
||||
u8 mrpc_eth_ver;
|
||||
u8 mrpc_inband_ver;
|
||||
u32 reserved3[7];
|
||||
u32 fw_update_tmo;
|
||||
u32 xml_version_cfg;
|
||||
u32 xml_version_img;
|
||||
u32 partition_id;
|
||||
u16 bl2_running;
|
||||
u16 cfg_running;
|
||||
u16 img_running;
|
||||
u16 key_running;
|
||||
u32 reserved4[43];
|
||||
u32 vendor_seeprom_twi;
|
||||
u32 vendor_table_revision;
|
||||
u32 vendor_specific_info[2];
|
||||
u16 p2p_vendor_id;
|
||||
u16 p2p_device_id;
|
||||
u8 p2p_revision_id;
|
||||
u8 reserved5[3];
|
||||
u32 p2p_class_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u16 subsystem_id;
|
||||
u32 p2p_serial_number[2];
|
||||
u8 mac_addr[6];
|
||||
u8 reserved6[2];
|
||||
u32 reserved7[3];
|
||||
char vendor_id[8];
|
||||
char product_id[24];
|
||||
char product_revision[2];
|
||||
u16 reserved8;
|
||||
} __packed;
|
||||
|
||||
struct sys_info_regs {
|
||||
u32 device_id;
|
||||
u32 device_version;
|
||||
u32 firmware_version;
|
||||
union {
|
||||
struct sys_info_regs_gen3 gen3;
|
||||
struct sys_info_regs_gen4 gen4;
|
||||
};
|
||||
} __packed;
|
||||
|
||||
struct partition_info {
|
||||
u32 address;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
struct flash_info_regs_gen3 {
|
||||
u32 flash_part_map_upd_idx;
|
||||
|
||||
struct active_partition_info {
|
||||
struct active_partition_info_gen3 {
|
||||
u32 address;
|
||||
u32 build_version;
|
||||
u32 build_string;
|
||||
} active_img;
|
||||
|
||||
struct active_partition_info active_cfg;
|
||||
struct active_partition_info inactive_img;
|
||||
struct active_partition_info inactive_cfg;
|
||||
struct active_partition_info_gen3 active_cfg;
|
||||
struct active_partition_info_gen3 inactive_img;
|
||||
struct active_partition_info_gen3 inactive_cfg;
|
||||
|
||||
u32 flash_length;
|
||||
|
||||
struct partition_info {
|
||||
u32 address;
|
||||
u32 length;
|
||||
} cfg0;
|
||||
|
||||
struct partition_info cfg0;
|
||||
struct partition_info cfg1;
|
||||
struct partition_info img0;
|
||||
struct partition_info img1;
|
||||
|
@ -151,6 +234,40 @@ struct flash_info_regs {
|
|||
struct partition_info vendor[8];
|
||||
};
|
||||
|
||||
struct flash_info_regs_gen4 {
|
||||
u32 flash_address;
|
||||
u32 flash_length;
|
||||
|
||||
struct active_partition_info_gen4 {
|
||||
unsigned char bl2;
|
||||
unsigned char cfg;
|
||||
unsigned char img;
|
||||
unsigned char key;
|
||||
} active_flag;
|
||||
|
||||
u32 reserved[3];
|
||||
|
||||
struct partition_info map0;
|
||||
struct partition_info map1;
|
||||
struct partition_info key0;
|
||||
struct partition_info key1;
|
||||
struct partition_info bl2_0;
|
||||
struct partition_info bl2_1;
|
||||
struct partition_info cfg0;
|
||||
struct partition_info cfg1;
|
||||
struct partition_info img0;
|
||||
struct partition_info img1;
|
||||
struct partition_info nvlog;
|
||||
struct partition_info vendor[8];
|
||||
};
|
||||
|
||||
struct flash_info_regs {
|
||||
union {
|
||||
struct flash_info_regs_gen3 gen3;
|
||||
struct flash_info_regs_gen4 gen4;
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
SWITCHTEC_NTB_REG_INFO_OFFSET = 0x0000,
|
||||
SWITCHTEC_NTB_REG_CTRL_OFFSET = 0x4000,
|
||||
|
@ -196,7 +313,9 @@ struct part_cfg_regs {
|
|||
u32 mrpc_comp_async_data[5];
|
||||
u32 dyn_binding_hdr;
|
||||
u32 dyn_binding_data[5];
|
||||
u32 reserved4[159];
|
||||
u32 intercomm_notify_hdr;
|
||||
u32 intercomm_notify_data[5];
|
||||
u32 reserved4[153];
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
|
@ -320,7 +439,8 @@ struct pff_csr_regs {
|
|||
u32 dpc_data[5];
|
||||
u32 cts_hdr;
|
||||
u32 cts_data[5];
|
||||
u32 reserved3[6];
|
||||
u32 uec_hdr;
|
||||
u32 uec_data[5];
|
||||
u32 hotplug_hdr;
|
||||
u32 hotplug_data[5];
|
||||
u32 ier_hdr;
|
||||
|
@ -355,6 +475,8 @@ struct switchtec_dev {
|
|||
struct device dev;
|
||||
struct cdev cdev;
|
||||
|
||||
enum switchtec_gen gen;
|
||||
|
||||
int partition;
|
||||
int partition_count;
|
||||
int pff_csr_count;
|
||||
|
|
|
@ -676,6 +676,7 @@
|
|||
#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
|
||||
#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */
|
||||
#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
|
||||
#define PCI_EXP_LNKCTL2_HASD 0x0020 /* HW Autonomous Speed Disable */
|
||||
#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */
|
||||
#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 52 /* v2 endpoints with link end here */
|
||||
#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */
|
||||
|
|
|
@ -32,7 +32,18 @@
|
|||
#define SWITCHTEC_IOCTL_PART_VENDOR5 10
|
||||
#define SWITCHTEC_IOCTL_PART_VENDOR6 11
|
||||
#define SWITCHTEC_IOCTL_PART_VENDOR7 12
|
||||
#define SWITCHTEC_IOCTL_NUM_PARTITIONS 13
|
||||
#define SWITCHTEC_IOCTL_PART_BL2_0 13
|
||||
#define SWITCHTEC_IOCTL_PART_BL2_1 14
|
||||
#define SWITCHTEC_IOCTL_PART_MAP_0 15
|
||||
#define SWITCHTEC_IOCTL_PART_MAP_1 16
|
||||
#define SWITCHTEC_IOCTL_PART_KEY_0 17
|
||||
#define SWITCHTEC_IOCTL_PART_KEY_1 18
|
||||
|
||||
#define SWITCHTEC_NUM_PARTITIONS_GEN3 13
|
||||
#define SWITCHTEC_NUM_PARTITIONS_GEN4 19
|
||||
|
||||
/* obsolete: for compatibility with old userspace software */
|
||||
#define SWITCHTEC_IOCTL_NUM_PARTITIONS SWITCHTEC_NUM_PARTITIONS_GEN3
|
||||
|
||||
struct switchtec_ioctl_flash_info {
|
||||
__u64 flash_length;
|
||||
|
@ -98,7 +109,9 @@ struct switchtec_ioctl_event_summary {
|
|||
#define SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT 27
|
||||
#define SWITCHTEC_IOCTL_EVENT_LINK_STATE 28
|
||||
#define SWITCHTEC_IOCTL_EVENT_GFMS 29
|
||||
#define SWITCHTEC_IOCTL_MAX_EVENTS 30
|
||||
#define SWITCHTEC_IOCTL_EVENT_INTERCOMM_REQ_NOTIFY 30
|
||||
#define SWITCHTEC_IOCTL_EVENT_UEC 31
|
||||
#define SWITCHTEC_IOCTL_MAX_EVENTS 32
|
||||
|
||||
#define SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX -1
|
||||
#define SWITCHTEC_IOCTL_EVENT_IDX_ALL -2
|
||||
|
|
Loading…
Reference in New Issue