pci-v5.13-fixes-2
-----BEGIN PGP SIGNATURE----- iQJIBAABCgAyFiEEgMe7l+5h9hnxdsnuWYigwDrT+vwFAmDM/J8UHGJoZWxnYWFz QGdvb2dsZS5jb20ACgkQWYigwDrT+vzAWBAAgHd/Taycg2JT1QakC2qkUPfipB2w IQWAzRAODWEXBOsgdck4H5q7y4dzxHdj4BmZIe0iPmc0LkqrqjYiKvYZzqdLzRlG 4SC12h7DLOBfPluKDfjB3Ceo0TlpAWM9c6Gm2liMscLJMMw8JcrnZK+pP03ws66O 3UjHRF+tJTDUqGUeOn45MVlkVSk5wIOG+hgGbI3AEGPvegteK0J97xJ8GI4MUi58 Uy5VMFB+ETOxvbzWAAiRIko4YkSjVNb1pme21Izi6z2FMldmUb9nECp6zSJzxj5t H6/8ehgzHDIoyak0DDzyS2rOL4D1jIqymEKQIIK2frODaRYSSYUR/vtXkhO/bxPf aJ9uFJQFZei98cSiONmq1NDJAMEMa21b32MfK5sOizJJ7ANljBFz+eVY0L+Mr+wy WQf8EiBXBCS2v3CQzS7iA+l8R6rvvf+VjDkqpe/ca1GrAeZ1UzdmU2vf9hcEW+Iu MJ1b6AtTTMAQIdZyTVFz+k/FR3jJyZBGavZFi8+I0Tgui0dooiCwmSgxJptVQrjr DydIiJ2Zgtq22T388aVeDL5X4xDcqWlHoamfHuBedxS/ti75Es7sexitkhMW+Sda Ygqb5Cvfyg8GdKvgvDZz59wg/+LNhhwt81ZoxD/RvDXmURyANA3l9GnTxBgq9BZb wCGLm4ZWP/AFe9g= =CY2S -----END PGP SIGNATURE----- Merge tag 'pci-v5.13-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI fixes from Bjorn Helgaas: - Clear 64-bit flag for host bridge windows below 4GB to fix a resource allocation regression added in -rc1 (Punit Agrawal) - Fix tegra194 MCFG quirk build regressions added in -rc1 (Jon Hunter) - Avoid secondary bus resets on TI KeyStone C667X devices (Antti Järvinen) - Avoid secondary bus resets on some NVIDIA GPUs (Shanker Donthineni) - Work around FLR erratum on Huawei Intelligent NIC VF (Chiqijun) - Avoid broken ATS on AMD Navi14 GPU (Evan Quan) - Trust Broadcom BCM57414 NIC to isolate functions even though it doesn't advertise ACS support (Sriharsha Basavapatna) - Work around AMD RS690 BIOSes that don't configure DMA above 4GB (Mikel Rychliski) - Fix panic during PIO transfer on Aardvark controller (Pali Rohár) * tag 'pci-v5.13-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: PCI: aardvark: Fix kernel panic during PIO transfer PCI: Add AMD RS690 quirk to enable 64-bit DMA PCI: Add ACS quirk for Broadcom BCM57414 NIC PCI: Mark AMD Navi14 GPU ATS as broken PCI: Work around Huawei Intelligent NIC VF FLR erratum PCI: Mark some NVIDIA GPUs to avoid bus reset PCI: Mark TI C667X to avoid bus reset PCI: tegra194: Fix MCFG quirk build regressions PCI: of: Clear 64-bit flag for non-prefetchable memory below 4GB
This commit is contained in:
Коммит
728a748b3f
|
@ -779,4 +779,48 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1571, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x15b1, pci_amd_enable_64bit_bar);
|
||||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
|
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1601, pci_amd_enable_64bit_bar);
|
||||||
|
|
||||||
|
#define RS690_LOWER_TOP_OF_DRAM2 0x30
|
||||||
|
#define RS690_LOWER_TOP_OF_DRAM2_VALID 0x1
|
||||||
|
#define RS690_UPPER_TOP_OF_DRAM2 0x31
|
||||||
|
#define RS690_HTIU_NB_INDEX 0xA8
|
||||||
|
#define RS690_HTIU_NB_INDEX_WR_ENABLE 0x100
|
||||||
|
#define RS690_HTIU_NB_DATA 0xAC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some BIOS implementations support RAM above 4GB, but do not configure the
|
||||||
|
* PCI host to respond to bus master accesses for these addresses. These
|
||||||
|
* implementations set the TOP_OF_DRAM_SLOT1 register correctly, so PCI DMA
|
||||||
|
* works as expected for addresses below 4GB.
|
||||||
|
*
|
||||||
|
* Reference: "AMD RS690 ASIC Family Register Reference Guide" (pg. 2-57)
|
||||||
|
* https://www.amd.com/system/files/TechDocs/43372_rs690_rrg_3.00o.pdf
|
||||||
|
*/
|
||||||
|
static void rs690_fix_64bit_dma(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
phys_addr_t top_of_dram = __pa(high_memory - 1) + 1;
|
||||||
|
|
||||||
|
if (top_of_dram <= (1ULL << 32))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
|
||||||
|
RS690_LOWER_TOP_OF_DRAM2);
|
||||||
|
pci_read_config_dword(pdev, RS690_HTIU_NB_DATA, &val);
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pci_info(pdev, "Adjusting top of DRAM to %pa for 64-bit DMA support\n", &top_of_dram);
|
||||||
|
|
||||||
|
pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
|
||||||
|
RS690_UPPER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
|
||||||
|
pci_write_config_dword(pdev, RS690_HTIU_NB_DATA, top_of_dram >> 32);
|
||||||
|
|
||||||
|
pci_write_config_dword(pdev, RS690_HTIU_NB_INDEX,
|
||||||
|
RS690_LOWER_TOP_OF_DRAM2 | RS690_HTIU_NB_INDEX_WR_ENABLE);
|
||||||
|
pci_write_config_dword(pdev, RS690_HTIU_NB_DATA,
|
||||||
|
top_of_dram | RS690_LOWER_TOP_OF_DRAM2_VALID);
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7910, rs690_fix_64bit_dma);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,6 +18,7 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
|
||||||
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
|
||||||
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
||||||
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
obj-$(CONFIG_PCI_MESON) += pci-meson.o
|
||||||
|
obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
|
||||||
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
|
||||||
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
|
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
|
||||||
|
|
||||||
|
@ -38,6 +39,6 @@ ifdef CONFIG_ACPI
|
||||||
ifdef CONFIG_PCI_QUIRKS
|
ifdef CONFIG_PCI_QUIRKS
|
||||||
obj-$(CONFIG_ARM64) += pcie-al.o
|
obj-$(CONFIG_ARM64) += pcie-al.o
|
||||||
obj-$(CONFIG_ARM64) += pcie-hisi.o
|
obj-$(CONFIG_ARM64) += pcie-hisi.o
|
||||||
obj-$(CONFIG_ARM64) += pcie-tegra194.o
|
obj-$(CONFIG_ARM64) += pcie-tegra194-acpi.o
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* ACPI quirks for Tegra194 PCIe host controller
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 NVIDIA Corporation.
|
||||||
|
*
|
||||||
|
* Author: Vidya Sagar <vidyas@nvidia.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci-acpi.h>
|
||||||
|
#include <linux/pci-ecam.h>
|
||||||
|
|
||||||
|
#include "pcie-designware.h"
|
||||||
|
|
||||||
|
struct tegra194_pcie_ecam {
|
||||||
|
void __iomem *config_base;
|
||||||
|
void __iomem *iatu_base;
|
||||||
|
void __iomem *dbi_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tegra194_acpi_init(struct pci_config_window *cfg)
|
||||||
|
{
|
||||||
|
struct device *dev = cfg->parent;
|
||||||
|
struct tegra194_pcie_ecam *pcie_ecam;
|
||||||
|
|
||||||
|
pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
|
||||||
|
if (!pcie_ecam)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pcie_ecam->config_base = cfg->win;
|
||||||
|
pcie_ecam->iatu_base = cfg->win + SZ_256K;
|
||||||
|
pcie_ecam->dbi_base = cfg->win + SZ_512K;
|
||||||
|
cfg->priv = pcie_ecam;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
|
||||||
|
u32 val, u32 reg)
|
||||||
|
{
|
||||||
|
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
||||||
|
|
||||||
|
writel(val, pcie_ecam->iatu_base + offset + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
|
||||||
|
int index, int type, u64 cpu_addr,
|
||||||
|
u64 pci_addr, u64 size)
|
||||||
|
{
|
||||||
|
atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
|
||||||
|
PCIE_ATU_LOWER_BASE);
|
||||||
|
atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
|
||||||
|
PCIE_ATU_UPPER_BASE);
|
||||||
|
atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
|
||||||
|
PCIE_ATU_LOWER_TARGET);
|
||||||
|
atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
|
||||||
|
PCIE_ATU_LIMIT);
|
||||||
|
atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
|
||||||
|
PCIE_ATU_UPPER_TARGET);
|
||||||
|
atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1);
|
||||||
|
atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __iomem *tegra194_map_bus(struct pci_bus *bus,
|
||||||
|
unsigned int devfn, int where)
|
||||||
|
{
|
||||||
|
struct pci_config_window *cfg = bus->sysdata;
|
||||||
|
struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
|
||||||
|
u32 busdev;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (bus->number == cfg->busr.start) {
|
||||||
|
if (PCI_SLOT(devfn) == 0)
|
||||||
|
return pcie_ecam->dbi_base + where;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||||
|
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||||
|
|
||||||
|
if (bus->parent->number == cfg->busr.start) {
|
||||||
|
if (PCI_SLOT(devfn) == 0)
|
||||||
|
type = PCIE_ATU_TYPE_CFG0;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
type = PCIE_ATU_TYPE_CFG1;
|
||||||
|
}
|
||||||
|
|
||||||
|
program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
|
||||||
|
SZ_256K);
|
||||||
|
|
||||||
|
return pcie_ecam->config_base + where;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct pci_ecam_ops tegra194_pcie_ops = {
|
||||||
|
.init = tegra194_acpi_init,
|
||||||
|
.pci_ops = {
|
||||||
|
.map_bus = tegra194_map_bus,
|
||||||
|
.read = pci_generic_config_read,
|
||||||
|
.write = pci_generic_config_write,
|
||||||
|
}
|
||||||
|
};
|
|
@ -22,8 +22,6 @@
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_pci.h>
|
#include <linux/of_pci.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/pci-acpi.h>
|
|
||||||
#include <linux/pci-ecam.h>
|
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
@ -247,24 +245,6 @@ static const unsigned int pcie_gen_freq[] = {
|
||||||
GEN4_CORE_CLK_FREQ
|
GEN4_CORE_CLK_FREQ
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u32 event_cntr_ctrl_offset[] = {
|
|
||||||
0x1d8,
|
|
||||||
0x1a8,
|
|
||||||
0x1a8,
|
|
||||||
0x1a8,
|
|
||||||
0x1c4,
|
|
||||||
0x1d8
|
|
||||||
};
|
|
||||||
|
|
||||||
static const u32 event_cntr_data_offset[] = {
|
|
||||||
0x1dc,
|
|
||||||
0x1ac,
|
|
||||||
0x1ac,
|
|
||||||
0x1ac,
|
|
||||||
0x1c8,
|
|
||||||
0x1dc
|
|
||||||
};
|
|
||||||
|
|
||||||
struct tegra_pcie_dw {
|
struct tegra_pcie_dw {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct resource *appl_res;
|
struct resource *appl_res;
|
||||||
|
@ -313,104 +293,6 @@ struct tegra_pcie_dw_of_data {
|
||||||
enum dw_pcie_device_mode mode;
|
enum dw_pcie_device_mode mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
|
|
||||||
struct tegra194_pcie_ecam {
|
|
||||||
void __iomem *config_base;
|
|
||||||
void __iomem *iatu_base;
|
|
||||||
void __iomem *dbi_base;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int tegra194_acpi_init(struct pci_config_window *cfg)
|
|
||||||
{
|
|
||||||
struct device *dev = cfg->parent;
|
|
||||||
struct tegra194_pcie_ecam *pcie_ecam;
|
|
||||||
|
|
||||||
pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
|
|
||||||
if (!pcie_ecam)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
pcie_ecam->config_base = cfg->win;
|
|
||||||
pcie_ecam->iatu_base = cfg->win + SZ_256K;
|
|
||||||
pcie_ecam->dbi_base = cfg->win + SZ_512K;
|
|
||||||
cfg->priv = pcie_ecam;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
|
|
||||||
u32 val, u32 reg)
|
|
||||||
{
|
|
||||||
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
|
||||||
|
|
||||||
writel(val, pcie_ecam->iatu_base + offset + reg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
|
|
||||||
int index, int type, u64 cpu_addr,
|
|
||||||
u64 pci_addr, u64 size)
|
|
||||||
{
|
|
||||||
atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
|
|
||||||
PCIE_ATU_LOWER_BASE);
|
|
||||||
atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
|
|
||||||
PCIE_ATU_UPPER_BASE);
|
|
||||||
atu_reg_write(pcie_ecam, index, lower_32_bits(pci_addr),
|
|
||||||
PCIE_ATU_LOWER_TARGET);
|
|
||||||
atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr + size - 1),
|
|
||||||
PCIE_ATU_LIMIT);
|
|
||||||
atu_reg_write(pcie_ecam, index, upper_32_bits(pci_addr),
|
|
||||||
PCIE_ATU_UPPER_TARGET);
|
|
||||||
atu_reg_write(pcie_ecam, index, type, PCIE_ATU_CR1);
|
|
||||||
atu_reg_write(pcie_ecam, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __iomem *tegra194_map_bus(struct pci_bus *bus,
|
|
||||||
unsigned int devfn, int where)
|
|
||||||
{
|
|
||||||
struct pci_config_window *cfg = bus->sysdata;
|
|
||||||
struct tegra194_pcie_ecam *pcie_ecam = cfg->priv;
|
|
||||||
u32 busdev;
|
|
||||||
int type;
|
|
||||||
|
|
||||||
if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (bus->number == cfg->busr.start) {
|
|
||||||
if (PCI_SLOT(devfn) == 0)
|
|
||||||
return pcie_ecam->dbi_base + where;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
|
||||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
|
||||||
|
|
||||||
if (bus->parent->number == cfg->busr.start) {
|
|
||||||
if (PCI_SLOT(devfn) == 0)
|
|
||||||
type = PCIE_ATU_TYPE_CFG0;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
type = PCIE_ATU_TYPE_CFG1;
|
|
||||||
}
|
|
||||||
|
|
||||||
program_outbound_atu(pcie_ecam, 0, type, cfg->res.start, busdev,
|
|
||||||
SZ_256K);
|
|
||||||
|
|
||||||
return pcie_ecam->config_base + where;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct pci_ecam_ops tegra194_pcie_ops = {
|
|
||||||
.init = tegra194_acpi_init,
|
|
||||||
.pci_ops = {
|
|
||||||
.map_bus = tegra194_map_bus,
|
|
||||||
.read = pci_generic_config_read,
|
|
||||||
.write = pci_generic_config_write,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCIE_TEGRA194
|
|
||||||
|
|
||||||
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
|
static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
|
||||||
{
|
{
|
||||||
return container_of(pci, struct tegra_pcie_dw, pci);
|
return container_of(pci, struct tegra_pcie_dw, pci);
|
||||||
|
@ -694,6 +576,24 @@ static struct pci_ops tegra_pci_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(CONFIG_PCIEASPM)
|
#if defined(CONFIG_PCIEASPM)
|
||||||
|
static const u32 event_cntr_ctrl_offset[] = {
|
||||||
|
0x1d8,
|
||||||
|
0x1a8,
|
||||||
|
0x1a8,
|
||||||
|
0x1a8,
|
||||||
|
0x1c4,
|
||||||
|
0x1d8
|
||||||
|
};
|
||||||
|
|
||||||
|
static const u32 event_cntr_data_offset[] = {
|
||||||
|
0x1dc,
|
||||||
|
0x1ac,
|
||||||
|
0x1ac,
|
||||||
|
0x1ac,
|
||||||
|
0x1c8,
|
||||||
|
0x1dc
|
||||||
|
};
|
||||||
|
|
||||||
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
|
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -2411,5 +2311,3 @@ MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);
|
||||||
MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
|
MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
|
||||||
MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
|
MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
|
||||||
#endif /* CONFIG_PCIE_TEGRA194 */
|
|
||||||
|
|
|
@ -514,7 +514,7 @@ static int advk_pcie_wait_pio(struct advk_pcie *pcie)
|
||||||
udelay(PIO_RETRY_DELAY);
|
udelay(PIO_RETRY_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(dev, "config read/write timed out\n");
|
dev_err(dev, "PIO read/write transfer time out\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,6 +657,35 @@ static bool advk_pcie_valid_device(struct advk_pcie *pcie, struct pci_bus *bus,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool advk_pcie_pio_is_running(struct advk_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct device *dev = &pcie->pdev->dev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trying to start a new PIO transfer when previous has not completed
|
||||||
|
* cause External Abort on CPU which results in kernel panic:
|
||||||
|
*
|
||||||
|
* SError Interrupt on CPU0, code 0xbf000002 -- SError
|
||||||
|
* Kernel panic - not syncing: Asynchronous SError Interrupt
|
||||||
|
*
|
||||||
|
* Functions advk_pcie_rd_conf() and advk_pcie_wr_conf() are protected
|
||||||
|
* by raw_spin_lock_irqsave() at pci_lock_config() level to prevent
|
||||||
|
* concurrent calls at the same time. But because PIO transfer may take
|
||||||
|
* about 1.5s when link is down or card is disconnected, it means that
|
||||||
|
* advk_pcie_wait_pio() does not always have to wait for completion.
|
||||||
|
*
|
||||||
|
* Some versions of ARM Trusted Firmware handles this External Abort at
|
||||||
|
* EL3 level and mask it to prevent kernel panic. Relevant TF-A commit:
|
||||||
|
* https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=3c7dcdac5c50
|
||||||
|
*/
|
||||||
|
if (advk_readl(pcie, PIO_START)) {
|
||||||
|
dev_err(dev, "Previous PIO read/write transfer is still running\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
||||||
int where, int size, u32 *val)
|
int where, int size, u32 *val)
|
||||||
{
|
{
|
||||||
|
@ -673,9 +702,10 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
||||||
return pci_bridge_emul_conf_read(&pcie->bridge, where,
|
return pci_bridge_emul_conf_read(&pcie->bridge, where,
|
||||||
size, val);
|
size, val);
|
||||||
|
|
||||||
/* Start PIO */
|
if (advk_pcie_pio_is_running(pcie)) {
|
||||||
advk_writel(pcie, 0, PIO_START);
|
*val = 0xffffffff;
|
||||||
advk_writel(pcie, 1, PIO_ISR);
|
return PCIBIOS_SET_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
/* Program the control register */
|
/* Program the control register */
|
||||||
reg = advk_readl(pcie, PIO_CTRL);
|
reg = advk_readl(pcie, PIO_CTRL);
|
||||||
|
@ -694,7 +724,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
|
||||||
/* Program the data strobe */
|
/* Program the data strobe */
|
||||||
advk_writel(pcie, 0xf, PIO_WR_DATA_STRB);
|
advk_writel(pcie, 0xf, PIO_WR_DATA_STRB);
|
||||||
|
|
||||||
/* Start the transfer */
|
/* Clear PIO DONE ISR and start the transfer */
|
||||||
|
advk_writel(pcie, 1, PIO_ISR);
|
||||||
advk_writel(pcie, 1, PIO_START);
|
advk_writel(pcie, 1, PIO_START);
|
||||||
|
|
||||||
ret = advk_pcie_wait_pio(pcie);
|
ret = advk_pcie_wait_pio(pcie);
|
||||||
|
@ -734,9 +765,8 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||||
if (where % size)
|
if (where % size)
|
||||||
return PCIBIOS_SET_FAILED;
|
return PCIBIOS_SET_FAILED;
|
||||||
|
|
||||||
/* Start PIO */
|
if (advk_pcie_pio_is_running(pcie))
|
||||||
advk_writel(pcie, 0, PIO_START);
|
return PCIBIOS_SET_FAILED;
|
||||||
advk_writel(pcie, 1, PIO_ISR);
|
|
||||||
|
|
||||||
/* Program the control register */
|
/* Program the control register */
|
||||||
reg = advk_readl(pcie, PIO_CTRL);
|
reg = advk_readl(pcie, PIO_CTRL);
|
||||||
|
@ -763,7 +793,8 @@ static int advk_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||||
/* Program the data strobe */
|
/* Program the data strobe */
|
||||||
advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB);
|
advk_writel(pcie, data_strobe, PIO_WR_DATA_STRB);
|
||||||
|
|
||||||
/* Start the transfer */
|
/* Clear PIO DONE ISR and start the transfer */
|
||||||
|
advk_writel(pcie, 1, PIO_ISR);
|
||||||
advk_writel(pcie, 1, PIO_START);
|
advk_writel(pcie, 1, PIO_START);
|
||||||
|
|
||||||
ret = advk_pcie_wait_pio(pcie);
|
ret = advk_pcie_wait_pio(pcie);
|
||||||
|
|
|
@ -353,6 +353,8 @@ static int devm_of_pci_get_host_bridge_resources(struct device *dev,
|
||||||
dev_warn(dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
|
dev_warn(dev, "More than one I/O resource converted for %pOF. CPU base address for old range lost!\n",
|
||||||
dev_node);
|
dev_node);
|
||||||
*io_base = range.cpu_addr;
|
*io_base = range.cpu_addr;
|
||||||
|
} else if (resource_type(res) == IORESOURCE_MEM) {
|
||||||
|
res->flags &= ~IORESOURCE_MEM_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_add_resource_offset(resources, res, res->start - range.pci_addr);
|
pci_add_resource_offset(resources, res, res->start - range.pci_addr);
|
||||||
|
|
|
@ -3546,6 +3546,18 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
|
||||||
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
|
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some NVIDIA GPU devices do not work with bus reset, SBR needs to be
|
||||||
|
* prevented for those affected devices.
|
||||||
|
*/
|
||||||
|
static void quirk_nvidia_no_bus_reset(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
if ((dev->device & 0xffc0) == 0x2340)
|
||||||
|
quirk_no_bus_reset(dev);
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
|
||||||
|
quirk_nvidia_no_bus_reset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
|
* Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
|
||||||
* The device will throw a Link Down error on AER-capable systems and
|
* The device will throw a Link Down error on AER-capable systems and
|
||||||
|
@ -3566,6 +3578,16 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
|
||||||
*/
|
*/
|
||||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CAVIUM, 0xa100, quirk_no_bus_reset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some TI KeyStone C667X devices do not support bus/hot reset. The PCIESS
|
||||||
|
* automatically disables LTSSM when Secondary Bus Reset is received and
|
||||||
|
* the device stops working. Prevent bus reset for these devices. With
|
||||||
|
* this change, the device can be assigned to VMs with VFIO, but it will
|
||||||
|
* leak state between VMs. Reference
|
||||||
|
* https://e2e.ti.com/support/processors/f/791/t/954382
|
||||||
|
*/
|
||||||
|
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0xb005, quirk_no_bus_reset);
|
||||||
|
|
||||||
static void quirk_no_pm_reset(struct pci_dev *dev)
|
static void quirk_no_pm_reset(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -3901,6 +3923,69 @@ static int delay_250ms_after_flr(struct pci_dev *dev, int probe)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PCI_DEVICE_ID_HINIC_VF 0x375E
|
||||||
|
#define HINIC_VF_FLR_TYPE 0x1000
|
||||||
|
#define HINIC_VF_FLR_CAP_BIT (1UL << 30)
|
||||||
|
#define HINIC_VF_OP 0xE80
|
||||||
|
#define HINIC_VF_FLR_PROC_BIT (1UL << 18)
|
||||||
|
#define HINIC_OPERATION_TIMEOUT 15000 /* 15 seconds */
|
||||||
|
|
||||||
|
/* Device-specific reset method for Huawei Intelligent NIC virtual functions */
|
||||||
|
static int reset_hinic_vf_dev(struct pci_dev *pdev, int probe)
|
||||||
|
{
|
||||||
|
unsigned long timeout;
|
||||||
|
void __iomem *bar;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (probe)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bar = pci_iomap(pdev, 0, 0);
|
||||||
|
if (!bar)
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
|
/* Get and check firmware capabilities */
|
||||||
|
val = ioread32be(bar + HINIC_VF_FLR_TYPE);
|
||||||
|
if (!(val & HINIC_VF_FLR_CAP_BIT)) {
|
||||||
|
pci_iounmap(pdev, bar);
|
||||||
|
return -ENOTTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set HINIC_VF_FLR_PROC_BIT for the start of FLR */
|
||||||
|
val = ioread32be(bar + HINIC_VF_OP);
|
||||||
|
val = val | HINIC_VF_FLR_PROC_BIT;
|
||||||
|
iowrite32be(val, bar + HINIC_VF_OP);
|
||||||
|
|
||||||
|
pcie_flr(pdev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The device must recapture its Bus and Device Numbers after FLR
|
||||||
|
* in order generate Completions. Issue a config write to let the
|
||||||
|
* device capture this information.
|
||||||
|
*/
|
||||||
|
pci_write_config_word(pdev, PCI_VENDOR_ID, 0);
|
||||||
|
|
||||||
|
/* Firmware clears HINIC_VF_FLR_PROC_BIT when reset is complete */
|
||||||
|
timeout = jiffies + msecs_to_jiffies(HINIC_OPERATION_TIMEOUT);
|
||||||
|
do {
|
||||||
|
val = ioread32be(bar + HINIC_VF_OP);
|
||||||
|
if (!(val & HINIC_VF_FLR_PROC_BIT))
|
||||||
|
goto reset_complete;
|
||||||
|
msleep(20);
|
||||||
|
} while (time_before(jiffies, timeout));
|
||||||
|
|
||||||
|
val = ioread32be(bar + HINIC_VF_OP);
|
||||||
|
if (!(val & HINIC_VF_FLR_PROC_BIT))
|
||||||
|
goto reset_complete;
|
||||||
|
|
||||||
|
pci_warn(pdev, "Reset dev timeout, FLR ack reg: %#010x\n", val);
|
||||||
|
|
||||||
|
reset_complete:
|
||||||
|
pci_iounmap(pdev, bar);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
|
static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
|
||||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
|
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF,
|
||||||
reset_intel_82599_sfp_virtfn },
|
reset_intel_82599_sfp_virtfn },
|
||||||
|
@ -3913,6 +3998,8 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = {
|
||||||
{ PCI_VENDOR_ID_INTEL, 0x0a54, delay_250ms_after_flr },
|
{ PCI_VENDOR_ID_INTEL, 0x0a54, delay_250ms_after_flr },
|
||||||
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
|
{ PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
|
||||||
reset_chelsio_generic_dev },
|
reset_chelsio_generic_dev },
|
||||||
|
{ PCI_VENDOR_ID_HUAWEI, PCI_DEVICE_ID_HINIC_VF,
|
||||||
|
reset_hinic_vf_dev },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4753,6 +4840,8 @@ static const struct pci_dev_acs_enabled {
|
||||||
{ PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
|
{ PCI_VENDOR_ID_AMPERE, 0xE00A, pci_quirk_xgene_acs },
|
||||||
{ PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
|
{ PCI_VENDOR_ID_AMPERE, 0xE00B, pci_quirk_xgene_acs },
|
||||||
{ PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
|
{ PCI_VENDOR_ID_AMPERE, 0xE00C, pci_quirk_xgene_acs },
|
||||||
|
/* Broadcom multi-function device */
|
||||||
|
{ PCI_VENDOR_ID_BROADCOM, 0x16D7, pci_quirk_mf_endpoint_acs },
|
||||||
{ PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
|
{ PCI_VENDOR_ID_BROADCOM, 0xD714, pci_quirk_brcm_acs },
|
||||||
/* Amazon Annapurna Labs */
|
/* Amazon Annapurna Labs */
|
||||||
{ PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs },
|
{ PCI_VENDOR_ID_AMAZON_ANNAPURNA_LABS, 0x0031, pci_quirk_al_acs },
|
||||||
|
@ -5154,7 +5243,8 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, 0x0422, quirk_no_ext_tags);
|
||||||
static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
|
static void quirk_amd_harvest_no_ats(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
if ((pdev->device == 0x7312 && pdev->revision != 0x00) ||
|
if ((pdev->device == 0x7312 && pdev->revision != 0x00) ||
|
||||||
(pdev->device == 0x7340 && pdev->revision != 0xc5))
|
(pdev->device == 0x7340 && pdev->revision != 0xc5) ||
|
||||||
|
(pdev->device == 0x7341 && pdev->revision != 0x00))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pdev->device == 0x15d8) {
|
if (pdev->device == 0x15d8) {
|
||||||
|
@ -5181,6 +5271,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x6900, quirk_amd_harvest_no_ats);
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7312, quirk_amd_harvest_no_ats);
|
||||||
/* AMD Navi14 dGPU */
|
/* AMD Navi14 dGPU */
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7340, quirk_amd_harvest_no_ats);
|
||||||
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x7341, quirk_amd_harvest_no_ats);
|
||||||
/* AMD Raven platform iGPU */
|
/* AMD Raven platform iGPU */
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
|
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x15d8, quirk_amd_harvest_no_ats);
|
||||||
#endif /* CONFIG_PCI_ATS */
|
#endif /* CONFIG_PCI_ATS */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче