Skip to content

Commit

Permalink
Merge branch 'pci/errors'
Browse files Browse the repository at this point in the history
- Add PCI_ERROR_RESPONSE and related definitions for signaling and checking
  for transaction errors on PCI (Naveen Naidu)

- Fabricate PCI_ERROR_RESPONSE data (~0) in config read wrappers, instead
  of in host controller drivers, when transactions fail on PCI (Naveen
  Naidu)

- Use PCI_POSSIBLE_ERROR() to check for possible failure of config reads
  (Naveen Naidu)

* pci/errors:
  PCI: xgene: Use PCI_ERROR_RESPONSE to identify config read errors
  PCI: hv: Use PCI_ERROR_RESPONSE to identify config read errors
  PCI: keystone: Use PCI_ERROR_RESPONSE to identify config read errors
  PCI: Use PCI_ERROR_RESPONSE to identify config read errors
  PCI: cpqphp: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI/PME: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI/DPC: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI: pciehp: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI: vmd: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI/ERR: Use PCI_POSSIBLE_ERROR() to check config reads
  PCI: rockchip-host: Drop error data fabrication when config read fails
  PCI: rcar-host: Drop error data fabrication when config read fails
  PCI: altera: Drop error data fabrication when config read fails
  PCI: mvebu: Drop error data fabrication when config read fails
  PCI: aardvark: Drop error data fabrication when config read fails
  PCI: kirin: Drop error data fabrication when config read fails
  PCI: histb: Drop error data fabrication when config read fails
  PCI: exynos: Drop error data fabrication when config read fails
  PCI: mediatek: Drop error data fabrication when config read fails
  PCI: iproc: Drop error data fabrication when config read fails
  PCI: thunder: Drop error data fabrication when config read fails
  PCI: Drop error data fabrication when config read fails
  PCI: Use PCI_SET_ERROR_RESPONSE() for disconnected devices
  PCI: Set error response data when config read fails
  PCI: Add PCI_ERROR_RESPONSE and related definitions
  • Loading branch information
Bjorn Helgaas committed Jan 13, 2022
2 parents da43f08 + c78b9a9 commit f5d3ca6
Show file tree
Hide file tree
Showing 24 changed files with 88 additions and 120 deletions.
36 changes: 19 additions & 17 deletions drivers/pci/access.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ int noinline pci_bus_read_config_##size \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
pci_lock_config(flags); \
res = bus->ops->read(bus, devfn, pos, len, &data); \
*value = (type)data; \
if (res) \
PCI_SET_ERROR_RESPONSE(value); \
else \
*value = (type)data; \
pci_unlock_config(flags); \
return res; \
}
Expand Down Expand Up @@ -80,10 +83,8 @@ int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn,
void __iomem *addr;

addr = bus->ops->map_bus(bus, devfn, where);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

if (size == 1)
*val = readb(addr);
Expand Down Expand Up @@ -122,10 +123,8 @@ int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn,
void __iomem *addr;

addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

*val = readl(addr);

Expand Down Expand Up @@ -228,7 +227,10 @@ int pci_user_read_config_##size \
ret = dev->bus->ops->read(dev->bus, dev->devfn, \
pos, sizeof(type), &data); \
raw_spin_unlock_irq(&pci_lock); \
*val = (type)data; \
if (ret) \
PCI_SET_ERROR_RESPONSE(val); \
else \
*val = (type)data; \
return pcibios_err_to_errno(ret); \
} \
EXPORT_SYMBOL_GPL(pci_user_read_config_##size);
Expand Down Expand Up @@ -410,9 +412,9 @@ int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
/*
* Reset *val to 0 if pci_read_config_word() fails, it may
* have been written as 0xFFFF if hardware error happens
* during pci_read_config_word().
* Reset *val to 0 if pci_read_config_word() fails; it may
* have been written as 0xFFFF (PCI_ERROR_RESPONSE) if the
* config read failed on PCI.
*/
if (ret)
*val = 0;
Expand Down Expand Up @@ -445,9 +447,9 @@ int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
if (pcie_capability_reg_implemented(dev, pos)) {
ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
/*
* Reset *val to 0 if pci_read_config_dword() fails, it may
* have been written as 0xFFFFFFFF if hardware error happens
* during pci_read_config_dword().
* Reset *val to 0 if pci_read_config_dword() fails; it may
* have been written as 0xFFFFFFFF (PCI_ERROR_RESPONSE) if
* the config read failed on PCI.
*/
if (ret)
*val = 0;
Expand Down Expand Up @@ -523,7 +525,7 @@ EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
{
if (pci_dev_is_disconnected(dev)) {
*val = ~0;
PCI_SET_ERROR_RESPONSE(val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
Expand All @@ -533,7 +535,7 @@ EXPORT_SYMBOL(pci_read_config_byte);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
{
if (pci_dev_is_disconnected(dev)) {
*val = ~0;
PCI_SET_ERROR_RESPONSE(val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
Expand All @@ -544,7 +546,7 @@ int pci_read_config_dword(const struct pci_dev *dev, int where,
u32 *val)
{
if (pci_dev_is_disconnected(dev)) {
*val = ~0;
PCI_SET_ERROR_RESPONSE(val);
return PCIBIOS_DEVICE_NOT_FOUND;
}
return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/dwc/pci-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,8 @@ static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
{
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);

if (PCI_SLOT(devfn)) {
*val = ~0;
if (PCI_SLOT(devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
}

*val = dw_pcie_read_dbi(pci, where, size);
return PCIBIOS_SUCCESSFUL;
Expand Down
6 changes: 3 additions & 3 deletions drivers/pci/controller/dwc/pci-keystone.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,9 +747,9 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)

#ifdef CONFIG_ARM
/*
* When a PCI device does not exist during config cycles, keystone host gets a
* bus error instead of returning 0xffffffff. This handler always returns 0
* for this kind of faults.
* When a PCI device does not exist during config cycles, keystone host
* gets a bus error instead of returning 0xffffffff (PCI_ERROR_RESPONSE).
* This handler always returns 0 for this kind of fault.
*/
static int ks_pcie_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/dwc/pcie-histb.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,8 @@ static int histb_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
{
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);

if (PCI_SLOT(devfn)) {
*val = ~0;
if (PCI_SLOT(devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
}

*val = dw_pcie_read_dbi(pci, where, size);
return PCIBIOS_SUCCESSFUL;
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/dwc/pcie-kirin.c
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,8 @@ static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
{
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);

if (PCI_SLOT(devfn)) {
*val = ~0;
if (PCI_SLOT(devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
}

*val = dw_pcie_read_dbi(pci, where, size);
return PCIBIOS_SUCCESSFUL;
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/pci-aardvark.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,10 +1037,8 @@ static int advk_pcie_rd_conf(struct pci_bus *bus, u32 devfn,
u32 reg;
int ret;

if (!advk_pcie_valid_device(pcie, bus, devfn)) {
*val = 0xffffffff;
if (!advk_pcie_valid_device(pcie, bus, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
}

if (pci_is_root_bus(bus))
return pci_bridge_emul_conf_read(&pcie->bridge, where,
Expand Down
2 changes: 1 addition & 1 deletion drivers/pci/controller/pci-hyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -2030,7 +2030,7 @@ static void prepopulate_bars(struct hv_pcibus_device *hbus)
* If the memory enable bit is already set, Hyper-V silently ignores
* the below BAR updates, and the related PCI device driver can not
* work, because reading from the device register(s) always returns
* 0xFFFFFFFF.
* 0xFFFFFFFF (PCI_ERROR_RESPONSE).
*/
list_for_each_entry(hpdev, &hbus->children, list_entry) {
_hv_pcifront_read_config(hpdev, PCI_COMMAND, 2, &command);
Expand Down
8 changes: 2 additions & 6 deletions drivers/pci/controller/pci-mvebu.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,20 +814,16 @@ static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
int ret;

port = mvebu_pcie_find_port(pcie, bus, devfn);
if (!port) {
*val = 0xffffffff;
if (!port)
return PCIBIOS_DEVICE_NOT_FOUND;
}

/* Access the emulated PCI-to-PCI bridge */
if (bus->number == 0)
return pci_bridge_emul_conf_read(&port->bridge, where,
size, val);

if (!mvebu_pcie_link_up(port)) {
*val = 0xffffffff;
if (!mvebu_pcie_link_up(port))
return PCIBIOS_DEVICE_NOT_FOUND;
}

/* Access the real PCIe interface */
ret = mvebu_pcie_hw_rd_conf(port, bus, devfn,
Expand Down
46 changes: 16 additions & 30 deletions drivers/pci/controller/pci-thunder-ecam.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
}
if (where_a == 0x4) {
addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr);
v &= ~0xf;
v |= 2; /* EA entry-1. Base-L */
Expand All @@ -56,10 +55,9 @@ static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
u32 barl_rb;

addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

barl_orig = readl(addr + 0);
writel(0xffffffff, addr + 0);
barl_rb = readl(addr + 0);
Expand All @@ -72,10 +70,9 @@ static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,
}
if (where_a == 0xc) {
addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr); /* EA entry-3. Base-H */
set_val(v, where, size, val);
return PCIBIOS_SUCCESSFUL;
Expand Down Expand Up @@ -104,10 +101,8 @@ static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,
}

addr = bus->ops->map_bus(bus, devfn, where_a);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr);

Expand Down Expand Up @@ -135,21 +130,17 @@ static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
int where_a = where & ~3;

addr = bus->ops->map_bus(bus, devfn, 0xc);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr);

/* Check for non type-00 header */
cfg_type = (v >> 16) & 0x7f;

addr = bus->ops->map_bus(bus, devfn, 8);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

class_rev = readl(addr);
if (class_rev == 0xffffffff)
Expand All @@ -176,10 +167,8 @@ static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
}

addr = bus->ops->map_bus(bus, devfn, 0);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

vendor_device = readl(addr);
if (vendor_device == 0xffffffff)
Expand All @@ -196,10 +185,9 @@ static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
bool is_tns = (vendor_device == 0xa01f177d);

addr = bus->ops->map_bus(bus, devfn, 0x70);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

/* E_CAP */
v = readl(addr);
has_msix = (v & 0xff00) != 0;
Expand All @@ -211,10 +199,9 @@ static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,
}
if (where_a == 0xb0) {
addr = bus->ops->map_bus(bus, devfn, where_a);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr);
if (v & 0xff00)
pr_err("Bad MSIX cap header: %08x\n", v);
Expand Down Expand Up @@ -268,10 +255,9 @@ static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,

if (where_a == 0x70) {
addr = bus->ops->map_bus(bus, devfn, where_a);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

v = readl(addr);
if (v & 0xff00)
pr_err("Bad PCIe cap header: %08x\n", v);
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/pci-thunder-pem.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,8 @@ static int thunder_pem_bridge_read(struct pci_bus *bus, unsigned int devfn,
struct pci_config_window *cfg = bus->sysdata;
struct thunder_pem_pci *pem_pci = (struct thunder_pem_pci *)cfg->priv;

if (devfn != 0 || where >= 2048) {
*val = ~0;
if (devfn != 0 || where >= 2048)
return PCIBIOS_DEVICE_NOT_FOUND;
}

/*
* 32-bit accesses only. Write the address to the low order
Expand Down
10 changes: 5 additions & 5 deletions drivers/pci/controller/pci-xgene.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
return PCIBIOS_DEVICE_NOT_FOUND;

/*
* The v1 controller has a bug in its Configuration Request
* Retry Status (CRS) logic: when CRS Software Visibility is
* enabled and we read the Vendor and Device ID of a non-existent
* device, the controller fabricates return data of 0xFFFF0001
* ("device exists but is not ready") instead of 0xFFFFFFFF
* The v1 controller has a bug in its Configuration Request Retry
* Status (CRS) logic: when CRS Software Visibility is enabled and
* we read the Vendor and Device ID of a non-existent device, the
* controller fabricates return data of 0xFFFF0001 ("device exists
* but is not ready") instead of 0xFFFFFFFF (PCI_ERROR_RESPONSE)
* ("device does not exist"). This causes the PCI core to retry
* the read until it times out. Avoid this by not claiming to
* support CRS SV.
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/pcie-altera.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,10 +510,8 @@ static int altera_pcie_cfg_read(struct pci_bus *bus, unsigned int devfn,
if (altera_pcie_hide_rc_bar(bus, devfn, where))
return PCIBIOS_BAD_REGISTER_NUMBER;

if (!altera_pcie_valid_device(pcie, bus, PCI_SLOT(devfn))) {
*value = 0xffffffff;
if (!altera_pcie_valid_device(pcie, bus, PCI_SLOT(devfn)))
return PCIBIOS_DEVICE_NOT_FOUND;
}

return _altera_pcie_cfg_read(pcie, bus->number, devfn, where, size,
value);
Expand Down
4 changes: 1 addition & 3 deletions drivers/pci/controller/pcie-iproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,8 @@ static int iproc_pci_raw_config_read32(struct iproc_pcie *pcie,
void __iomem *addr;

addr = iproc_pcie_map_cfg_bus(pcie, 0, devfn, where & ~0x3);
if (!addr) {
*val = ~0;
if (!addr)
return PCIBIOS_DEVICE_NOT_FOUND;
}

*val = readl(addr);

Expand Down
11 changes: 2 additions & 9 deletions drivers/pci/controller/pcie-mediatek.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,19 +365,12 @@ static int mtk_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
{
struct mtk_pcie_port *port;
u32 bn = bus->number;
int ret;

port = mtk_pcie_find_port(bus, devfn);
if (!port) {
*val = ~0;
if (!port)
return PCIBIOS_DEVICE_NOT_FOUND;
}

ret = mtk_pcie_hw_rd_cfg(port, bn, devfn, where, size, val);
if (ret)
*val = ~0;

return ret;
return mtk_pcie_hw_rd_cfg(port, bn, devfn, where, size, val);
}

static int mtk_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
Expand Down
Loading

0 comments on commit f5d3ca6

Please sign in to comment.