Skip to content

Commit f09f873

Browse files
dhdangbjorn-helgaas
authored andcommitted
PCI: xgene: Disable Configuration Request Retry Status for v1 silicon
When a CPU reads the Vendor and Device ID of a non-existent device, the controller should fabricate return data of 0xFFFFFFFF. Configuration Request Retry Status (CRS) is not applicable in this case because the device doesn't exist at all. The X-Gene v1 PCIe controller has a bug in the CRS logic such that when CRS is enabled, it fabricates return data of 0xFFFF0001 for this case, which means "the device exists but is not ready." That causes the PCI core to retry the read until it times out after 60 seconds. Disable CRS capability advertisement by clearing the CRS Software Visibility bit in the Root Capabilities Register. [bhelgaas: changelog and comment] Tested-by: Ian Campbell <[email protected]> Tested-by: Marcin Juszkiewicz <[email protected]> Signed-off-by: Duc Dang <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Acked-by: Tanmay Inamdar <[email protected]>
1 parent e1e6e5c commit f09f873

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

drivers/pci/host/pci-xgene.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@
5959
#define SZ_1T (SZ_1G*1024ULL)
6060
#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
6161

62+
#define ROOT_CAP_AND_CTRL 0x5C
63+
64+
/* PCIe IP version */
65+
#define XGENE_PCIE_IP_VER_UNKN 0
66+
#define XGENE_PCIE_IP_VER_1 1
67+
6268
struct xgene_pcie_port {
6369
struct device_node *node;
6470
struct device *dev;
@@ -67,6 +73,7 @@ struct xgene_pcie_port {
6773
void __iomem *cfg_base;
6874
unsigned long cfg_addr;
6975
bool link_up;
76+
u32 version;
7077
};
7178

7279
static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
@@ -140,9 +147,37 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
140147
return xgene_pcie_get_cfg_base(bus) + offset;
141148
}
142149

150+
static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
151+
int where, int size, u32 *val)
152+
{
153+
struct xgene_pcie_port *port = bus->sysdata;
154+
155+
if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
156+
PCIBIOS_SUCCESSFUL)
157+
return PCIBIOS_DEVICE_NOT_FOUND;
158+
159+
/*
160+
* The v1 controller has a bug in its Configuration Request
161+
* Retry Status (CRS) logic: when CRS is enabled and we read the
162+
* Vendor and Device ID of a non-existent device, the controller
163+
* fabricates return data of 0xFFFF0001 ("device exists but is not
164+
* ready") instead of 0xFFFFFFFF ("device does not exist"). This
165+
* causes the PCI core to retry the read until it times out.
166+
* Avoid this by not claiming to support CRS.
167+
*/
168+
if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) &&
169+
((where & ~0x3) == ROOT_CAP_AND_CTRL))
170+
*val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
171+
172+
if (size <= 2)
173+
*val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
174+
175+
return PCIBIOS_SUCCESSFUL;
176+
}
177+
143178
static struct pci_ops xgene_pcie_ops = {
144179
.map_bus = xgene_pcie_map_bus,
145-
.read = pci_generic_config_read32,
180+
.read = xgene_pcie_config_read32,
146181
.write = pci_generic_config_write32,
147182
};
148183

@@ -500,6 +535,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
500535
port->node = of_node_get(pdev->dev.of_node);
501536
port->dev = &pdev->dev;
502537

538+
port->version = XGENE_PCIE_IP_VER_UNKN;
539+
if (of_device_is_compatible(port->node, "apm,xgene-pcie"))
540+
port->version = XGENE_PCIE_IP_VER_1;
541+
503542
ret = xgene_pcie_map_reg(port, pdev);
504543
if (ret)
505544
return ret;

0 commit comments

Comments
 (0)