Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1415021/?format=api
{ "id": 1415021, "url": "http://patchwork.ozlabs.org/api/patches/1415021/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20201211160612.1498780-42-sr@denx.de/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20201211160612.1498780-42-sr@denx.de>", "list_archive_url": null, "date": "2020-12-11T16:06:03", "name": "[v1,41/50] mips: octeon: Add cvmx-pcie.c", "commit_ref": "646ed331b634126c9d7d2e6cd1409bbad38916c1", "pull_url": null, "state": "accepted", "archived": false, "hash": "4999e55844e6d07949e6538e12f123d732f1f3f1", "submitter": { "id": 13, "url": "http://patchwork.ozlabs.org/api/people/13/?format=api", "name": "Stefan Roese", "email": "sr@denx.de" }, "delegate": { "id": 4307, "url": "http://patchwork.ozlabs.org/api/users/4307/?format=api", "username": "danielschwierzeck", "first_name": "Daniel", "last_name": "Schwierzeck", "email": "daniel.schwierzeck@googlemail.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20201211160612.1498780-42-sr@denx.de/mbox/", "series": [ { "id": 220054, "url": "http://patchwork.ozlabs.org/api/series/220054/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=220054", "date": "2020-12-11T16:05:23", "name": "mips: octeon: Add serdes and device helper support incl. DM PCIe driver", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/220054/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1415021/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1415021/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=<UNKNOWN>)", "ozlabs.org;\n dmarc=none (p=none dis=none) header.from=denx.de", "ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=denx.de header.i=@denx.de header.a=rsa-sha256\n header.s=phobos-20191101 header.b=k8DyQmY5;\n\tdkim-atps=neutral", "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=denx.de", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n dmarc=none (p=none dis=none) header.from=denx.de", "phobos.denx.de; spf=none smtp.mailfrom=sr@denx.de" ], "Received": [ "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4Cswqh3nq9z9sSs\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 12 Dec 2020 03:15:28 +1100 (AEDT)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 47CF2827EB;\n\tFri, 11 Dec 2020 17:09:38 +0100 (CET)", "by phobos.denx.de (Postfix, from userid 109)\n id 01633827CA; Fri, 11 Dec 2020 17:08:52 +0100 (CET)", "from mx2.mailbox.org (mx2a.mailbox.org\n [IPv6:2001:67c:2050:104:0:2:25:2])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 633AC82766\n for <u-boot@lists.denx.de>; Fri, 11 Dec 2020 17:06:31 +0100 (CET)", "from smtp1.mailbox.org (smtp1.mailbox.org [80.241.60.240])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest\n SHA256) (No client certificate requested)\n by mx2.mailbox.org (Postfix) with ESMTPS id 0F044A0E6D;\n Fri, 11 Dec 2020 17:06:31 +0100 (CET)", "from smtp1.mailbox.org ([80.241.60.240])\n by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de\n [80.241.56.125]) (amavisd-new, port 10030)\n with ESMTP id G7rRc78F3I6u; Fri, 11 Dec 2020 17:06:25 +0100 (CET)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=denx.de;\n\ts=phobos-20191101; t=1607702978;\n\tbh=rsxTG4YvrZh6YKojSzB4pFofdXHx6XBJFbeTVS2ExRs=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id:\n\t List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe:\n\t From;\n\tb=k8DyQmY5JL7ummEqdO/EJSXEDcI50ylAgc1SI8/XTnbDky/0oJRgShwjkasQwNDft\n\t YoBb1HSfWyruac6aocv0HDQ6w8g2yBjY6e4gHN8lb5IPeeZT+xtq4WzDEDo8juyJ00\n\t dZO/pNCQO2/oOl4WzBRv5pq7dWauFWHohMhEQF/EhgSL1HJX1goJefvFSDwj97YRbt\n\t lnS4RRj0bi1+6Ox/zlh4G91+09qYMUPjgMW3wCLNxhO/0SSDFq7PnATWu/Fu53hF9T\n\t n9n3MAsoVnQDiQzHz/D3HFO9djWdCjcDcTzzyshML4kNF9c0TcTimjDgcEhSC00jQl\n\t n4/XlIO8gVHFA==", "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW,\n SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2", "From": "Stefan Roese <sr@denx.de>", "To": "u-boot@lists.denx.de", "Cc": "daniel.schwierzeck@gmail.com, awilliams@marvell.com, cchavva@marvell.com", "Subject": "[PATCH v1 41/50] mips: octeon: Add cvmx-pcie.c", "Date": "Fri, 11 Dec 2020 17:06:03 +0100", "Message-Id": "<20201211160612.1498780-42-sr@denx.de>", "In-Reply-To": "<20201211160612.1498780-1-sr@denx.de>", "References": "<20201211160612.1498780-1-sr@denx.de>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-MBO-SPAM-Probability": "**", "X-Rspamd-Score": "2.32 / 15.00 / 15.00", "X-Rspamd-Queue-Id": "024161884", "X-Rspamd-UID": "6163bd", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.34", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>", "X-Virus-Scanned": "clamav-milter 0.102.3 at phobos.denx.de", "X-Virus-Status": "Clean" }, "content": "From: Aaron Williams <awilliams@marvell.com>\n\nImport cvmx-pcie.c from 2013 U-Boot. It will be used by the later\nadded drivers to support PCIe and networking on the MIPS Octeon II / III\nplatforms.\n\nSigned-off-by: Aaron Williams <awilliams@marvell.com>\nSigned-off-by: Stefan Roese <sr@denx.de>\n---\n\n arch/mips/mach-octeon/cvmx-pcie.c | 2487 +++++++++++++++++++++++++++++\n 1 file changed, 2487 insertions(+)\n create mode 100644 arch/mips/mach-octeon/cvmx-pcie.c", "diff": "diff --git a/arch/mips/mach-octeon/cvmx-pcie.c b/arch/mips/mach-octeon/cvmx-pcie.c\nnew file mode 100644\nindex 0000000000..f42d44cbec\n--- /dev/null\n+++ b/arch/mips/mach-octeon/cvmx-pcie.c\n@@ -0,0 +1,2487 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2020 Marvell International Ltd.\n+ *\n+ * Interface to PCIe as a host(RC) or target(EP)\n+ */\n+\n+#include <log.h>\n+#include <linux/delay.h>\n+#include <linux/libfdt.h>\n+\n+#include <mach/cvmx-regs.h>\n+#include <mach/octeon-model.h>\n+#include <mach/cvmx-fuse.h>\n+#include <mach/octeon-feature.h>\n+#include <mach/cvmx-qlm.h>\n+#include <mach/octeon_qlm.h>\n+\n+#include <mach/cvmx-helper-fdt.h>\n+\n+#include <mach/cvmx-regs.h>\n+#include <mach/octeon-model.h>\n+#include <mach/cvmx-fuse.h>\n+#include <mach/octeon-feature.h>\n+#include <mach/cvmx-qlm.h>\n+#include <mach/octeon_qlm.h>\n+#include <mach/cvmx-pcie.h>\n+#include <mach/cvmx-error.h>\n+#include <mach/cvmx-helper.h>\n+#include <mach/cvmx-helper-util.h>\n+#include <mach/cvmx-bgxx-defs.h>\n+#include <mach/cvmx-ciu-defs.h>\n+#include <mach/cvmx-gmxx-defs.h>\n+#include <mach/cvmx-gserx-defs.h>\n+#include <mach/cvmx-mio-defs.h>\n+#include <mach/cvmx-pciercx-defs.h>\n+#include <mach/cvmx-pcieepx-defs.h>\n+#include <mach/cvmx-pemx-defs.h>\n+#include <mach/cvmx-pexp-defs.h>\n+#include <mach/cvmx-rst-defs.h>\n+#include <mach/cvmx-sata-defs.h>\n+#include <mach/cvmx-sli-defs.h>\n+#include <mach/cvmx-sriomaintx-defs.h>\n+#include <mach/cvmx-sriox-defs.h>\n+\n+#include <mach/cvmx-dpi-defs.h>\n+#include <mach/cvmx-sli-defs.h>\n+#include <mach/cvmx-dtx-defs.h>\n+\n+DECLARE_GLOBAL_DATA_PTR;\n+\n+#define MRRS_CN6XXX 3 /* 1024 byte Max Read Request Size */\n+#define MPS_CN6XXX 0 /* 128 byte Max Packet Size (Limit of most PCs) */\n+\n+/* Endian swap mode. */\n+#define _CVMX_PCIE_ES 1\n+\n+#define CVMX_READ_CSR(addr)\t\t csr_rd_node(node, addr)\n+#define CVMX_WRITE_CSR(addr, val)\t csr_wr_node(node, addr, val)\n+#define CVMX_PCIE_CFGX_READ(p, addr)\t cvmx_pcie_cfgx_read_node(node, p, addr)\n+#define CVMX_PCIE_CFGX_WRITE(p, addr, val) cvmx_pcie_cfgx_write_node(node, p, addr, val)\n+\n+/* #define DEBUG_PCIE */\n+\n+/* Delay after link up, before issuing first configuration read */\n+#define PCIE_DEVICE_READY_WAIT_DELAY_MICROSECONDS 700000\n+\n+/* Recommended Preset Vector: Drop Preset 10 */\n+int pcie_preset_vec[4] = { 0x593, 0x593, 0x593, 0x593 };\n+\n+/* Number of LTSSM transitions to record, must be a power of 2 */\n+#define LTSSM_HISTORY_SIZE 64\n+#define MAX_RETRIES\t 2\n+\n+bool pcie_link_initialized[CVMX_MAX_NODES][CVMX_PCIE_MAX_PORTS];\n+int cvmx_primary_pcie_bus_number = 1;\n+\n+static uint32_t __cvmx_pcie_config_read32(int node, int pcie_port, int bus, int dev, int func,\n+\t\t\t\t\t int reg, int lst);\n+\n+/**\n+ * Return the Core virtual base address for PCIe IO access. IOs are\n+ * read/written as an offset from this address.\n+ *\n+ * @param pcie_port PCIe port the IO is for\n+ *\n+ * @return 64bit Octeon IO base address for read/write\n+ */\n+uint64_t cvmx_pcie_get_io_base_address(int pcie_port)\n+{\n+\tcvmx_pcie_address_t pcie_addr;\n+\n+\tpcie_addr.u64 = 0;\n+\tpcie_addr.io.upper = 0;\n+\tpcie_addr.io.io = 1;\n+\tpcie_addr.io.did = 3;\n+\tpcie_addr.io.subdid = 2;\n+\tpcie_addr.io.node = (pcie_port >> 4) & 0x3;\n+\tpcie_addr.io.es = _CVMX_PCIE_ES;\n+\tpcie_addr.io.port = (pcie_port & 0x3);\n+\treturn pcie_addr.u64;\n+}\n+\n+/**\n+ * Size of the IO address region returned at address\n+ * cvmx_pcie_get_io_base_address()\n+ *\n+ * @param pcie_port PCIe port the IO is for\n+ *\n+ * @return Size of the IO window\n+ */\n+uint64_t cvmx_pcie_get_io_size(int pcie_port)\n+{\n+\treturn 1ull << 32;\n+}\n+\n+/**\n+ * Return the Core virtual base address for PCIe MEM access. Memory is\n+ * read/written as an offset from this address.\n+ *\n+ * @param pcie_port PCIe port the IO is for\n+ *\n+ * @return 64bit Octeon IO base address for read/write\n+ */\n+uint64_t cvmx_pcie_get_mem_base_address(int pcie_port)\n+{\n+\tcvmx_pcie_address_t pcie_addr;\n+\n+\tpcie_addr.u64 = 0;\n+\tpcie_addr.mem.upper = 0;\n+\tpcie_addr.mem.io = 1;\n+\tpcie_addr.mem.did = 3;\n+\tpcie_addr.mem.subdid = 3 + (pcie_port & 0x3);\n+\tpcie_addr.mem.node = (pcie_port >> 4) & 0x3;\n+\treturn pcie_addr.u64;\n+}\n+\n+/**\n+ * Size of the Mem address region returned at address\n+ * cvmx_pcie_get_mem_base_address()\n+ *\n+ * @param pcie_port PCIe port the IO is for\n+ *\n+ * @return Size of the Mem window\n+ */\n+uint64_t cvmx_pcie_get_mem_size(int pcie_port)\n+{\n+\treturn 1ull << 36;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Return the QLM number for the PCIE port.\n+ *\n+ * @param pcie_port QLM number to return for.\n+ *\n+ * @return QLM number.\n+ */\n+static int __cvmx_pcie_get_qlm(int node, int pcie_port)\n+{\n+\tif (OCTEON_IS_MODEL(OCTEON_CN73XX)) {\n+\t\tcvmx_pemx_cfg_t pem_cfg;\n+\t\tcvmx_pemx_qlm_t pem_qlm;\n+\t\tcvmx_gserx_cfg_t gserx_cfg;\n+\n+\t\tswitch (pcie_port) {\n+\t\tcase 0: /* PEM0 */\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(0));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 0; /* PEM0 is on QLM0 and possibly QLM1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM0 is disabled */\n+\t\tcase 1:\t\t\t /* PEM1 */\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(0));\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(1));\n+\t\t\tif (!pem_cfg.cn78xx.lanes8 && gserx_cfg.s.pcie)\n+\t\t\t\treturn 1; /* PEM1 is on QLM 1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM1 is disabled */\n+\t\tcase 2:\t\t\t /* PEM2 */\n+\t\t\tpem_qlm.u64 = CVMX_READ_CSR(CVMX_PEMX_QLM(2));\n+\t\t\tif (pem_qlm.cn73xx.pemdlmsel == 1) {\n+\t\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(5));\n+\t\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\t\treturn 5; /* PEM2 is on DLM5 */\n+\t\t\t\telse\n+\t\t\t\t\treturn -1; /* PEM2 is disabled */\n+\t\t\t}\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(2));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 2; /* PEM2 is on QLM2 and possibly QLM3 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM2 is disabled */\n+\t\tcase 3:\t\t\t /* PEM3 */\n+\t\t\tpem_qlm.u64 = CVMX_READ_CSR(CVMX_PEMX_QLM(3));\n+\t\t\tif (pem_qlm.cn73xx.pemdlmsel == 1) {\n+\t\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(6));\n+\t\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\t\treturn 6; /* PEM2 is on DLM5 */\n+\t\t\t\telse\n+\t\t\t\t\treturn -1; /* PEM2 is disabled */\n+\t\t\t}\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(2));\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(3));\n+\t\t\tif (!pem_cfg.cn78xx.lanes8 && gserx_cfg.s.pcie)\n+\t\t\t\treturn 3; /* PEM2 is on QLM2 and possibly QLM3 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM2 is disabled */\n+\t\tdefault:\n+\t\t\tprintf(\"Invalid %d PCIe port\\n\", pcie_port);\n+\t\t\treturn -2;\n+\t\t}\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {\n+\t\tcvmx_pemx_cfg_t pem_cfg;\n+\t\tcvmx_gserx_cfg_t gserx_cfg;\n+\n+\t\tswitch (pcie_port) {\n+\t\tcase 0:\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(0));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 0; /* PEM0 is on QLM0 and possibly QLM1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM0 is disabled */\n+\t\tcase 1:\t\t\t /* PEM1 */\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(0));\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(1));\n+\t\t\tif (!pem_cfg.cn78xx.lanes8 && gserx_cfg.s.pcie)\n+\t\t\t\treturn 1; /* PEM1 is on QLM 1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM1 is disabled */\n+\t\tcase 2:\t\t\t /* PEM2 */\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(2));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 2; /* PEM2 is on QLM2 and possibly QLM3 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM2 is disabled */\n+\t\tcase 3:\t\t\t /* PEM3 */\n+\t\t{\n+\t\t\tcvmx_gserx_cfg_t gser4_cfg;\n+\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(2));\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(3));\n+\t\t\tgser4_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(4));\n+\t\t\tif (pem_cfg.cn78xx.lanes8) {\n+\t\t\t\tif (gser4_cfg.s.pcie)\n+\t\t\t\t\treturn 4; /* PEM3 is on QLM4 */\n+\t\t\t\telse\n+\t\t\t\t\treturn -1; /* PEM3 is disabled */\n+\t\t\t} else {\n+\t\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\t\treturn 3; /* PEM3 is on QLM3 */\n+\t\t\t\telse if (gser4_cfg.s.pcie)\n+\t\t\t\t\treturn 4; /* PEM3 is on QLM4 */\n+\t\t\t\telse\n+\t\t\t\t\treturn -1; /* PEM3 is disabled */\n+\t\t\t}\n+\t\t}\n+\t\tdefault:\n+\t\t\tprintf(\"Invalid %d PCIe port\\n\", pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {\n+\t\tenum cvmx_qlm_mode mode1 = cvmx_qlm_get_mode(1);\n+\t\tenum cvmx_qlm_mode mode2 = cvmx_qlm_get_mode(2);\n+\n+\t\tswitch (pcie_port) {\n+\t\tcase 0: /* PCIe0 can be DLM1 with 1, 2 or 4 lanes */\n+\t\t\tif (mode1 == CVMX_QLM_MODE_PCIE || /* Using DLM 1-2 */\n+\t\t\t mode1 == CVMX_QLM_MODE_PCIE_1X2 || /* Using DLM 1 */\n+\t\t\t mode1 == CVMX_QLM_MODE_PCIE_2X1 || /* Using DLM 1, lane 0 */\n+\t\t\t mode1 == CVMX_QLM_MODE_PCIE_1X1) /* Using DLM 1, l0, l1 not used */\n+\t\t\t\treturn 1;\n+\t\t\telse\n+\t\t\t\treturn -1;\n+\t\tcase 1: /* PCIe1 can be DLM1 1 lane(1), DLM2 1 lane(0) or 2 lanes(0-1) */\n+\t\t\tif (mode1 == CVMX_QLM_MODE_PCIE_2X1)\n+\t\t\t\treturn 1;\n+\t\t\telse if (mode2 == CVMX_QLM_MODE_PCIE_1X2)\n+\t\t\t\treturn 2;\n+\t\t\telse if (mode2 == CVMX_QLM_MODE_PCIE_2X1)\n+\t\t\t\treturn 2;\n+\t\t\telse\n+\t\t\t\treturn -1;\n+\t\tcase 2: /* PCIe2 can be DLM2 1 lanes(1) */\n+\t\t\tif (mode2 == CVMX_QLM_MODE_PCIE_2X1)\n+\t\t\t\treturn 2;\n+\t\t\telse\n+\t\t\t\treturn -1;\n+\t\tdefault: /* Only three PEM blocks */\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {\n+\t\tcvmx_gserx_cfg_t gserx_cfg;\n+\n+\t\tswitch (pcie_port) {\n+\t\tcase 0: /* PEM0 */\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(0));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 0; /* PEM0 is on QLM0 and possibly QLM1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM0 is disabled */\n+\t\tcase 1:\t\t\t /* PEM1 */\n+\t\t\tgserx_cfg.u64 = CVMX_READ_CSR(CVMX_GSERX_CFG(1));\n+\t\t\tif (gserx_cfg.s.pcie)\n+\t\t\t\treturn 1; /* PEM1 is on DLM1 */\n+\t\t\telse\n+\t\t\t\treturn -1; /* PEM1 is disabled */\n+\t\tdefault:\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\treturn -1;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Initialize the RC config space CSRs\n+ *\n+ * @param node node\n+ * @param pcie_port PCIe port to initialize\n+ */\n+static void __cvmx_pcie_rc_initialize_config_space(int node, int pcie_port)\n+{\n+\t/* Max Payload Size (PCIE*_CFG030[MPS]) */\n+\t/* Max Read Request Size (PCIE*_CFG030[MRRS]) */\n+\t/* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */\n+\t/* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */\n+\t{\n+\t\tcvmx_pciercx_cfg030_t pciercx_cfg030;\n+\n+\t\tpciercx_cfg030.u32 = CVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t\t\t CVMX_PCIERCX_CFG030(pcie_port));\n+\t\tpciercx_cfg030.s.mps = MPS_CN6XXX;\n+\t\tpciercx_cfg030.s.mrrs = MRRS_CN6XXX;\n+\t\t/*\n+\t\t * Enable relaxed order processing. This will allow devices\n+\t\t * to affect read response ordering\n+\t\t */\n+\t\tpciercx_cfg030.s.ro_en = 1;\n+\t\t/* Enable no snoop processing. Not used by Octeon */\n+\t\tpciercx_cfg030.s.ns_en = 1;\n+\t\t/* Correctable error reporting enable. */\n+\t\tpciercx_cfg030.s.ce_en = 1;\n+\t\t/* Non-fatal error reporting enable. */\n+\t\tpciercx_cfg030.s.nfe_en = 1;\n+\t\t/* Fatal error reporting enable. */\n+\t\tpciercx_cfg030.s.fe_en = 1;\n+\t\t/* Unsupported request reporting enable. */\n+\t\tpciercx_cfg030.s.ur_en = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG030(pcie_port),\n+\t\t\t\t pciercx_cfg030.u32);\n+\t}\n+\n+\t/*\n+\t * Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match\n+\t * PCIE*_CFG030[MPS]\n+\t */\n+\t/*\n+\t * Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not exceed\n+\t * PCIE*_CFG030[MRRS]\n+\t */\n+\tcvmx_dpi_sli_prtx_cfg_t prt_cfg;\n+\tcvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;\n+\n+\tprt_cfg.u64 = CVMX_READ_CSR(CVMX_DPI_SLI_PRTX_CFG(pcie_port));\n+\tprt_cfg.s.mps = MPS_CN6XXX;\n+\tprt_cfg.s.mrrs = MRRS_CN6XXX;\n+\t/* Max outstanding load request. */\n+\tprt_cfg.s.molr = 32;\n+\tCVMX_WRITE_CSR(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);\n+\n+\tsli_s2m_portx_ctl.u64 = CVMX_READ_CSR(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));\n+\tif (!(OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX) ||\n+\t OCTEON_IS_MODEL(OCTEON_CNF75XX)))\n+\t\tsli_s2m_portx_ctl.cn61xx.mrrs = MRRS_CN6XXX;\n+\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);\n+\n+\t/* ECRC Generation (PCIE*_CFG070[GE,CE]) */\n+\t{\n+\t\tcvmx_pciercx_cfg070_t pciercx_cfg070;\n+\n+\t\tpciercx_cfg070.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG070(pcie_port));\n+\t\tpciercx_cfg070.s.ge = 1; /* ECRC generation enable. */\n+\t\tpciercx_cfg070.s.ce = 1; /* ECRC check enable. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG070(pcie_port), pciercx_cfg070.u32);\n+\t}\n+\n+\t/* Access Enables (PCIE*_CFG001[MSAE,ME]) */\n+\t/* ME and MSAE should always be set. */\n+\t/* Interrupt Disable (PCIE*_CFG001[I_DIS]) */\n+\t/* System Error Message Enable (PCIE*_CFG001[SEE]) */\n+\t{\n+\t\tcvmx_pciercx_cfg001_t pciercx_cfg001;\n+\n+\t\tpciercx_cfg001.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG001(pcie_port));\n+\t\tpciercx_cfg001.s.msae = 1; /* Memory space enable. */\n+\t\tpciercx_cfg001.s.me = 1; /* Bus master enable. */\n+\t\tpciercx_cfg001.s.i_dis = 1; /* INTx assertion disable. */\n+\t\tpciercx_cfg001.s.see = 1; /* SERR# enable */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG001(pcie_port), pciercx_cfg001.u32);\n+\t}\n+\n+\t/* Advanced Error Recovery Message Enables */\n+\t/* (PCIE*_CFG066,PCIE*_CFG067,PCIE*_CFG069) */\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG066(pcie_port), 0);\n+\t/* Use CVMX_PCIERCX_CFG067 hardware default */\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG069(pcie_port), 0);\n+\n+\t/* Active State Power Management (PCIE*_CFG032[ASLPC]) */\n+\t{\n+\t\tcvmx_pciercx_cfg032_t pciercx_cfg032;\n+\n+\t\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));\n+\t\tpciercx_cfg032.s.aslpc = 0; /* Active state Link PM control. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG032(pcie_port), pciercx_cfg032.u32);\n+\t}\n+\n+\t/* Link Width Mode (PCIERCn_CFG452[LME]) - Set during\n+\t * cvmx_pcie_rc_initialize_link()\n+\t */\n+\t/* Primary Bus Number (PCIERCn_CFG006[PBNUM]) */\n+\t{\n+\t\t/* We set the primary bus number to 1 so IDT bridges are happy.\n+\t\t * They don't like zero\n+\t\t */\n+\t\tcvmx_pciercx_cfg006_t pciercx_cfg006;\n+\n+\t\tpciercx_cfg006.u32 = 0;\n+\t\tpciercx_cfg006.s.pbnum = cvmx_primary_pcie_bus_number;\n+\t\tpciercx_cfg006.s.sbnum = cvmx_primary_pcie_bus_number;\n+\t\tpciercx_cfg006.s.subbnum = cvmx_primary_pcie_bus_number;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG006(pcie_port), pciercx_cfg006.u32);\n+\t}\n+\n+\t/* Memory-mapped I/O BAR (PCIERCn_CFG008) */\n+\t/* Most applications should disable the memory-mapped I/O BAR by */\n+\t/* setting PCIERCn_CFG008[ML_ADDR] < PCIERCn_CFG008[MB_ADDR] */\n+\t{\n+\t\tcvmx_pciercx_cfg008_t pciercx_cfg008;\n+\n+\t\tpciercx_cfg008.u32 = 0;\n+\t\tpciercx_cfg008.s.mb_addr = 0x100;\n+\t\tpciercx_cfg008.s.ml_addr = 0;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG008(pcie_port), pciercx_cfg008.u32);\n+\t}\n+\n+\t/* Prefetchable BAR (PCIERCn_CFG009,PCIERCn_CFG010,PCIERCn_CFG011) */\n+\t/* Most applications should disable the prefetchable BAR by setting */\n+\t/* PCIERCn_CFG011[UMEM_LIMIT],PCIERCn_CFG009[LMEM_LIMIT] < */\n+\t/* PCIERCn_CFG010[UMEM_BASE],PCIERCn_CFG009[LMEM_BASE] */\n+\t{\n+\t\tcvmx_pciercx_cfg009_t pciercx_cfg009;\n+\t\tcvmx_pciercx_cfg010_t pciercx_cfg010;\n+\t\tcvmx_pciercx_cfg011_t pciercx_cfg011;\n+\n+\t\tpciercx_cfg009.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG009(pcie_port));\n+\t\tpciercx_cfg010.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG010(pcie_port));\n+\t\tpciercx_cfg011.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG011(pcie_port));\n+\t\tpciercx_cfg009.s.lmem_base = 0x100;\n+\t\tpciercx_cfg009.s.lmem_limit = 0;\n+\t\tpciercx_cfg010.s.umem_base = 0x100;\n+\t\tpciercx_cfg011.s.umem_limit = 0;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG009(pcie_port), pciercx_cfg009.u32);\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG010(pcie_port), pciercx_cfg010.u32);\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG011(pcie_port), pciercx_cfg011.u32);\n+\t}\n+\n+\t/* System Error Interrupt Enables (PCIERCn_CFG035[SECEE,SEFEE,SENFEE]) */\n+\t/* PME Interrupt Enables (PCIERCn_CFG035[PMEIE]) */\n+\t{\n+\t\tcvmx_pciercx_cfg035_t pciercx_cfg035;\n+\n+\t\tpciercx_cfg035.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG035(pcie_port));\n+\t\tpciercx_cfg035.s.secee = 1; /* System error on correctable error enable. */\n+\t\tpciercx_cfg035.s.sefee = 1; /* System error on fatal error enable. */\n+\t\tpciercx_cfg035.s.senfee = 1; /* System error on non-fatal error enable. */\n+\t\tpciercx_cfg035.s.pmeie = 1; /* PME interrupt enable. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG035(pcie_port), pciercx_cfg035.u32);\n+\t}\n+\n+\t/* Advanced Error Recovery Interrupt Enables */\n+\t/* (PCIERCn_CFG075[CERE,NFERE,FERE]) */\n+\t{\n+\t\tcvmx_pciercx_cfg075_t pciercx_cfg075;\n+\n+\t\tpciercx_cfg075.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG075(pcie_port));\n+\t\tpciercx_cfg075.s.cere = 1; /* Correctable error reporting enable. */\n+\t\tpciercx_cfg075.s.nfere = 1; /* Non-fatal error reporting enable. */\n+\t\tpciercx_cfg075.s.fere = 1; /* Fatal error reporting enable. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG075(pcie_port), pciercx_cfg075.u32);\n+\t}\n+\n+\t/* HP Interrupt Enables (PCIERCn_CFG034[HPINT_EN], */\n+\t/* PCIERCn_CFG034[DLLS_EN,CCINT_EN]) */\n+\t{\n+\t\tcvmx_pciercx_cfg034_t pciercx_cfg034;\n+\n+\t\tpciercx_cfg034.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG034(pcie_port));\n+\t\tpciercx_cfg034.s.hpint_en = 1; /* Hot-plug interrupt enable. */\n+\t\tpciercx_cfg034.s.dlls_en = 1; /* Data Link Layer state changed enable */\n+\t\tpciercx_cfg034.s.ccint_en = 1; /* Command completed interrupt enable. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG034(pcie_port), pciercx_cfg034.u32);\n+\t}\n+\n+\tif (OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX) ||\n+\t OCTEON_IS_MODEL(OCTEON_CNF75XX)) {\n+\t\tint qlm = __cvmx_pcie_get_qlm(node, pcie_port);\n+\t\tint speed = cvmx_qlm_get_gbaud_mhz(qlm);\n+\t\tcvmx_pemx_cfg_t pem_cfg;\n+\t\tcvmx_pciercx_cfg031_t cfg031;\n+\t\tcvmx_pciercx_cfg040_t cfg040;\n+\t\tcvmx_pciercx_cfg452_t cfg452;\n+\t\tcvmx_pciercx_cfg089_t cfg089;\n+\t\tcvmx_pciercx_cfg090_t cfg090;\n+\t\tcvmx_pciercx_cfg091_t cfg091;\n+\t\tcvmx_pciercx_cfg092_t cfg092;\n+\t\tcvmx_pciercx_cfg554_t cfg554;\n+\n+\t\t/*\n+\t\t * Make sure the PEM agrees with GSERX about the speed\n+\t\t * its going to try\n+\t\t */\n+\t\tswitch (speed) {\n+\t\tcase 2500: /* Gen1 */\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\t\t\tpem_cfg.s.md = 0;\n+\t\t\tCVMX_WRITE_CSR(CVMX_PEMX_CFG(pcie_port), pem_cfg.u64);\n+\n+\t\t\t/* Set the target link speed */\n+\t\t\tcfg040.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG040(pcie_port));\n+\t\t\tcfg040.s.tls = 1;\n+\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG040(pcie_port), cfg040.u32);\n+\t\t\tbreak;\n+\t\tcase 5000: /* Gen2 */\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\t\t\tpem_cfg.s.md = 1;\n+\t\t\tCVMX_WRITE_CSR(CVMX_PEMX_CFG(pcie_port), pem_cfg.u64);\n+\n+\t\t\t/* Set the target link speed */\n+\t\t\tcfg040.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG040(pcie_port));\n+\t\t\tcfg040.s.tls = 2;\n+\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG040(pcie_port), cfg040.u32);\n+\t\t\tbreak;\n+\t\tcase 8000: /* Gen3 */\n+\t\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\t\t\tpem_cfg.s.md = 2;\n+\t\t\tCVMX_WRITE_CSR(CVMX_PEMX_CFG(pcie_port), pem_cfg.u64);\n+\n+\t\t\t/* Set the target link speed */\n+\t\t\tcfg040.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG040(pcie_port));\n+\t\t\tcfg040.s.tls = 3;\n+\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG040(pcie_port), cfg040.u32);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Link Width Mode (PCIERCn_CFG452[LME]) */\n+\t\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\t\tcfg452.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG452(pcie_port));\n+\t\tif (qlm >= 5)\n+\t\t\tcfg452.s.lme = 0x3;\n+\t\telse\n+\t\t\tcfg452.s.lme = (pem_cfg.cn78xx.lanes8) ? 0xf : 0x7;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG452(pcie_port), cfg452.u32);\n+\n+\t\t/* Errata PEM-25990 - Disable ASLPMS */\n+\t\tcfg031.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));\n+\t\tcfg031.s.aslpms = 0;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), cfg031.u32);\n+\n+\t\t/* CFG554.PRV default changed from 16'h7ff to 16'h593. */\n+\t\tcfg554.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG554(pcie_port));\n+\t\tcfg554.s.prv = pcie_preset_vec[pcie_port];\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG554(pcie_port), cfg554.u32);\n+\t\t/* Errata PEM-26189 - Disable the 2ms timer on all chips */\n+\t\tcfg554.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG554(pcie_port));\n+\t\tcfg554.s.p23td = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG554(pcie_port), cfg554.u32);\n+\n+\t\t/* Errata PEM-21178 - Change the CFG[089-092] LxUTP & LxDTP defaults. */\n+\t\tcfg089.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG089(pcie_port));\n+\t\tcfg089.s.l1ddtp = 7;\n+\t\tcfg089.s.l1utp = 7;\n+\t\tcfg089.s.l0dtp = 7;\n+\t\tcfg089.s.l0utp = 7;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG089(pcie_port), cfg089.u32);\n+\t\tcfg090.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG090(pcie_port));\n+\t\tcfg090.s.l3dtp = 7;\n+\t\tcfg090.s.l3utp = 7;\n+\t\tcfg090.s.l2dtp = 7;\n+\t\tcfg090.s.l2utp = 7;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG090(pcie_port), cfg090.u32);\n+\t\tcfg091.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG091(pcie_port));\n+\t\tcfg091.s.l5dtp = 7;\n+\t\tcfg091.s.l5utp = 7;\n+\t\tcfg091.s.l4dtp = 7;\n+\t\tcfg091.s.l4utp = 7;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG091(pcie_port), cfg091.u32);\n+\t\tcfg092.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG092(pcie_port));\n+\t\tcfg092.s.l7dtp = 7;\n+\t\tcfg092.s.l7utp = 7;\n+\t\tcfg092.s.l6dtp = 7;\n+\t\tcfg092.s.l6utp = 7;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG092(pcie_port), cfg092.u32);\n+\t}\n+}\n+\n+static void __cvmx_increment_ba(cvmx_sli_mem_access_subidx_t *pmas)\n+{\n+\tif (OCTEON_IS_MODEL(OCTEON_CN68XX))\n+\t\tpmas->cn68xx.ba++;\n+\telse\n+\t\tpmas->cn63xx.ba++;\n+}\n+\n+/*\n+ * milliseconds to retry PCIe cfg-space access:\n+ * Value 32(unscaled) was recommended in HRM, but may be too small for\n+ * some PCIe devices. This 200mS default should cover most devices,\n+ * but can be extended by bootparam cvmx-pcie.cfg_timeout, or reduced\n+ * to speed boot if it is known that no devices need so much time.\n+ */\n+static int cfg_timeout = 200;\n+\n+static int cfg_retries(void)\n+{\n+\tstatic int cfg_ticks = -1;\n+\n+\tif (cfg_ticks < 0) {\n+\t\tu64 nS = cfg_timeout * 1000000;\n+\t\tconst int ceiling = 0xffff;\n+\n+\t\tcfg_ticks = nS / (gd->bus_clk >> 16);\n+\t\tif (cfg_ticks > ceiling)\n+\t\t\tcfg_ticks = ceiling;\n+\t}\n+\n+\treturn cfg_ticks;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Enable/Disable PEMX_PEMON.pemon based on the direction.\n+ *\n+ * @param node node\n+ * @param pcie_port PCIe port\n+ * @param direction 0 to disable, 1 to enable\n+ */\n+static void __cvmx_pcie_config_pemon(int node, int pcie_port, bool direction)\n+{\n+\tcvmx_pemx_on_t pemon;\n+\n+\tpemon.u64 = CVMX_READ_CSR(CVMX_PEMX_ON(pcie_port));\n+\tpemon.s.pemon = direction;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_ON(pcie_port), pemon.u64);\n+\tpemon.u64 = CVMX_READ_CSR(CVMX_PEMX_ON(pcie_port));\n+}\n+\n+/**\n+ * @INTERNAL\n+ * De-assert GSER_PHY.phy_reset for a given qlm\n+ *\n+ * @param node node\n+ * @param qlm qlm for a given PCIe port\n+ */\n+static void __cvmx_pcie_gser_phy_config(int node, int pcie_port, int qlm)\n+{\n+\tcvmx_pemx_cfg_t pem_cfg;\n+\tcvmx_gserx_phy_ctl_t ctrl;\n+\tint has_8lanes = 0;\n+\tint is_gen3 = 0;\n+\n+\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm));\n+\n+\t/* Assert the reset */\n+\tctrl.s.phy_reset = 1;\n+\tCVMX_WRITE_CSR(CVMX_GSERX_PHY_CTL(qlm), ctrl.u64);\n+\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\tudelay(10);\n+\n+\thas_8lanes = pem_cfg.cn78xx.lanes8;\n+\tis_gen3 = pem_cfg.cn78xx.md >= 2;\n+\n+\tif (has_8lanes) {\n+\t\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm + 1));\n+\t\tctrl.s.phy_reset = 1;\n+\t\tCVMX_WRITE_CSR(CVMX_GSERX_PHY_CTL(qlm + 1), ctrl.u64);\n+\t\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm + 1));\n+\t}\n+\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm));\n+\tudelay(10);\n+\n+\t/* Deassert the reset */\n+\tctrl.s.phy_reset = 0;\n+\tCVMX_WRITE_CSR(CVMX_GSERX_PHY_CTL(qlm), ctrl.u64);\n+\tpem_cfg.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG(pcie_port));\n+\tudelay(500);\n+\n+\tif (has_8lanes) {\n+\t\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm + 1));\n+\t\tctrl.s.phy_reset = 0;\n+\t\tCVMX_WRITE_CSR(CVMX_GSERX_PHY_CTL(qlm + 1), ctrl.u64);\n+\t}\n+\tctrl.u64 = CVMX_READ_CSR(CVMX_GSERX_PHY_CTL(qlm));\n+\tudelay(500);\n+\n+\t/* Apply some erratas after PHY reset, only applies to PCIe GEN3 */\n+\tif (is_gen3) {\n+\t\tint i;\n+\t\tint high_qlm = has_8lanes ? qlm + 1 : qlm;\n+\n+\t\t/* Apply workaround for Errata GSER-26150 */\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN73XX_PASS1_0)) {\n+\t\t\tfor (i = qlm; i < high_qlm; i++) {\n+\t\t\t\tcvmx_gserx_glbl_pll_cfg_3_t pll_cfg_3;\n+\t\t\t\tcvmx_gserx_glbl_misc_config_1_t misc_config_1;\n+\t\t\t\t/* Update PLL parameters */\n+\t\t\t\t/*\n+\t\t\t\t * Step 1: Set\n+\t\t\t\t * GSER()_GLBL_PLL_CFG_3[PLL_VCTRL_SEL_LCVCO_VAL] = 0x2,\n+\t\t\t\t * and\n+\t\t\t\t * GSER()_GLBL_PLL_CFG_3[PCS_SDS_PLL_VCO_AMP] = 0\n+\t\t\t\t */\n+\t\t\t\tpll_cfg_3.u64 = CVMX_READ_CSR(CVMX_GSERX_GLBL_PLL_CFG_3(i));\n+\t\t\t\tpll_cfg_3.s.pcs_sds_pll_vco_amp = 0;\n+\t\t\t\tpll_cfg_3.s.pll_vctrl_sel_lcvco_val = 2;\n+\t\t\t\tCVMX_WRITE_CSR(CVMX_GSERX_GLBL_PLL_CFG_3(i), pll_cfg_3.u64);\n+\n+\t\t\t\t/*\n+\t\t\t\t * Step 2: Set\n+\t\t\t\t * GSER()_GLBL_MISC_CONFIG_1[PCS_SDS_TRIM_CHP_REG] = 0x2.\n+\t\t\t\t */\n+\t\t\t\tmisc_config_1.u64 = CVMX_READ_CSR(CVMX_GSERX_GLBL_MISC_CONFIG_1(i));\n+\t\t\t\tmisc_config_1.s.pcs_sds_trim_chp_reg = 2;\n+\t\t\t\tCVMX_WRITE_CSR(CVMX_GSERX_GLBL_MISC_CONFIG_1(i), misc_config_1.u64);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Apply workaround for Errata GSER-25992 */\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN73XX_PASS1_X) ||\n+\t\t OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {\n+\t\t\tfor (i = qlm; i < high_qlm; i++)\n+\t\t\t\tcvmx_qlm_gser_errata_25992(node, i);\n+\t\t}\n+\t}\n+}\n+\n+/* Get the PCIe LTSSM state for the given port\n+ *\n+ * @param node Node to query\n+ * @param pcie_port PEM to query\n+ *\n+ * @return LTSSM state\n+ */\n+static int __cvmx_pcie_rc_get_ltssm_state(int node, int pcie_port)\n+{\n+\tu64 debug;\n+\n+\tif (OCTEON_IS_MODEL(OCTEON_CN73XX) && pcie_port == 0) {\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_SPEM_SELX(0), 0);\n+\t\tCVMX_READ_CSR(CVMX_DTX_SPEM_SELX(0));\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_SPEM_ENAX(0), 0xfffffffffull);\n+\t\tCVMX_READ_CSR(CVMX_DTX_SPEM_ENAX(0));\n+\n+\t\t/* Read the value */\n+\t\tdebug = CVMX_READ_CSR(CVMX_DTX_SPEM_DATX(0));\n+\n+\t\t/* Disable the PEM from driving OCLA signals */\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_SPEM_ENAX(0), 0);\n+\t\tCVMX_READ_CSR(CVMX_DTX_SPEM_ENAX(0));\n+\t} else {\n+\t\t/* LTSSM state is in debug select 0 */\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_PEMX_SELX(0, pcie_port), 0);\n+\t\tCVMX_READ_CSR(CVMX_DTX_PEMX_SELX(0, pcie_port));\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_PEMX_ENAX(0, pcie_port), 0xfffffffffull);\n+\t\tCVMX_READ_CSR(CVMX_DTX_PEMX_ENAX(0, pcie_port));\n+\n+\t\t/* Read the value */\n+\t\tdebug = CVMX_READ_CSR(CVMX_DTX_PEMX_DATX(0, pcie_port));\n+\n+\t\t/* Disable the PEM from driving OCLA signals */\n+\t\tCVMX_WRITE_CSR(CVMX_DTX_PEMX_ENAX(0, pcie_port), 0);\n+\t\tCVMX_READ_CSR(CVMX_DTX_PEMX_ENAX(0, pcie_port));\n+\t}\n+\n+\t/* DBGSEL = 0x0, bits[8:3] */\n+\treturn cvmx_bit_extract(debug, 3, 6);\n+}\n+\n+/**\n+ * Get the PCIe LTSSM state for the given port\n+ *\n+ * @param node Node to query\n+ * @param pcie_port PEM to query\n+ *\n+ * @return LTSSM state\n+ */\n+static const char *cvmx_pcie_get_ltssm_string(int ltssm)\n+{\n+\tswitch (ltssm) {\n+\tcase 0x00:\n+\t\treturn \"DETECT_QUIET\";\n+\tcase 0x01:\n+\t\treturn \"DETECT_ACT\";\n+\tcase 0x02:\n+\t\treturn \"POLL_ACTIVE\";\n+\tcase 0x03:\n+\t\treturn \"POLL_COMPLIANCE\";\n+\tcase 0x04:\n+\t\treturn \"POLL_CONFIG\";\n+\tcase 0x05:\n+\t\treturn \"PRE_DETECT_QUIET\";\n+\tcase 0x06:\n+\t\treturn \"DETECT_WAIT\";\n+\tcase 0x07:\n+\t\treturn \"CFG_LINKWD_START\";\n+\tcase 0x08:\n+\t\treturn \"CFG_LINKWD_ACEPT\";\n+\tcase 0x09:\n+\t\treturn \"CFG_LANENUM_WAIT\";\n+\tcase 0x0A:\n+\t\treturn \"CFG_LANENUM_ACEPT\";\n+\tcase 0x0B:\n+\t\treturn \"CFG_COMPLETE\";\n+\tcase 0x0C:\n+\t\treturn \"CFG_IDLE\";\n+\tcase 0x0D:\n+\t\treturn \"RCVRY_LOCK\";\n+\tcase 0x0E:\n+\t\treturn \"RCVRY_SPEED\";\n+\tcase 0x0F:\n+\t\treturn \"RCVRY_RCVRCFG\";\n+\tcase 0x10:\n+\t\treturn \"RCVRY_IDLE\";\n+\tcase 0x11:\n+\t\treturn \"L0\";\n+\tcase 0x12:\n+\t\treturn \"L0S\";\n+\tcase 0x13:\n+\t\treturn \"L123_SEND_EIDLE\";\n+\tcase 0x14:\n+\t\treturn \"L1_IDLE\";\n+\tcase 0x15:\n+\t\treturn \"L2_IDLE\";\n+\tcase 0x16:\n+\t\treturn \"L2_WAKE\";\n+\tcase 0x17:\n+\t\treturn \"DISABLED_ENTRY\";\n+\tcase 0x18:\n+\t\treturn \"DISABLED_IDLE\";\n+\tcase 0x19:\n+\t\treturn \"DISABLED\";\n+\tcase 0x1A:\n+\t\treturn \"LPBK_ENTRY\";\n+\tcase 0x1B:\n+\t\treturn \"LPBK_ACTIVE\";\n+\tcase 0x1C:\n+\t\treturn \"LPBK_EXIT\";\n+\tcase 0x1D:\n+\t\treturn \"LPBK_EXIT_TIMEOUT\";\n+\tcase 0x1E:\n+\t\treturn \"HOT_RESET_ENTRY\";\n+\tcase 0x1F:\n+\t\treturn \"HOT_RESET\";\n+\tcase 0x20:\n+\t\treturn \"RCVRY_EQ0\";\n+\tcase 0x21:\n+\t\treturn \"RCVRY_EQ1\";\n+\tcase 0x22:\n+\t\treturn \"RCVRY_EQ2\";\n+\tcase 0x23:\n+\t\treturn \"RCVRY_EQ3\";\n+\tdefault:\n+\t\treturn \"Unknown\";\n+\t}\n+}\n+\n+/**\n+ * During PCIe link initialization we need to make config request to the attached\n+ * device to verify its speed and width. These config access happen very early\n+ * after the device is taken out of reset, so may fail for some amount of time.\n+ * This function automatically retries these config accesses. The normal builtin\n+ * hardware retry isn't enough for this very early access.\n+ *\n+ * @param node Note to read from\n+ * @param pcie_port PCIe port to read from\n+ * @param bus PCIe bus number\n+ * @param dev PCIe device\n+ * @param func PCIe function on the device\n+ * @param reg Register to read\n+ *\n+ * @return Config register value, or all ones on failure\n+ */\n+static uint32_t cvmx_pcie_config_read32_retry(int node, int pcie_port, int bus, int dev, int func,\n+\t\t\t\t\t int reg)\n+{\n+\t/*\n+\t * Read the PCI config register until we get a valid value. Some cards\n+\t * require time after link up to return data. Wait at most 3 seconds\n+\t */\n+\tu64 timeout = 300;\n+\tu32 val;\n+\n+\tdo {\n+\t\t/* Read PCI capability pointer */\n+\t\tval = __cvmx_pcie_config_read32(node, pcie_port, bus, dev, func, reg, 0);\n+\n+\t\t/* Check the read succeeded */\n+\t\tif (val != 0xffffffff)\n+\t\t\treturn val;\n+\t\t/* Failed, wait a little and try again */\n+\t\tmdelay(10);\n+\t} while (--timeout);\n+\n+\tdebug(\"N%d.PCIe%d: Config read failed, can't communicate with device\\n\",\n+\t node, pcie_port);\n+\n+\treturn -1;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Initialize a host mode PCIe gen 2 link. This function takes a PCIe\n+ * port from reset to a link up state. Software can then begin\n+ * configuring the rest of the link.\n+ *\n+ * @param node\t node\n+ * @param pcie_port PCIe port to initialize\n+ *\n+ * @return Zero on success\n+ */\n+static int __cvmx_pcie_rc_initialize_link_gen2(int node, int pcie_port)\n+{\n+\tu64 start_cycle;\n+\n+\tcvmx_pemx_ctl_status_t pem_ctl_status;\n+\tcvmx_pciercx_cfg032_t pciercx_cfg032;\n+\tcvmx_pciercx_cfg448_t pciercx_cfg448;\n+\n+\tif (OCTEON_IS_OCTEON3()) {\n+\t\tif (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_PEMX_ON(pcie_port), cvmx_pemx_on_t,\n+\t\t\t\t\t pemoor, ==, 1, 100000)) {\n+\t\t\tprintf(\"%d:PCIe: Port %d PEM not on, skipping\\n\", node, pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t/* Bring up the link */\n+\tpem_ctl_status.u64 = CVMX_READ_CSR(CVMX_PEMX_CTL_STATUS(pcie_port));\n+\tpem_ctl_status.s.lnk_enb = 1;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);\n+\n+\t/* Wait for the link to come up */\n+\tstart_cycle = get_timer(0);\n+\tdo {\n+\t\tif (get_timer(start_cycle) > 1000)\n+\t\t\treturn -1;\n+\n+\t\tudelay(1000);\n+\t\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t\t\t CVMX_PCIERCX_CFG032(pcie_port));\n+\t} while ((pciercx_cfg032.s.dlla == 0) || (pciercx_cfg032.s.lt == 1));\n+\n+\t/* Update the Replay Time Limit. Empirically, some PCIe devices take a\n+\t * little longer to respond than expected under load. As a workaround\n+\t * for this we configure the Replay Time Limit to the value expected\n+\t * for a 512 byte MPS instead of our actual 256 byte MPS. The numbers\n+\t * below are directly from the PCIe spec table 3-4\n+\t */\n+\tpciercx_cfg448.u32 = CVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG448(pcie_port));\n+\tswitch (pciercx_cfg032.s.nlw) {\n+\tcase 1: /* 1 lane */\n+\t\tpciercx_cfg448.s.rtl = 1677;\n+\t\tbreak;\n+\tcase 2: /* 2 lanes */\n+\t\tpciercx_cfg448.s.rtl = 867;\n+\t\tbreak;\n+\tcase 4: /* 4 lanes */\n+\t\tpciercx_cfg448.s.rtl = 462;\n+\t\tbreak;\n+\tcase 8: /* 8 lanes */\n+\t\tpciercx_cfg448.s.rtl = 258;\n+\t\tbreak;\n+\t}\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG448(pcie_port),\n+\t\t\t pciercx_cfg448.u32);\n+\n+\treturn 0;\n+}\n+\n+extern int octeon_pcie_get_qlm_from_fdt(int numa_node, int pcie_port);\n+\n+static int __cvmx_pcie_check_pcie_port(int node, int pcie_port, enum cvmx_qlm_mode mode)\n+{\n+\tif (mode == CVMX_QLM_MODE_SRIO_1X4 || mode == CVMX_QLM_MODE_SRIO_2X2 ||\n+\t mode == CVMX_QLM_MODE_SRIO_4X1) {\n+\t\tprintf(\"%d:PCIe: Port %d is SRIO, skipping.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t} else if (mode == CVMX_QLM_MODE_SGMII) {\n+\t\tprintf(\"%d:PCIe: Port %d is SGMII, skipping.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t} else if (mode == CVMX_QLM_MODE_XAUI || mode == CVMX_QLM_MODE_RXAUI) {\n+\t\tprintf(\"%d:PCIe: Port %d is XAUI, skipping.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t} else if (mode == CVMX_QLM_MODE_ILK) {\n+\t\tprintf(\"%d:PCIe: Port %d is ILK, skipping.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t} else if (mode != CVMX_QLM_MODE_PCIE &&\n+\t\t mode != CVMX_QLM_MODE_PCIE_1X8 &&\n+\t\t mode != CVMX_QLM_MODE_PCIE_1X2 &&\n+\t\t mode != CVMX_QLM_MODE_PCIE_2X1 &&\n+\t\t mode != CVMX_QLM_MODE_PCIE_1X1) {\n+\t\tprintf(\"%d:PCIe: Port %d is unknown, skipping.\\n\",\n+\t\t node, pcie_port);\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int __cvmx_pcie_check_qlm_mode(int node, int pcie_port, int qlm)\n+{\n+\tenum cvmx_qlm_mode mode = CVMX_QLM_MODE_DISABLED;\n+\n+\tif (qlm < 0)\n+\t\treturn -1;\n+\n+\t/* Make sure this interface is PCIe */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN70XX)) {\n+\t\tif (cvmx_qlm_get_dlm_mode(1, pcie_port) ==\n+\t\t CVMX_QLM_MODE_DISABLED) {\n+\t\t\tprintf(\"PCIe: Port %d not in PCIe mode, skipping\\n\",\n+\t\t\t pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {\n+\t\t/*\n+\t\t * Requires reading the MIO_QLMX_CFG register to figure\n+\t\t * out the port type.\n+\t\t */\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN68XX)) {\n+\t\t\tqlm = 3 - (pcie_port * 2);\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN61XX)) {\n+\t\t\tcvmx_mio_qlmx_cfg_t qlm_cfg;\n+\n+\t\t\tqlm_cfg.u64 = csr_rd(CVMX_MIO_QLMX_CFG(1));\n+\t\t\tif (qlm_cfg.s.qlm_cfg == 1)\n+\t\t\t\tqlm = 1;\n+\t\t\telse\n+\t\t\t\tqlm = pcie_port;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN66XX) ||\n+\t\t\t OCTEON_IS_MODEL(OCTEON_CN63XX)) {\n+\t\t\tqlm = pcie_port;\n+\t\t}\n+\n+\t\t/*\n+\t\t * PCIe is allowed only in QLM1, 1 PCIe port in x2 or\n+\t\t * 2 PCIe ports in x1\n+\t\t */\n+\t\telse if (OCTEON_IS_MODEL(OCTEON_CNF71XX))\n+\t\t\tqlm = 1;\n+\n+\t\tmode = cvmx_qlm_get_mode(qlm);\n+\n+\t\t__cvmx_pcie_check_pcie_port(node, pcie_port, mode);\n+\t}\n+\treturn 0;\n+}\n+\n+static void __cvmx_pcie_sli_config(int node, int pcie_port)\n+{\n+\tcvmx_pemx_bar_ctl_t pemx_bar_ctl;\n+\tcvmx_pemx_ctl_status_t pemx_ctl_status;\n+\tcvmx_sli_ctl_portx_t sli_ctl_portx;\n+\tcvmx_sli_mem_access_ctl_t sli_mem_access_ctl;\n+\tcvmx_sli_mem_access_subidx_t mem_access_subid;\n+\tcvmx_pemx_bar1_indexx_t bar1_index;\n+\tint i;\n+\n+\t/* Store merge control (SLI_MEM_ACCESS_CTL[TIMER,MAX_WORD]) */\n+\tsli_mem_access_ctl.u64 = CVMX_READ_CSR(CVMX_PEXP_SLI_MEM_ACCESS_CTL);\n+\tsli_mem_access_ctl.s.max_word = 0; /* Allow 16 words to combine */\n+\tsli_mem_access_ctl.s.timer = 127; /* Wait up to 127 cycles for more data */\n+\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_MEM_ACCESS_CTL, sli_mem_access_ctl.u64);\n+\n+\t/* Setup Mem access SubDIDs */\n+\tmem_access_subid.u64 = 0;\n+\tmem_access_subid.s.port = pcie_port;\t/* Port the request is sent to. */\n+\tmem_access_subid.s.nmerge = 0;\t\t/* Allow merging as it works on CN6XXX. */\n+\tmem_access_subid.s.esr = _CVMX_PCIE_ES; /* Endian-swap for Reads. */\n+\tmem_access_subid.s.esw = _CVMX_PCIE_ES; /* Endian-swap for Writes. */\n+\tmem_access_subid.s.wtype = 0;\t\t/* \"No snoop\" and \"Relaxed ordering\" are not set */\n+\tmem_access_subid.s.rtype = 0;\t\t/* \"No snoop\" and \"Relaxed ordering\" are not set */\n+\t/* PCIe Address Bits <63:34>. */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN68XX))\n+\t\tmem_access_subid.cn68xx.ba = 0;\n+\telse\n+\t\tmem_access_subid.cn63xx.ba = 0;\n+\n+\t/* Setup mem access 12-15 for port 0, 16-19 for port 1, supplying 36\n+\t * bits of address space\n+\t */\n+\tfor (i = 12 + pcie_port * 4; i < 16 + pcie_port * 4; i++) {\n+\t\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(i), mem_access_subid.u64);\n+\t\t/* Set each SUBID to extend the addressable range */\n+\t\t__cvmx_increment_ba(&mem_access_subid);\n+\t}\n+\n+\tif (OCTEON_IS_MODEL(OCTEON_CN63XX) || OCTEON_IS_MODEL(OCTEON_CN66XX) ||\n+\t OCTEON_IS_MODEL(OCTEON_CN68XX) ||\n+\t (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX))) {\n+\t\t/* Disable the peer to peer forwarding register. This must be\n+\t\t * setup by the OS after it enumerates the bus and assigns\n+\t\t * addresses to the PCIe busses\n+\t\t */\n+\t\tfor (i = 0; i < 4; i++) {\n+\t\t\tCVMX_WRITE_CSR(CVMX_PEMX_P2P_BARX_START(i, pcie_port), -1);\n+\t\t\tCVMX_WRITE_CSR(CVMX_PEMX_P2P_BARX_END(i, pcie_port), -1);\n+\t\t}\n+\t}\n+\n+\t/* Set Octeon's BAR0 to decode 0-16KB. It overlaps with Bar2 */\n+\tCVMX_WRITE_CSR(CVMX_PEMX_P2N_BAR0_START(pcie_port), 0);\n+\n+\t/* Set Octeon's BAR2 to decode 0-2^41. Bar0 and Bar1 take precedence\n+\t * where they overlap. It also overlaps with the device addresses, so\n+\t * make sure the peer to peer forwarding is set right\n+\t */\n+\tCVMX_WRITE_CSR(CVMX_PEMX_P2N_BAR2_START(pcie_port), 0);\n+\n+\t/* Setup BAR2 attributes */\n+\t/* Relaxed Ordering (NPEI_CTL_PORTn[PTLP_RO,CTLP_RO, WAIT_COM]) */\n+\t/* - PTLP_RO,CTLP_RO should normally be set (except for debug). */\n+\t/* - WAIT_COM=0 will likely work for all applications. */\n+\t/* Load completion relaxed ordering (NPEI_CTL_PORTn[WAITL_COM]) */\n+\tpemx_bar_ctl.u64 = CVMX_READ_CSR(CVMX_PEMX_BAR_CTL(pcie_port));\n+\tpemx_bar_ctl.s.bar1_siz = 3; /* 256MB BAR1 */\n+\tpemx_bar_ctl.s.bar2_enb = 1;\n+\tpemx_bar_ctl.s.bar2_esx = _CVMX_PCIE_ES;\n+\tpemx_bar_ctl.s.bar2_cax = 0;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_BAR_CTL(pcie_port), pemx_bar_ctl.u64);\n+\tsli_ctl_portx.u64 = CVMX_READ_CSR(CVMX_PEXP_SLI_CTL_PORTX(pcie_port));\n+\tsli_ctl_portx.s.ptlp_ro = 1;\n+\tsli_ctl_portx.s.ctlp_ro = 1;\n+\tsli_ctl_portx.s.wait_com = 0;\n+\tsli_ctl_portx.s.waitl_com = 0;\n+\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_CTL_PORTX(pcie_port), sli_ctl_portx.u64);\n+\n+\t/* BAR1 follows BAR2 */\n+\tCVMX_WRITE_CSR(CVMX_PEMX_P2N_BAR1_START(pcie_port),\n+\t\t CVMX_PCIE_BAR1_RC_BASE);\n+\n+\tbar1_index.u64 = 0;\n+\tbar1_index.s.addr_idx = (CVMX_PCIE_BAR1_PHYS_BASE >> 22);\n+\tbar1_index.s.ca = 1;\t\t /* Not Cached */\n+\tbar1_index.s.end_swp = _CVMX_PCIE_ES; /* Endian Swap mode */\n+\tbar1_index.s.addr_v = 1;\t /* Valid entry */\n+\n+\tfor (i = 0; i < 16; i++) {\n+\t\tCVMX_WRITE_CSR(CVMX_PEMX_BAR1_INDEXX(i, pcie_port),\n+\t\t\t bar1_index.u64);\n+\t\t/* 256MB / 16 >> 22 == 4 */\n+\t\tbar1_index.s.addr_idx += (((1ull << 28) / 16ull) >> 22);\n+\t}\n+\n+\t/* Wait for 200ms */\n+\tpemx_ctl_status.u64 = CVMX_READ_CSR(CVMX_PEMX_CTL_STATUS(pcie_port));\n+\tpemx_ctl_status.cn63xx.cfg_rtry = cfg_retries();\n+\tCVMX_WRITE_CSR(CVMX_PEMX_CTL_STATUS(pcie_port), pemx_ctl_status.u64);\n+\n+\t/*\n+\t * Here is the second part of the config retry changes. Wait for 700ms\n+\t * after setting up the link before continuing. PCIe says the devices\n+\t * may need up to 900ms to come up. 700ms plus 200ms from above gives\n+\t * us a total of 900ms\n+\t */\n+\tif (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX))\n+\t\tudelay(PCIE_DEVICE_READY_WAIT_DELAY_MICROSECONDS);\n+}\n+\n+/**\n+ * Initialize a PCIe gen 2 port for use in host(RC) mode. It doesn't enumerate\n+ * the bus.\n+ *\n+ * @param pcie_port PCIe port to initialize\n+ *\n+ * @return Zero on success\n+ */\n+static int __cvmx_pcie_rc_initialize_gen2(int pcie_port)\n+{\n+\tcvmx_ciu_soft_prst_t ciu_soft_prst;\n+\tcvmx_mio_rst_ctlx_t mio_rst_ctl;\n+\tcvmx_pemx_bist_status_t pemx_bist_status;\n+\tcvmx_pemx_bist_status2_t pemx_bist_status2;\n+\tcvmx_pciercx_cfg032_t pciercx_cfg032;\n+\tcvmx_pciercx_cfg515_t pciercx_cfg515;\n+\tu64 ciu_soft_prst_reg, rst_ctl_reg;\n+\tint ep_mode;\n+\tint qlm = 0;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\n+\tif (pcie_port >= CVMX_PCIE_PORTS) {\n+\t\t//debug(\"Invalid PCIe%d port\\n\", pcie_port);\n+\t\treturn -1;\n+\t}\n+\n+\tif (__cvmx_pcie_check_qlm_mode(node, pcie_port, qlm))\n+\t\treturn -1;\n+\n+\t/* Make sure we aren't trying to setup a target mode interface in host\n+\t * mode\n+\t */\n+\tif (OCTEON_IS_OCTEON3()) {\n+\t\tciu_soft_prst_reg = CVMX_RST_SOFT_PRSTX(pcie_port);\n+\t\trst_ctl_reg = CVMX_RST_CTLX(pcie_port);\n+\t} else {\n+\t\tciu_soft_prst_reg = (pcie_port) ? CVMX_CIU_SOFT_PRST1 : CVMX_CIU_SOFT_PRST;\n+\t\trst_ctl_reg = CVMX_MIO_RST_CTLX(pcie_port);\n+\t}\n+\tmio_rst_ctl.u64 = CVMX_READ_CSR(rst_ctl_reg);\n+\n+\tep_mode = ((OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CNF71XX)) ?\n+\t\t\t\t (mio_rst_ctl.s.prtmode != 1) :\n+\t\t\t\t (!mio_rst_ctl.s.host_mode));\n+\n+\tif (OCTEON_IS_MODEL(OCTEON_CN70XX) && pcie_port) {\n+\t\tcvmx_pemx_cfg_t pemx_cfg;\n+\n+\t\tpemx_cfg.u64 = csr_rd(CVMX_PEMX_CFG(0));\n+\t\tif ((pemx_cfg.s.md & 3) == 2) {\n+\t\t\tprintf(\"PCIe: Port %d in 1x4 mode.\\n\", pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\tif (ep_mode) {\n+\t\tprintf(\"%d:PCIe: Port %d in endpoint mode.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t}\n+\n+\t/* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be\n+\t * programmed\n+\t */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) {\n+\t\tif (pcie_port) {\n+\t\t\tcvmx_ciu_qlm1_t ciu_qlm;\n+\n+\t\t\tciu_qlm.u64 = csr_rd(CVMX_CIU_QLM1);\n+\t\t\tciu_qlm.s.txbypass = 1;\n+\t\t\tciu_qlm.s.txdeemph = 5;\n+\t\t\tciu_qlm.s.txmargin = 0x17;\n+\t\t\tcsr_wr(CVMX_CIU_QLM1, ciu_qlm.u64);\n+\t\t} else {\n+\t\t\tcvmx_ciu_qlm0_t ciu_qlm;\n+\n+\t\t\tciu_qlm.u64 = csr_rd(CVMX_CIU_QLM0);\n+\t\t\tciu_qlm.s.txbypass = 1;\n+\t\t\tciu_qlm.s.txdeemph = 5;\n+\t\t\tciu_qlm.s.txmargin = 0x17;\n+\t\t\tcsr_wr(CVMX_CIU_QLM0, ciu_qlm.u64);\n+\t\t}\n+\t}\n+\n+\t/* Bring the PCIe out of reset */\n+\tciu_soft_prst.u64 = CVMX_READ_CSR(ciu_soft_prst_reg);\n+\t/* After a chip reset the PCIe will also be in reset. If it\n+\t * isn't, most likely someone is trying to init it again\n+\t * without a proper PCIe reset.\n+\t */\n+\tif (ciu_soft_prst.s.soft_prst == 0) {\n+\t\t/* Reset the port */\n+\t\tciu_soft_prst.s.soft_prst = 1;\n+\t\tCVMX_WRITE_CSR(ciu_soft_prst_reg, ciu_soft_prst.u64);\n+\n+\t\t/* Read to make sure write happens */\n+\t\tciu_soft_prst.u64 = CVMX_READ_CSR(ciu_soft_prst_reg);\n+\n+\t\t/* Keep PERST asserted for 2 ms */\n+\t\tudelay(2000);\n+\t}\n+\n+\t/* Deassert PERST */\n+\tciu_soft_prst.u64 = CVMX_READ_CSR(ciu_soft_prst_reg);\n+\tciu_soft_prst.s.soft_prst = 0;\n+\tCVMX_WRITE_CSR(ciu_soft_prst_reg, ciu_soft_prst.u64);\n+\tciu_soft_prst.u64 = CVMX_READ_CSR(ciu_soft_prst_reg);\n+\n+\t/* Wait 1ms for PCIe reset to complete */\n+\tudelay(1000);\n+\n+\t/* Set MPLL multiplier as per Errata 20669. */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN70XX)) {\n+\t\tint qlm = __cvmx_pcie_get_qlm(0, pcie_port);\n+\t\tenum cvmx_qlm_mode mode;\n+\t\tint old_mult;\n+\t\tu64 meas_refclock = cvmx_qlm_measure_clock(qlm);\n+\n+\t\tif (meas_refclock > 99000000 && meas_refclock < 101000000) {\n+\t\t\told_mult = 35;\n+\t\t} else if (meas_refclock > 124000000 &&\n+\t\t\t meas_refclock < 126000000) {\n+\t\t\told_mult = 56;\n+\t\t} else if (meas_refclock > 156000000 &&\n+\t\t\t meas_refclock < 156500000) {\n+\t\t\told_mult = 45;\n+\t\t} else {\n+\t\t\tprintf(\"%s: Invalid reference clock for qlm %d\\n\",\n+\t\t\t __func__, qlm);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tmode = cvmx_qlm_get_mode(qlm);\n+\t\t__cvmx_qlm_set_mult(qlm, 2500, old_mult);\n+\t\t/* Adjust mplls for both dlms when configured as pcie 1x4 */\n+\t\tif (mode == CVMX_QLM_MODE_PCIE && pcie_port == 0)\n+\t\t\t__cvmx_qlm_set_mult(qlm + 1, 2500, old_mult);\n+\t}\n+\n+\t/*\n+\t * Check and make sure PCIe came out of reset. If it doesn't the board\n+\t * probably hasn't wired the clocks up and the interface should be\n+\t * skipped\n+\t */\n+\tif (CVMX_WAIT_FOR_FIELD64_NODE(node, rst_ctl_reg, cvmx_mio_rst_ctlx_t,\n+\t\t\t\t rst_done, ==, 1, 10000)) {\n+\t\tprintf(\"%d:PCIe: Port %d stuck in reset, skipping.\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Check BIST status */\n+\tpemx_bist_status.u64 = CVMX_READ_CSR(CVMX_PEMX_BIST_STATUS(pcie_port));\n+\tif (pemx_bist_status.u64)\n+\t\tprintf(\"%d:PCIe: BIST FAILED for port %d (0x%016llx)\\n\", node, pcie_port,\n+\t\t CAST64(pemx_bist_status.u64));\n+\tpemx_bist_status2.u64 = CVMX_READ_CSR(CVMX_PEMX_BIST_STATUS2(pcie_port));\n+\n+\t/*\n+\t * Errata PCIE-14766 may cause the lower 6 bits to be randomly set on\n+\t * CN63XXp1\n+\t */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_X))\n+\t\tpemx_bist_status2.u64 &= ~0x3full;\n+\n+\tif (pemx_bist_status2.u64) {\n+\t\tprintf(\"%d:PCIe: BIST2 FAILED for port %d (0x%016llx)\\n\",\n+\t\t node, pcie_port, CAST64(pemx_bist_status2.u64));\n+\t}\n+\n+\t/* Initialize the config space CSRs */\n+\t__cvmx_pcie_rc_initialize_config_space(node, pcie_port);\n+\n+\t/* Enable gen2 speed selection */\n+\tpciercx_cfg515.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG515(pcie_port));\n+\tpciercx_cfg515.s.dsc = 1;\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32);\n+\n+\t/* Bring the link up */\n+\tif (__cvmx_pcie_rc_initialize_link_gen2(node, pcie_port)) {\n+\t\t/* Some gen1 devices don't handle the gen 2 training correctly.\n+\t\t * Disable gen2 and try again with only gen1\n+\t\t */\n+\t\tcvmx_pciercx_cfg031_t pciercx_cfg031;\n+\n+\t\tpciercx_cfg031.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG031(pcie_port));\n+\t\tpciercx_cfg031.s.mls = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG031(pcie_port), pciercx_cfg031.u32);\n+\t\tif (__cvmx_pcie_rc_initialize_link_gen2(node, pcie_port)) {\n+\t\t\tprintf(\"PCIe: Link timeout on port %d, probably the slot is empty\\n\",\n+\t\t\t pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\t__cvmx_pcie_sli_config(node, pcie_port);\n+\n+\t/* Display the link status */\n+\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));\n+\tprintf(\"PCIe: Port %d link active, %d lanes, speed gen%d\\n\", pcie_port,\n+\t pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);\n+\n+\tpcie_link_initialized[node][pcie_port] = true;\n+\treturn 0;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Initialize a host mode PCIe gen 2 link. This function takes a PCIe\n+ * port from reset to a link up state. Software can then begin\n+ * configuring the rest of the link.\n+ *\n+ * @param node\t node\n+ * @param pcie_port PCIe port to initialize\n+ *\n+ * @return Zero on success\n+ */\n+static int __cvmx_pcie_rc_initialize_link_gen2_v3(int node, int pcie_port)\n+{\n+\tu8 ltssm_history[LTSSM_HISTORY_SIZE];\n+\tint ltssm_history_loc;\n+\tcvmx_pemx_ctl_status_t pem_ctl_status;\n+\tcvmx_pciercx_cfg006_t pciercx_cfg006;\n+\tcvmx_pciercx_cfg031_t pciercx_cfg031;\n+\tcvmx_pciercx_cfg032_t pciercx_cfg032;\n+\tcvmx_pciercx_cfg068_t pciercx_cfg068;\n+\tcvmx_pciercx_cfg448_t pciercx_cfg448;\n+\tcvmx_pciercx_cfg515_t pciercx_cfg515;\n+\tint max_gen, max_width;\n+\tu64 hold_time;\n+\tu64 bounce_allow_time;\n+\tu64 timeout, good_time, current_time;\n+\tint neg_gen, neg_width, bus, dev_gen, dev_width;\n+\tunsigned int cap, cap_next;\n+\tint ltssm_state, desired_gen;\n+\tint desired_width;\n+\tint i, need_speed_change, need_lane_change;\n+\tint do_retry_speed = 0;\n+\tint link_up = 0, is_loop_done = 0;\n+\n+\tif (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_PEMX_ON(pcie_port), cvmx_pemx_on_t, pemoor, ==, 1,\n+\t\t\t\t 100000)) {\n+\t\tprintf(\"N%d:PCIe: Port %d PEM not on, skipping\\n\", node, pcie_port);\n+\t\treturn -1;\n+\t}\n+\n+\t/* Record starting LTSSM state for debug */\n+\tmemset(ltssm_history, -1, sizeof(ltssm_history));\n+\tltssm_history[0] = __cvmx_pcie_rc_get_ltssm_state(node, pcie_port);\n+\tltssm_history_loc = 0;\n+\n+\tpciercx_cfg031.u32 = CVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG031(pcie_port));\n+\t/* Max speed of PEM from config (1-3) */\n+\tmax_gen = pciercx_cfg031.s.mls;\n+\t/* Max lane width of PEM (1-3) */\n+\tmax_width = pciercx_cfg031.s.mlw;\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: Link supports up to %d lanes, speed gen%d\\n\",\n+\t node, pcie_port, max_width, max_gen);\n+#endif\n+\n+\t/* Bring up the link */\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: Enabling the link\\n\", node, pcie_port);\n+#endif\n+\tpem_ctl_status.u64 = CVMX_READ_CSR(CVMX_PEMX_CTL_STATUS(pcie_port));\n+\tpem_ctl_status.s.lnk_enb = 1;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_CTL_STATUS(pcie_port), pem_ctl_status.u64);\n+\n+\t/*\n+\t * Configure SLI after enabling PCIe link. Is required for reading\n+\t * PCIe card capabilities.\n+\t */\n+\t__cvmx_pcie_sli_config(node, pcie_port);\n+\n+\t/*\n+\t * After the link is enabled no prints until link up or error,\n+\t * Otherwise will miss link state captures\n+\t */\n+\n+retry_speed:\n+\t/* Clear RC Correctable Error Status Register */\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG068(pcie_port), -1);\n+\n+\t/* Wait for the link to come up and link training to be complete */\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: Waiting for link\\n\", node, pcie_port);\n+#endif\n+\n+\t/* Timeout of 2 secs */\n+\ttimeout = get_timer(0) + 2000;\n+\n+\t/* Records when the link first went good */\n+\tgood_time = 0;\n+\n+\tdo {\n+\t\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));\n+\t\t/*\n+\t\t * Errata PEM-31375 PEM RSL access to PCLK registers can\n+\t\t * timeout during speed change. Check for temporary hardware\n+\t\t * timeout, and rety if happens\n+\t\t */\n+\t\tif (pciercx_cfg032.u32 == 0xffffffff)\n+\t\t\tcontinue;\n+\n+\t\t/* Record LTSSM state for debug */\n+\t\tltssm_state = __cvmx_pcie_rc_get_ltssm_state(node, pcie_port);\n+\n+\t\tif (ltssm_history[ltssm_history_loc] != ltssm_state) {\n+\t\t\tltssm_history_loc = (ltssm_history_loc + 1) & (LTSSM_HISTORY_SIZE - 1);\n+\t\t\tltssm_history[ltssm_history_loc] = ltssm_state;\n+\t\t}\n+\n+\t\t/* Check if the link is up */\n+\t\t//\t\tcurrent_time = cvmx_get_cycle();\n+\t\tcurrent_time = get_timer(0);\n+\t\tlink_up = (pciercx_cfg032.s.dlla && !pciercx_cfg032.s.lt);\n+\n+\t\tif (link_up) {\n+\t\t\t/* Is this the first link up? */\n+\t\t\tif (!good_time) {\n+\t\t\t\t/* Mark the time when the link transitioned to good */\n+\t\t\t\tgood_time = current_time;\n+\t\t\t} else {\n+\t\t\t\t/* Check for a link error */\n+\t\t\t\tpciercx_cfg068.u32 = CVMX_PCIE_CFGX_READ(\n+\t\t\t\t\tpcie_port, CVMX_PCIERCX_CFG068(pcie_port));\n+\t\t\t\tif (pciercx_cfg068.s.res) {\n+\t\t\t\t\t/*\n+\t\t\t\t\t * Ignore errors before we've been\n+\t\t\t\t\t * stable for bounce_allow_time\n+\t\t\t\t\t */\n+\t\t\t\t\tif (good_time + bounce_allow_time <=\n+\t\t\t\t\t current_time) {\n+#ifdef DEBUG_PCIE\n+\t\t\t\t\t\tprintf(\"N%d.PCIe%d: Link errors after link up\\n\",\n+\t\t\t\t\t\t node, pcie_port);\n+#endif\n+\t\t\t\t\t\t/* Link error, signal a retry */\n+\t\t\t\t\t\treturn 1;\n+\t\t\t\t\t}\n+\n+\t\t\t\t\t/*\n+\t\t\t\t\t * Clear RC Correctable Error\n+\t\t\t\t\t * Status Register\n+\t\t\t\t\t */\n+\t\t\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port,\n+\t\t\t\t\t\t\t CVMX_PCIERCX_CFG068(pcie_port),\n+\t\t\t\t\t\t\t -1);\n+#ifdef DEBUG_PCIE\n+\t\t\t\t\tprintf(\"N%d.PCIe%d: Ignored error during settling time\\n\",\n+\t\t\t\t\t node, pcie_port);\n+#endif\n+\t\t\t\t}\n+\t\t\t}\n+\t\t} else if (good_time) {\n+\t\t\tif (good_time + bounce_allow_time <= current_time) {\n+\t\t\t\t/*\n+\t\t\t\t * We allow bounces for bounce_allow_time after\n+\t\t\t\t * the link is good. Once this time passes any\n+\t\t\t\t * bounce requires a retry\n+\t\t\t\t */\n+#ifdef DEBUG_PCIE\n+\t\t\t\tprintf(\"N%d.PCIe%d: Link bounce detected\\n\",\n+\t\t\t\t node, pcie_port);\n+#endif\n+\t\t\t\treturn 1; /* Link bounce, signal a retry */\n+\t\t\t}\n+\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"N%d.PCIe%d: Ignored bounce during settling time\\n\",\n+\t\t\t node, pcie_port);\n+#endif\n+\t\t}\n+\n+\t\t/* Determine if we've hit the timeout */\n+\t\tis_loop_done = (current_time >= timeout);\n+\n+\t\t/*\n+\t\t * Determine if we've had a good link for the required hold\n+\t\t * time\n+\t\t */\n+\t\tis_loop_done |= link_up && (good_time + hold_time <=\n+\t\t\t\t\t current_time);\n+\t} while (!is_loop_done);\n+\n+\t/* Trace the LTSSM state */\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: LTSSM History\\n\", node, pcie_port);\n+#endif\n+\tfor (i = 0; i < LTSSM_HISTORY_SIZE; i++) {\n+\t\tltssm_history_loc = (ltssm_history_loc + 1) & (LTSSM_HISTORY_SIZE - 1);\n+#ifdef DEBUG_PCIE\n+\t\tif (ltssm_history[ltssm_history_loc] != 0xff)\n+\t\t\tprintf(\"N%d.PCIe%d: %s\\n\", node, pcie_port,\n+\t\t\t cvmx_pcie_get_ltssm_string(ltssm_history[ltssm_history_loc]));\n+#endif\n+\t}\n+\n+\tif (!link_up) {\n+\t\tltssm_state = __cvmx_pcie_rc_get_ltssm_state(node, pcie_port);\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d.PCIe%d: Link down, Data link layer %s(DLLA=%d), Link training %s(LT=%d), LTSSM %s\\n\",\n+\t\t node, pcie_port, pciercx_cfg032.s.dlla ? \"active\" : \"down\",\n+\t\t pciercx_cfg032.s.dlla, pciercx_cfg032.s.lt ? \"active\" : \"complete\",\n+\t\t pciercx_cfg032.s.lt, cvmx_pcie_get_ltssm_string(ltssm_state));\n+#endif\n+\t\treturn 1; /* Link down, signal a retry */\n+\t}\n+\n+\t/* Report the negotiated link speed and width */\n+\tneg_gen = pciercx_cfg032.s.ls;\t /* Current speed of PEM (1-3) */\n+\tneg_width = pciercx_cfg032.s.nlw; /* Current lane width of PEM (1-8) */\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: Link negotiated %d lanes, speed gen%d\\n\", node, pcie_port, neg_width,\n+\t neg_gen);\n+#endif\n+\t/* Determine PCIe bus number the directly attached device uses */\n+\tpciercx_cfg006.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG006(pcie_port));\n+\tbus = pciercx_cfg006.s.sbnum;\n+\n+\t/* The SLI has to be initialized so we can read the downstream devices */\n+\tdev_gen = 1; /* Device max speed (1-3) */\n+\tdev_width = 1; /* Device max lane width (1-16) */\n+#ifdef DEBUG_PCIE\n+\tprintf(\"N%d.PCIe%d: Reading Bus %d device max speed and width\\n\", node, pcie_port, bus);\n+#endif\n+\n+\t/*\n+\t * Here is the second part of the config retry changes. Wait for 700ms\n+\t * after setting up the link before continuing. PCIe says the devices\n+\t * may need up to 900ms to come up. 700ms plus 200ms from above gives\n+\t * us a total of 900ms\n+\t */\n+\tudelay(PCIE_DEVICE_READY_WAIT_DELAY_MICROSECONDS);\n+\n+\t/* Read PCI capability pointer at offset 0x34 of target */\n+\tcap = cvmx_pcie_config_read32_retry(node, pcie_port, bus, 0, 0, 0x34);\n+\n+\t/* Check if we were able to read capabilities pointer */\n+\tif (cap == 0xffffffff)\n+\t\treturn 1; /* Signal retry needed */\n+\n+\t/* Read device max speed and width */\n+\tcap_next = cap & 0xff;\n+\twhile (cap_next) {\n+\t\tcap = cvmx_pcie_config_read32_retry(node, pcie_port, bus,\n+\t\t\t\t\t\t 0, 0, cap_next);\n+\t\tif (cap == 0xffffffff)\n+\t\t\treturn 1; /* Signal retry needed */\n+\n+\t\t/* Is this a PCIe capability (0x10)? */\n+\t\tif ((cap & 0xff) == 0x10) {\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"N%d.PCIe%d: Found PCIe capability at offset 0x%x\\n\",\n+\t\t\t node, pcie_port, cap_next);\n+#endif\n+\t\t\t/* Offset 0xc contains the max link info */\n+\t\t\tcap = cvmx_pcie_config_read32_retry(node, pcie_port, bus, 0, 0,\n+\t\t\t\t\t\t\t cap_next + 0xc);\n+\t\t\tif (cap == 0xffffffff)\n+\t\t\t\treturn 1;\t /* Signal retry needed */\n+\t\t\tdev_gen = cap & 0xf;\t /* Max speed of PEM from config (1-3) */\n+\t\t\tdev_width = (cap >> 4) & 0x3f; /* Max lane width of PEM (1-16) */\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"N%d.PCIe%d: Device supports %d lanes, speed gen%d\\n\", node,\n+\t\t\t pcie_port, dev_width, dev_gen);\n+#endif\n+\t\t\tbreak;\n+\t\t}\n+\t\t/* Move to next capability */\n+\t\tcap_next = (cap >> 8) & 0xff;\n+\t}\n+\n+\t/*\n+\t * Desired link speed and width is either limited by the device or our\n+\t * PEM configuration. Choose the most restrictive limit\n+\t */\n+\tdesired_gen = (dev_gen < max_gen) ? dev_gen : max_gen;\n+\tdesired_width = (dev_width < max_width) ? dev_width : max_width;\n+\n+\t/*\n+\t * We need a change if we don't match the desired speed or width.\n+\t * Note that we allow better than expected in case the device lied\n+\t * about its capabilities\n+\t */\n+\tneed_speed_change = (neg_gen < desired_gen);\n+\tneed_lane_change = (neg_width < desired_width);\n+\n+\tif (need_lane_change) {\n+\t\t/* We didn't get the maximum number of lanes */\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d.PCIe%d: Link width (%d) less that supported (%d)\\n\",\n+\t\t node, pcie_port, neg_width, desired_width);\n+#endif\n+\t\treturn 2; /* Link wrong width, signal a retry */\n+\t} else if (need_speed_change) {\n+\t\tif (do_retry_speed) {\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"N%d.PCIe%d: Link speed (gen%d) less that supported (gen%d)\\n\", node,\n+\t\t\t pcie_port, neg_gen, desired_gen);\n+#endif\n+\t\t\treturn 1; /* Link at width, but speed low. Request a retry */\n+\t\t}\n+\n+\t\t/* We didn't get the maximum speed. Request a speed change */\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d.PCIe%d: Link speed (gen%d) less that supported (gen%d), requesting a speed change\\n\",\n+\t\t node, pcie_port, neg_gen, desired_gen);\n+#endif\n+\t\tpciercx_cfg515.u32 =\n+\t\t\tCVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t CVMX_PCIERCX_CFG515(pcie_port));\n+\t\tpciercx_cfg515.s.dsc = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port,\n+\t\t\t\t CVMX_PCIERCX_CFG515(pcie_port),\n+\t\t\t\t pciercx_cfg515.u32);\n+\t\tmdelay(100);\n+\t\tdo_retry_speed = true;\n+\t\tgoto retry_speed;\n+\t} else {\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d.PCIe%d: Link at best speed and width\\n\",\n+\t\t node, pcie_port);\n+#endif\n+\t\t/* For gen3 links check if we are getting errors over the link */\n+\t\tif (neg_gen == 3) {\n+\t\t\t/* Read RC Correctable Error Status Register */\n+\t\t\tpciercx_cfg068.u32 =\n+\t\t\t\tCVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG068(pcie_port));\n+\t\t\tif (pciercx_cfg068.s.res) {\n+#ifdef DEBUG_PCIE\n+\t\t\t\tprintf(\"N%d.PCIe%d: Link reporting error status\\n\", node,\n+\t\t\t\t pcie_port);\n+#endif\n+\t\t\t\treturn 1; /* Getting receiver errors, request a retry */\n+\t\t\t}\n+\t\t}\n+\t\treturn 0; /* Link at correct speed and width */\n+\t}\n+\n+\t/* Update the Replay Time Limit. Empirically, some PCIe devices take a\n+\t * little longer to respond than expected under load. As a workaround\n+\t * for this we configure the Replay Time Limit to the value expected\n+\t * for a 512 byte MPS instead of our actual 256 byte MPS. The numbers\n+\t * below are directly from the PCIe spec table 3-4\n+\t */\n+\tpciercx_cfg448.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG448(pcie_port));\n+\tswitch (pciercx_cfg032.s.nlw) {\n+\tcase 1: /* 1 lane */\n+\t\tpciercx_cfg448.s.rtl = 1677;\n+\t\tbreak;\n+\tcase 2: /* 2 lanes */\n+\t\tpciercx_cfg448.s.rtl = 867;\n+\t\tbreak;\n+\tcase 4: /* 4 lanes */\n+\t\tpciercx_cfg448.s.rtl = 462;\n+\t\tbreak;\n+\tcase 8: /* 8 lanes */\n+\t\tpciercx_cfg448.s.rtl = 258;\n+\t\tbreak;\n+\t}\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG448(pcie_port), pciercx_cfg448.u32);\n+\n+\treturn 0;\n+}\n+\n+static int __cvmx_pcie_rc_initialize_gen2_v3(int pcie_port)\n+{\n+\tcvmx_rst_ctlx_t rst_ctl;\n+\tcvmx_rst_soft_prstx_t rst_soft_prst;\n+\tcvmx_pciercx_cfg031_t pciercx_cfg031;\n+\tcvmx_pciercx_cfg032_t pciercx_cfg032;\n+\tcvmx_pciercx_cfg038_t pciercx_cfg038;\n+\tcvmx_pciercx_cfg040_t pciercx_cfg040;\n+\tcvmx_pciercx_cfg515_t pciercx_cfg515;\n+\tcvmx_pciercx_cfg548_t pciercx_cfg548;\n+\tcvmx_pemx_bist_status_t pemx_bist_status;\n+\tu64 rst_soft_prst_reg;\n+\tint qlm;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\tbool requires_pem_reset = 0;\n+\tenum cvmx_qlm_mode mode = CVMX_QLM_MODE_DISABLED;\n+\tint retry_count = 0;\n+\tint result = 0;\n+\n+\tpcie_port &= 0x3;\n+\n+\t/* Assume link down until proven up */\n+\tpcie_link_initialized[node][pcie_port] = false;\n+\n+\t/* Attempt link initialization up to 3 times */\n+\twhile (retry_count <= MAX_RETRIES) {\n+#ifdef DEBUG_PCIE\n+\t\tif (retry_count)\n+\t\t\tprintf(\"N%d:PCIE%d: Starting link retry %d\\n\", node, pcie_port,\n+\t\t\t retry_count);\n+#endif\n+\t\tif (pcie_port >= CVMX_PCIE_PORTS) {\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"Invalid PCIe%d port\\n\", pcie_port);\n+#endif\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tqlm = __cvmx_pcie_get_qlm(node, pcie_port);\n+\n+\t\tif (qlm < 0)\n+\t\t\treturn -1;\n+\n+\t\tmode = cvmx_qlm_get_mode(qlm);\n+\t\tif (__cvmx_pcie_check_pcie_port(node, pcie_port, mode))\n+\t\t\treturn -1;\n+\n+\t\trst_soft_prst_reg = CVMX_RST_SOFT_PRSTX(pcie_port);\n+\t\trst_ctl.u64 = CVMX_READ_CSR(CVMX_RST_CTLX(pcie_port));\n+\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN78XX)) {\n+\t\t\tCVMX_WRITE_CSR(CVMX_DTX_PEMX_SELX(0, pcie_port), 0x17);\n+\t\t\tCVMX_WRITE_CSR(CVMX_DTX_PEMX_SELX(1, pcie_port), 0);\n+\t\t}\n+\n+\t\tif (!rst_ctl.s.host_mode) {\n+\t\t\tprintf(\"N%d:PCIE: Port %d in endpoint mode.\\n\",\n+\t\t\t node, pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* Bring the PCIe out of reset */\n+\t\trst_soft_prst.u64 = CVMX_READ_CSR(rst_soft_prst_reg);\n+\n+\t\t/*\n+\t\t * After a chip reset the PCIe will also be in reset. If it\n+\t\t * isn't, most likely someone is trying to init it again\n+\t\t * without a proper PCIe reset.\n+\t\t */\n+\t\tif (rst_soft_prst.s.soft_prst == 0) {\n+\t\t\t/* Disable the MAC controller before resetting */\n+\t\t\t__cvmx_pcie_config_pemon(node, pcie_port, 0);\n+\n+\t\t\t/* Reset the port */\n+\t\t\trst_soft_prst.s.soft_prst = 1;\n+\t\t\tCVMX_WRITE_CSR(rst_soft_prst_reg, rst_soft_prst.u64);\n+\n+\t\t\t/* Read to make sure write happens */\n+\t\t\trst_soft_prst.u64 = CVMX_READ_CSR(rst_soft_prst_reg);\n+\n+\t\t\t/* Keep PERST asserted for 2 ms */\n+\t\t\tudelay(2000);\n+\n+\t\t\t/* Reset GSER_PHY to put in a clean state */\n+\t\t\t__cvmx_pcie_gser_phy_config(node, pcie_port, qlm);\n+\t\t\trequires_pem_reset = 1;\n+\n+\t\t\t/* Enable MAC controller before taking pcie out of reset */\n+\t\t\t__cvmx_pcie_config_pemon(node, pcie_port, 1);\n+\t\t}\n+\n+\t\t/* Deassert PERST */\n+\t\trst_soft_prst.u64 = CVMX_READ_CSR(rst_soft_prst_reg);\n+\t\trst_soft_prst.s.soft_prst = 0;\n+\t\tCVMX_WRITE_CSR(rst_soft_prst_reg, rst_soft_prst.u64);\n+\t\trst_soft_prst.u64 = CVMX_READ_CSR(rst_soft_prst_reg);\n+\n+\t\t/* Check if PLLs are locked after GSER_PHY reset. */\n+\t\tif (requires_pem_reset) {\n+\t\t\tcvmx_pemx_cfg_t pemx_cfg;\n+\n+\t\t\tpemx_cfg.u64 = csr_rd(CVMX_PEMX_CFG(pcie_port));\n+\t\t\tif (CVMX_WAIT_FOR_FIELD64(CVMX_GSERX_QLM_STAT(qlm), cvmx_gserx_qlm_stat_t,\n+\t\t\t\t\t\t rst_rdy, ==, 1, 10000)) {\n+\t\t\t\tprintf(\"QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\\n\", qlm);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tif (pemx_cfg.cn78xx.lanes8 &&\n+\t\t\t (CVMX_WAIT_FOR_FIELD64(CVMX_GSERX_QLM_STAT(qlm + 1),\n+\t\t\t\t\t\t cvmx_gserx_qlm_stat_t, rst_rdy, ==, 1, 10000))) {\n+\t\t\t\tprintf(\"QLM%d: Timeout waiting for GSERX_QLM_STAT[rst_rdy]\\n\",\n+\t\t\t\t qlm + 1);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Wait 1ms for PCIe reset to complete */\n+\t\tudelay(1000);\n+\n+\t\t/*\n+\t\t * Check and make sure PCIe came out of reset. If it doesn't\n+\t\t * the board probably hasn't wired the clocks up and the\n+\t\t * interface should be skipped\n+\t\t */\n+\t\tif (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_RST_CTLX(pcie_port),\n+\t\t\t\t\t cvmx_rst_ctlx_t,\n+\t\t\t\t\t rst_done, ==, 1, 10000)) {\n+\t\t\tprintf(\"N%d:PCIE: Port %d stuck in reset, skipping.\\n\", node, pcie_port);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\t/* Check BIST status */\n+\t\tpemx_bist_status.u64 = CVMX_READ_CSR(CVMX_PEMX_BIST_STATUS(pcie_port));\n+\t\tif (pemx_bist_status.u64)\n+\t\t\tprintf(\"N%d:PCIE: BIST FAILED for port %d (0x%016llx)\\n\", node, pcie_port,\n+\t\t\t CAST64(pemx_bist_status.u64));\n+\n+\t\t\t/* Initialize the config space CSRs */\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d:PCIE%d Initialize Config Space\\n\", node, pcie_port);\n+#endif\n+\t\t__cvmx_pcie_rc_initialize_config_space(node, pcie_port);\n+\n+\t\t/* Enable gen2 speed selection */\n+\t\tpciercx_cfg515.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG515(pcie_port));\n+\t\tpciercx_cfg515.s.dsc = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG515(pcie_port), pciercx_cfg515.u32);\n+\n+\t\t/* Do the link retries on the PCIe interface */\n+\t\tif (retry_count == MAX_RETRIES) {\n+\t\t\t/*\n+\t\t\t * This has to be done AFTER the QLM/PHY interface\n+\t\t\t * initialized\n+\t\t\t */\n+\t\t\tpciercx_cfg031.u32 =\n+\t\t\t\tCVMX_PCIE_CFGX_READ(pcie_port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG031(pcie_port));\n+\t\t\t/*\n+\t\t\t * Drop speed to gen2 if link bouncing\n+\t\t\t * Result = -1 PEM in reset\n+\t\t\t * Result = 0: link speed and width ok no retry needed\n+\t\t\t * Result = 1: link errors or speed change needed\n+\t\t\t * Result = 2: lane width error\n+\t\t\t */\n+\t\t\tif (pciercx_cfg031.s.mls == 3 && result != 2) {\n+#ifdef DEBUG_PCIE\n+\t\t\t\tprintf(\"N%d:PCIE%d: Dropping speed to gen2\\n\", node, pcie_port);\n+#endif\n+\t\t\t\tpciercx_cfg031.s.mls = 2;\n+\t\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG031(pcie_port),\n+\t\t\t\t\t\t pciercx_cfg031.u32);\n+\n+\t\t\t\t/* Set the target link speed */\n+\t\t\t\tpciercx_cfg040.u32 = CVMX_PCIE_CFGX_READ(\n+\t\t\t\t\tpcie_port, CVMX_PCIERCX_CFG040(pcie_port));\n+\t\t\t\tpciercx_cfg040.s.tls = 2;\n+\t\t\t\tCVMX_PCIE_CFGX_WRITE(pcie_port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG040(pcie_port),\n+\t\t\t\t\t\t pciercx_cfg040.u32);\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Bring the link up */\n+\t\tresult = __cvmx_pcie_rc_initialize_link_gen2_v3(node, pcie_port);\n+\t\tif (result == 0) {\n+#ifdef DEBUG_PCIE\n+\t\t\tprintf(\"N%d:PCIE%d: Link does not need a retry\\n\", node, pcie_port);\n+#endif\n+\t\t\tbreak;\n+\t\t} else if (result > 0) {\n+\t\t\tif (retry_count >= MAX_RETRIES) {\n+\t\t\t\tint link_up;\n+#ifdef DEBUG_PCIE\n+\t\t\t\tprintf(\"N%d:PCIE%d: Link requested a retry, but hit the max retries\\n\",\n+\t\t\t\t node, pcie_port);\n+#endif\n+\t\t\t\t/* If the link is down, report failure */\n+\t\t\t\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(\n+\t\t\t\t\tpcie_port,\n+\t\t\t\t\tCVMX_PCIERCX_CFG032(pcie_port));\n+\t\t\t\tlink_up = (pciercx_cfg032.s.dlla && !pciercx_cfg032.s.lt);\n+\t\t\t\tif (!link_up)\n+\t\t\t\t\tresult = -1;\n+\t\t\t}\n+#ifdef DEBUG_PCIE\n+\t\t\telse\n+\t\t\t\tprintf(\"N%d.PCIE%d: Link requested a retry\\n\", node, pcie_port);\n+#endif\n+\t\t}\n+\t\tif (result < 0) {\n+\t\t\tint ltssm_state = __cvmx_pcie_rc_get_ltssm_state(node, pcie_port);\n+\n+\t\t\tprintf(\"N%d:PCIE%d: Link timeout, probably the slot is empty (LTSSM %s)\\n\",\n+\t\t\t node, pcie_port, cvmx_pcie_get_ltssm_string(ltssm_state));\n+\t\t\treturn -1;\n+\t\t}\n+\t\tretry_count++;\n+\t}\n+\n+\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));\n+\t/*\n+\t * Errata PEM-28816: Link retrain initiated at GEN1 can cause PCIE\n+\t * link to hang. For Gen1 links we must disable equalization\n+\t */\n+\tif (pciercx_cfg032.s.ls == 1) {\n+#ifdef DEBUG_PCIE\n+\t\tprintf(\"N%d:PCIE%d: Disabling equalization for GEN1 Link\\n\", node, pcie_port);\n+#endif\n+\t\tpciercx_cfg548.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG548(pcie_port));\n+\t\tpciercx_cfg548.s.ed = 1;\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG548(pcie_port), pciercx_cfg548.u32);\n+\t}\n+\n+\t/* Errata PCIE-29440: Atomic operations to work properly */\n+\tpciercx_cfg038.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG038(pcie_port));\n+\tpciercx_cfg038.s.atom_op_eb = 0;\n+\tpciercx_cfg038.s.atom_op = 1;\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG038(pcie_port), pciercx_cfg038.u32);\n+\n+\t/* Errata PCIE-29566 PEM Link Hangs after going into L1 */\n+\tpciercx_cfg548.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG548(pcie_port));\n+\tpciercx_cfg548.s.grizdnc = 0;\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIERCX_CFG548(pcie_port), pciercx_cfg548.u32);\n+\n+\tif (result < 0)\n+\t\treturn result;\n+\n+\t/* Display the link status */\n+\tpciercx_cfg032.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIERCX_CFG032(pcie_port));\n+\tprintf(\"N%d:PCIe: Port %d link active, %d lanes, speed gen%d\\n\", node, pcie_port,\n+\t pciercx_cfg032.s.nlw, pciercx_cfg032.s.ls);\n+\n+\tpcie_link_initialized[node][pcie_port] = true;\n+\treturn 0;\n+}\n+\n+/**\n+ * Initialize a PCIe port for use in host(RC) mode. It doesn't enumerate the bus.\n+ *\n+ * @param pcie_port PCIe port to initialize for a node\n+ *\n+ * @return Zero on success\n+ */\n+int cvmx_pcie_rc_initialize(int pcie_port)\n+{\n+\tint result;\n+\n+\tif (OCTEON_IS_OCTEON2() || OCTEON_IS_MODEL(OCTEON_CN70XX))\n+\t\tresult = __cvmx_pcie_rc_initialize_gen2(pcie_port);\n+\telse\n+\t\tresult = __cvmx_pcie_rc_initialize_gen2_v3(pcie_port);\n+\n+\tif (result == 0)\n+\t\tcvmx_error_enable_group(CVMX_ERROR_GROUP_PCI, pcie_port);\n+\treturn result;\n+}\n+\n+/**\n+ * Shutdown a PCIe port and put it in reset\n+ *\n+ * @param pcie_port PCIe port to shutdown for a node\n+ *\n+ * @return Zero on success\n+ */\n+int cvmx_pcie_rc_shutdown(int pcie_port)\n+{\n+\tu64 ciu_soft_prst_reg;\n+\tcvmx_ciu_soft_prst_t ciu_soft_prst;\n+\tint node;\n+\n+\t/* Shutdown only if PEM is in RC mode */\n+\tif (!cvmx_pcie_is_host_mode(pcie_port))\n+\t\treturn -1;\n+\n+\tnode = (pcie_port >> 4) & 0x3;\n+\tpcie_port &= 0x3;\n+\tcvmx_error_disable_group(CVMX_ERROR_GROUP_PCI, pcie_port);\n+\t/* Wait for all pending operations to complete */\n+\tif (CVMX_WAIT_FOR_FIELD64_NODE(node, CVMX_PEMX_CPL_LUT_VALID(pcie_port),\n+\t\t\t\t cvmx_pemx_cpl_lut_valid_t, tag, ==,\n+\t\t\t\t 0, 2000))\n+\t\tdebug(\"PCIe: Port %d shutdown timeout\\n\", pcie_port);\n+\n+\tif (OCTEON_IS_OCTEON3()) {\n+\t\tciu_soft_prst_reg = CVMX_RST_SOFT_PRSTX(pcie_port);\n+\t} else {\n+\t\tciu_soft_prst_reg = (pcie_port) ? CVMX_CIU_SOFT_PRST1 :\n+\t\t\tCVMX_CIU_SOFT_PRST;\n+\t}\n+\n+\t/* Force reset */\n+\tciu_soft_prst.u64 = CVMX_READ_CSR(ciu_soft_prst_reg);\n+\tciu_soft_prst.s.soft_prst = 1;\n+\tCVMX_WRITE_CSR(ciu_soft_prst_reg, ciu_soft_prst.u64);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Build a PCIe config space request address for a device\n+ *\n+ * @param node\t node\n+ * @param port\t PCIe port (relative to the node) to access\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ *\n+ * @return 64bit Octeon IO address\n+ */\n+static uint64_t __cvmx_pcie_build_config_addr(int node, int port, int bus, int dev, int fn, int reg)\n+{\n+\tcvmx_pcie_address_t pcie_addr;\n+\tcvmx_pciercx_cfg006_t pciercx_cfg006;\n+\n+\tpciercx_cfg006.u32 = cvmx_pcie_cfgx_read_node(node, port,\n+\t\t\t\t\t\t CVMX_PCIERCX_CFG006(port));\n+\tif (bus <= pciercx_cfg006.s.pbnum && dev != 0)\n+\t\treturn 0;\n+\n+\tpcie_addr.u64 = 0;\n+\tpcie_addr.config.upper = 2;\n+\tpcie_addr.config.io = 1;\n+\tpcie_addr.config.did = 3;\n+\tpcie_addr.config.subdid = 1;\n+\tpcie_addr.config.node = node;\n+\tpcie_addr.config.es = _CVMX_PCIE_ES;\n+\tpcie_addr.config.port = port;\n+\t/* Always use config type 0 */\n+\tif (pciercx_cfg006.s.pbnum == 0)\n+\t\tpcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum + 1);\n+\telse\n+\t\tpcie_addr.config.ty = (bus > pciercx_cfg006.s.pbnum);\n+\tpcie_addr.config.bus = bus;\n+\tpcie_addr.config.dev = dev;\n+\tpcie_addr.config.func = fn;\n+\tpcie_addr.config.reg = reg;\n+\treturn pcie_addr.u64;\n+}\n+\n+/**\n+ * Read 8bits from a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ *\n+ * @return Result of the read\n+ */\n+uint8_t cvmx_pcie_config_read8(int pcie_port, int bus, int dev, int fn, int reg)\n+{\n+\tu64 address;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);\n+\tif (address)\n+\t\treturn cvmx_read64_uint8(address);\n+\telse\n+\t\treturn 0xff;\n+}\n+\n+/**\n+ * Read 16bits from a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ *\n+ * @return Result of the read\n+ */\n+uint16_t cvmx_pcie_config_read16(int pcie_port, int bus, int dev, int fn, int reg)\n+{\n+\tu64 address;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);\n+\tif (address)\n+\t\treturn le16_to_cpu(cvmx_read64_uint16(address));\n+\telse\n+\t\treturn 0xffff;\n+}\n+\n+static uint32_t __cvmx_pcie_config_read32(int node, int pcie_port, int bus, int dev, int func,\n+\t\t\t\t\t int reg, int lst)\n+{\n+\tu64 address;\n+\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, func, reg);\n+\tif (lst) {\n+\t\tif (address && pcie_link_initialized[node][pcie_port])\n+\t\t\treturn le32_to_cpu(cvmx_read64_uint32(address));\n+\t\telse\n+\t\t\treturn 0xffffffff;\n+\t} else if (address) {\n+\t\treturn le32_to_cpu(cvmx_read64_uint32(address));\n+\t} else {\n+\t\treturn 0xffffffff;\n+\t}\n+}\n+\n+/**\n+ * Read 32bits from a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ *\n+ * @return Result of the read\n+ */\n+uint32_t cvmx_pcie_config_read32(int pcie_port, int bus, int dev, int fn, int reg)\n+{\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\treturn __cvmx_pcie_config_read32(node, pcie_port, bus, dev, fn, reg,\n+\t\t\t\t\t pcie_link_initialized[node][pcie_port]);\n+}\n+\n+/**\n+ * Write 8bits to a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ * @param val Value to write\n+ */\n+void cvmx_pcie_config_write8(int pcie_port, int bus, int dev, int fn, int reg, uint8_t val)\n+{\n+\tu64 address;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);\n+\tif (address)\n+\t\tcvmx_write64_uint8(address, val);\n+}\n+\n+/**\n+ * Write 16bits to a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ * @param val Value to write\n+ */\n+void cvmx_pcie_config_write16(int pcie_port, int bus, int dev, int fn, int reg, uint16_t val)\n+{\n+\tu64 address;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);\n+\tif (address)\n+\t\tcvmx_write64_uint16(address, cpu_to_le16(val));\n+}\n+\n+/**\n+ * Write 32bits to a Device's config space\n+ *\n+ * @param pcie_port PCIe port the device is on\n+ * @param bus Sub bus\n+ * @param dev Device ID\n+ * @param fn Device sub function\n+ * @param reg Register to access\n+ * @param val Value to write\n+ */\n+void cvmx_pcie_config_write32(int pcie_port, int bus, int dev, int fn, int reg, uint32_t val)\n+{\n+\tu64 address;\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tpcie_port &= 0x3;\n+\taddress = __cvmx_pcie_build_config_addr(node, pcie_port, bus, dev, fn, reg);\n+\tif (address)\n+\t\tcvmx_write64_uint32(address, cpu_to_le32(val));\n+}\n+\n+/**\n+ * Read a PCIe config space register indirectly. This is used for\n+ * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.\n+ *\n+ * @param pcie_port PCIe port to read from\n+ * @param cfg_offset Address to read\n+ *\n+ * @return Value read\n+ */\n+uint32_t cvmx_pcie_cfgx_read(int pcie_port, uint32_t cfg_offset)\n+{\n+\treturn cvmx_pcie_cfgx_read_node(0, pcie_port, cfg_offset);\n+}\n+\n+uint32_t cvmx_pcie_cfgx_read_node(int node, int pcie_port, uint32_t cfg_offset)\n+{\n+\tcvmx_pemx_cfg_rd_t pemx_cfg_rd;\n+\n+\tpemx_cfg_rd.u64 = 0;\n+\tpemx_cfg_rd.s.addr = cfg_offset;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_CFG_RD(pcie_port), pemx_cfg_rd.u64);\n+\tpemx_cfg_rd.u64 = CVMX_READ_CSR(CVMX_PEMX_CFG_RD(pcie_port));\n+\n+\treturn pemx_cfg_rd.s.data;\n+}\n+\n+/**\n+ * Write a PCIe config space register indirectly. This is used for\n+ * registers of the form PCIEEP_CFG??? and PCIERC?_CFG???.\n+ *\n+ * @param pcie_port PCIe port to write to\n+ * @param cfg_offset Address to write\n+ * @param val Value to write\n+ */\n+void cvmx_pcie_cfgx_write(int pcie_port, uint32_t cfg_offset, uint32_t val)\n+{\n+\tcvmx_pcie_cfgx_write_node(0, pcie_port, cfg_offset, val);\n+}\n+\n+void cvmx_pcie_cfgx_write_node(int node, int pcie_port, uint32_t cfg_offset, uint32_t val)\n+{\n+\tcvmx_pemx_cfg_wr_t pemx_cfg_wr;\n+\n+\tpemx_cfg_wr.u64 = 0;\n+\tpemx_cfg_wr.s.addr = cfg_offset;\n+\tpemx_cfg_wr.s.data = val;\n+\tCVMX_WRITE_CSR(CVMX_PEMX_CFG_WR(pcie_port), pemx_cfg_wr.u64);\n+}\n+\n+extern int cvmx_pcie_is_host_mode(int pcie_port);\n+\n+/**\n+ * Initialize a PCIe port for use in target(EP) mode.\n+ *\n+ * @param pcie_port PCIe port to initialize for a node\n+ *\n+ * @return Zero on success\n+ */\n+int cvmx_pcie_ep_initialize(int pcie_port)\n+{\n+\tint node = (pcie_port >> 4) & 0x3;\n+\n+\tif (cvmx_pcie_is_host_mode(pcie_port))\n+\t\treturn -1;\n+\n+\tpcie_port &= 0x3;\n+\n+\t/* CN63XX Pass 1.0 errata G-14395 requires the QLM De-emphasis be\n+\t * programmed\n+\t */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN63XX_PASS1_0)) {\n+\t\tif (pcie_port) {\n+\t\t\tcvmx_ciu_qlm1_t ciu_qlm;\n+\n+\t\t\tciu_qlm.u64 = csr_rd(CVMX_CIU_QLM1);\n+\t\t\tciu_qlm.s.txbypass = 1;\n+\t\t\tciu_qlm.s.txdeemph = 5;\n+\t\t\tciu_qlm.s.txmargin = 0x17;\n+\t\t\tcsr_wr(CVMX_CIU_QLM1, ciu_qlm.u64);\n+\t\t} else {\n+\t\t\tcvmx_ciu_qlm0_t ciu_qlm;\n+\n+\t\t\tciu_qlm.u64 = csr_rd(CVMX_CIU_QLM0);\n+\t\t\tciu_qlm.s.txbypass = 1;\n+\t\t\tciu_qlm.s.txdeemph = 5;\n+\t\t\tciu_qlm.s.txmargin = 0x17;\n+\t\t\tcsr_wr(CVMX_CIU_QLM0, ciu_qlm.u64);\n+\t\t}\n+\t}\n+\n+\t/* Enable bus master and memory */\n+\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIEEPX_CFG001(pcie_port), 0x6);\n+\n+\t/* Max Payload Size (PCIE*_CFG030[MPS]) */\n+\t/* Max Read Request Size (PCIE*_CFG030[MRRS]) */\n+\t/* Relaxed-order, no-snoop enables (PCIE*_CFG030[RO_EN,NS_EN] */\n+\t/* Error Message Enables (PCIE*_CFG030[CE_EN,NFE_EN,FE_EN,UR_EN]) */\n+\t{\n+\t\tcvmx_pcieepx_cfg030_t pcieepx_cfg030;\n+\n+\t\tpcieepx_cfg030.u32 = CVMX_PCIE_CFGX_READ(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port));\n+\t\tpcieepx_cfg030.s.mps = MPS_CN6XXX;\n+\t\tpcieepx_cfg030.s.mrrs = MRRS_CN6XXX;\n+\t\tpcieepx_cfg030.s.ro_en = 1; /* Enable relaxed ordering. */\n+\t\tpcieepx_cfg030.s.ns_en = 1; /* Enable no snoop. */\n+\t\tpcieepx_cfg030.s.ce_en = 1; /* Correctable error reporting enable. */\n+\t\tpcieepx_cfg030.s.nfe_en = 1; /* Non-fatal error reporting enable. */\n+\t\tpcieepx_cfg030.s.fe_en = 1; /* Fatal error reporting enable. */\n+\t\tpcieepx_cfg030.s.ur_en = 1; /* Unsupported request reporting enable. */\n+\t\tCVMX_PCIE_CFGX_WRITE(pcie_port, CVMX_PCIEEPX_CFG030(pcie_port), pcieepx_cfg030.u32);\n+\t}\n+\n+\t/* Max Payload Size (DPI_SLI_PRTX_CFG[MPS]) must match\n+\t * PCIE*_CFG030[MPS]\n+\t */\n+\t/* Max Read Request Size (DPI_SLI_PRTX_CFG[MRRS]) must not\n+\t * exceed PCIE*_CFG030[MRRS]\n+\t */\n+\tcvmx_dpi_sli_prtx_cfg_t prt_cfg;\n+\tcvmx_sli_s2m_portx_ctl_t sli_s2m_portx_ctl;\n+\n+\tprt_cfg.u64 = CVMX_READ_CSR(CVMX_DPI_SLI_PRTX_CFG(pcie_port));\n+\tprt_cfg.s.mps = MPS_CN6XXX;\n+\tprt_cfg.s.mrrs = MRRS_CN6XXX;\n+\t/* Max outstanding load request. */\n+\tprt_cfg.s.molr = 32;\n+\tCVMX_WRITE_CSR(CVMX_DPI_SLI_PRTX_CFG(pcie_port), prt_cfg.u64);\n+\n+\tsli_s2m_portx_ctl.u64 = CVMX_READ_CSR(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port));\n+\tif (!(OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX) ||\n+\t OCTEON_IS_MODEL(OCTEON_CNF75XX)))\n+\t\tsli_s2m_portx_ctl.cn61xx.mrrs = MRRS_CN6XXX;\n+\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_S2M_PORTX_CTL(pcie_port), sli_s2m_portx_ctl.u64);\n+\n+\t/* Setup Mem access SubDID 12 to access Host memory */\n+\tcvmx_sli_mem_access_subidx_t mem_access_subid;\n+\n+\tmem_access_subid.u64 = 0;\n+\tmem_access_subid.s.port = pcie_port; /* Port the request is sent to. */\n+\tmem_access_subid.s.nmerge = 0;\t /* Merging is allowed in this window. */\n+\tmem_access_subid.s.esr = 0;\t /* Endian-swap for Reads. */\n+\tmem_access_subid.s.esw = 0;\t /* Endian-swap for Writes. */\n+\tmem_access_subid.s.wtype = 0;\t /* \"No snoop\" and \"Relaxed ordering\" are not set */\n+\tmem_access_subid.s.rtype = 0;\t /* \"No snoop\" and \"Relaxed ordering\" are not set */\n+\t/* PCIe Address Bits <63:34>. */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN68XX))\n+\t\tmem_access_subid.cn68xx.ba = 0;\n+\telse\n+\t\tmem_access_subid.cn63xx.ba = 0;\n+\tCVMX_WRITE_CSR(CVMX_PEXP_SLI_MEM_ACCESS_SUBIDX(12 + pcie_port * 4), mem_access_subid.u64);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * Wait for posted PCIe read/writes to reach the other side of\n+ * the internal PCIe switch. This will insure that core\n+ * read/writes are posted before anything after this function\n+ * is called. This may be necessary when writing to memory that\n+ * will later be read using the DMA/PKT engines.\n+ *\n+ * @param pcie_port PCIe port to wait for\n+ */\n+void cvmx_pcie_wait_for_pending(int pcie_port)\n+{\n+\tcvmx_sli_data_out_cnt_t sli_data_out_cnt;\n+\tint a;\n+\tint b;\n+\tint c;\n+\n+\tsli_data_out_cnt.u64 = csr_rd(CVMX_PEXP_SLI_DATA_OUT_CNT);\n+\tif (pcie_port) {\n+\t\tif (!sli_data_out_cnt.s.p1_fcnt)\n+\t\t\treturn;\n+\t\ta = sli_data_out_cnt.s.p1_ucnt;\n+\t\tb = (a + sli_data_out_cnt.s.p1_fcnt - 1) & 0xffff;\n+\t} else {\n+\t\tif (!sli_data_out_cnt.s.p0_fcnt)\n+\t\t\treturn;\n+\t\ta = sli_data_out_cnt.s.p0_ucnt;\n+\t\tb = (a + sli_data_out_cnt.s.p0_fcnt - 1) & 0xffff;\n+\t}\n+\n+\twhile (1) {\n+\t\tsli_data_out_cnt.u64 = csr_rd(CVMX_PEXP_SLI_DATA_OUT_CNT);\n+\t\tc = (pcie_port) ? sli_data_out_cnt.s.p1_ucnt :\n+\t\t\tsli_data_out_cnt.s.p0_ucnt;\n+\t\tif (a <= b) {\n+\t\t\tif (c < a || c > b)\n+\t\t\t\treturn;\n+\t\t} else {\n+\t\t\tif (c > b && c < a)\n+\t\t\t\treturn;\n+\t\t}\n+\t}\n+}\n+\n+/**\n+ * Returns if a PCIe port is in host or target mode.\n+ *\n+ * @param pcie_port PCIe port number (PEM number)\n+ *\n+ * @return 0 if PCIe port is in target mode, !0 if in host mode.\n+ */\n+int cvmx_pcie_is_host_mode(int pcie_port)\n+{\n+\tint node = (pcie_port >> 4) & 0x3;\n+\tcvmx_mio_rst_ctlx_t mio_rst_ctl;\n+\n+\tpcie_port &= 0x3;\n+\tif (OCTEON_IS_MODEL(OCTEON_CN78XX) || OCTEON_IS_MODEL(OCTEON_CN73XX)) {\n+\t\tcvmx_pemx_strap_t strap;\n+\n+\t\tstrap.u64 = CVMX_READ_CSR(CVMX_PEMX_STRAP(pcie_port));\n+\t\treturn (strap.cn78xx.pimode == 3);\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN70XX)) {\n+\t\tcvmx_rst_ctlx_t rst_ctl;\n+\n+\t\trst_ctl.u64 = csr_rd(CVMX_RST_CTLX(pcie_port));\n+\t\treturn !!rst_ctl.s.host_mode;\n+\t}\n+\n+\tmio_rst_ctl.u64 = csr_rd(CVMX_MIO_RST_CTLX(pcie_port));\n+\tif (OCTEON_IS_MODEL(OCTEON_CN61XX) || OCTEON_IS_MODEL(OCTEON_CNF71XX))\n+\t\treturn mio_rst_ctl.s.prtmode != 0;\n+\telse\n+\t\treturn !!mio_rst_ctl.s.host_mode;\n+}\n", "prefixes": [ "v1", "41/50" ] }