These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / pci / host / pci-xgene.c
index ee082c0..ae00ce2 100644 (file)
 #define SZ_1T                          (SZ_1G*1024ULL)
 #define PIPE_PHY_RATE_RD(src)          ((0xc000 & (u32)(src)) >> 0xe)
 
+#define ROOT_CAP_AND_CTRL              0x5C
+
+/* PCIe IP version */
+#define XGENE_PCIE_IP_VER_UNKN         0
+#define XGENE_PCIE_IP_VER_1            1
+
 struct xgene_pcie_port {
        struct device_node      *node;
        struct device           *dev;
@@ -67,6 +73,7 @@ struct xgene_pcie_port {
        void __iomem            *cfg_base;
        unsigned long           cfg_addr;
        bool                    link_up;
+       u32                     version;
 };
 
 static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
@@ -130,9 +137,7 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
 static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
                              int offset)
 {
-       struct xgene_pcie_port *port = bus->sysdata;
-
-       if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up ||
+       if ((pci_is_root_bus(bus) && devfn != 0) ||
            xgene_pcie_hide_rc_bars(bus, offset))
                return NULL;
 
@@ -140,9 +145,37 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
        return xgene_pcie_get_cfg_base(bus) + offset;
 }
 
+static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn,
+                                   int where, int size, u32 *val)
+{
+       struct xgene_pcie_port *port = bus->sysdata;
+
+       if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) !=
+           PCIBIOS_SUCCESSFUL)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /*
+        * The v1 controller has a bug in its Configuration Request
+        * Retry Status (CRS) logic: when CRS 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 ("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.
+        */
+       if (pci_is_root_bus(bus) && (port->version == XGENE_PCIE_IP_VER_1) &&
+           ((where & ~0x3) == ROOT_CAP_AND_CTRL))
+               *val &= ~(PCI_EXP_RTCAP_CRSVIS << 16);
+
+       if (size <= 2)
+               *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
 static struct pci_ops xgene_pcie_ops = {
        .map_bus = xgene_pcie_map_bus,
-       .read = pci_generic_config_read32,
+       .read = xgene_pcie_config_read32,
        .write = pci_generic_config_write32,
 };
 
@@ -288,8 +321,16 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
                                return ret;
                        break;
                case IORESOURCE_MEM:
-                       xgene_pcie_setup_ob_reg(port, res, OMR1BARL, res->start,
-                                               res->start - window->offset);
+                       if (res->flags & IORESOURCE_PREFETCH)
+                               xgene_pcie_setup_ob_reg(port, res, OMR2BARL,
+                                                       res->start,
+                                                       res->start -
+                                                       window->offset);
+                       else
+                               xgene_pcie_setup_ob_reg(port, res, OMR1BARL,
+                                                       res->start,
+                                                       res->start -
+                                                       window->offset);
                        break;
                case IORESOURCE_BUS:
                        break;
@@ -483,6 +524,10 @@ static int xgene_pcie_probe_bridge(struct platform_device *pdev)
        port->node = of_node_get(pdev->dev.of_node);
        port->dev = &pdev->dev;
 
+       port->version = XGENE_PCIE_IP_VER_UNKN;
+       if (of_device_is_compatible(port->node, "apm,xgene-pcie"))
+               port->version = XGENE_PCIE_IP_VER_1;
+
        ret = xgene_pcie_map_reg(port, pdev);
        if (ret)
                return ret;