aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDuc Dang <dhdang@apm.com>2015-06-12 20:35:57 -0400
committerBjorn Helgaas <bhelgaas@google.com>2015-06-18 13:09:03 -0400
commitf09f8735fb9ca113239fead45d96a48660cc2ae3 (patch)
treefe12e44c989b3bcd9498f43ee7cc71ed40cdf70f
parente1e6e5c4de24cee3b1bdde52661a8c493351d3cb (diff)
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 <ian.campbell@citrix.com> Tested-by: Marcin Juszkiewicz <mjuszkiewicz@redhat.com> Signed-off-by: Duc Dang <dhdang@apm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Tanmay Inamdar <tinamdar@apm.com>
-rw-r--r--drivers/pci/host/pci-xgene.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index 3e5a636c9a9a..70af714a2d43 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -59,6 +59,12 @@
59#define SZ_1T (SZ_1G*1024ULL) 59#define SZ_1T (SZ_1G*1024ULL)
60#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe) 60#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
61 61
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
62struct xgene_pcie_port { 68struct xgene_pcie_port {
63 struct device_node *node; 69 struct device_node *node;
64 struct device *dev; 70 struct device *dev;
@@ -67,6 +73,7 @@ struct xgene_pcie_port {
67 void __iomem *cfg_base; 73 void __iomem *cfg_base;
68 unsigned long cfg_addr; 74 unsigned long cfg_addr;
69 bool link_up; 75 bool link_up;
76 u32 version;
70}; 77};
71 78
72static inline u32 pcie_bar_low_val(u32 addr, u32 flags) 79static 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,
140 return xgene_pcie_get_cfg_base(bus) + offset; 147 return xgene_pcie_get_cfg_base(bus) + offset;
141} 148}
142 149
150static 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
143static struct pci_ops xgene_pcie_ops = { 178static struct pci_ops xgene_pcie_ops = {
144 .map_bus = xgene_pcie_map_bus, 179 .map_bus = xgene_pcie_map_bus,
145 .read = pci_generic_config_read32, 180 .read = xgene_pcie_config_read32,
146 .write = pci_generic_config_write32, 181 .write = pci_generic_config_write32,
147}; 182};
148 183
@@ -500,6 +535,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
500 port->node = of_node_get(pdev->dev.of_node); 535 port->node = of_node_get(pdev->dev.of_node);
501 port->dev = &pdev->dev; 536 port->dev = &pdev->dev;
502 537
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
503 ret = xgene_pcie_map_reg(port, pdev); 542 ret = xgene_pcie_map_reg(port, pdev);
504 if (ret) 543 if (ret)
505 return ret; 544 return ret;