Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1415018/?format=api
{ "id": 1415018, "url": "http://patchwork.ozlabs.org/api/patches/1415018/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20201211160612.1498780-40-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-40-sr@denx.de>", "list_archive_url": null, "date": "2020-12-11T16:06:01", "name": "[v1,39/50] mips: octeon: Add cvmx-helper-util.c", "commit_ref": "3b883dea28cf6e90d531d8dea417b311fd1be59b", "pull_url": null, "state": "accepted", "archived": false, "hash": "64f44c06323ba795bccb64484f6f26e2991bc5fe", "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-40-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/1415018/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1415018/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=nHwvhN3Q;\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 4Cswq71gXBz9sTL\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 12 Dec 2020 03:14:59 +1100 (AEDT)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 44499827E4;\n\tFri, 11 Dec 2020 17:09:29 +0100 (CET)", "by phobos.denx.de (Postfix, from userid 109)\n id EF744827BB; Fri, 11 Dec 2020 17:08:39 +0100 (CET)", "from mx2.mailbox.org (mx2.mailbox.org [80.241.60.215])\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 BEA1982752\n for <u-boot@lists.denx.de>; Fri, 11 Dec 2020 17:06:30 +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 7DD68A0E5E;\n Fri, 11 Dec 2020 17:06:30 +0100 (CET)", "from smtp1.mailbox.org ([80.241.60.240])\n by hefe.heinlein-support.de (hefe.heinlein-support.de [91.198.250.172])\n (amavisd-new, port 10030)\n with ESMTP id S9U_4r0DPhYL; 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=1607702969;\n\tbh=AD61tQEO8/DA2Rm77QMeEZa4uUynmY+licd1ozXwyRA=;\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=nHwvhN3Qr/WjlzODnMyObwJsxamCRAapqtYXZDk3BJR7hXrj7c1VsJhgpSXQxw6Z+\n\t FraRIsyRFdV8ntcrb5SmNLfV8+YJTIUginqCC7sM1iEnJx6is/5DHBPEmRgzdsss3Z\n\t bdG3m+xdsaRyF44m27r2VkPSmzHw//WZmtKBa++MOTgQfKXPkyhQ1rtd8w+CUEC57o\n\t AIyFdO1WhCDhHjvGJb3zx4tDphMhRB+ZiNrbuZEBVE7LFZnzUrS8phx4G4RooUjOG9\n\t +k3aMd2M0MtiLVtLHgpQFRgGus6Zyh7dUHhDJtPwp+/qeT7o+/h5lJJUMpwU3KWofA\n\t FWzX35LeyhjtA==", "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 39/50] mips: octeon: Add cvmx-helper-util.c", "Date": "Fri, 11 Dec 2020 17:06:01 +0100", "Message-Id": "<20201211160612.1498780-40-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": "-0.76 / 15.00 / 15.00", "X-Rspamd-Queue-Id": "72C801880", "X-Rspamd-UID": "36e69e", "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-helper-util.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-helper-util.c | 1225 ++++++++++++++++++++++\n 1 file changed, 1225 insertions(+)\n create mode 100644 arch/mips/mach-octeon/cvmx-helper-util.c", "diff": "diff --git a/arch/mips/mach-octeon/cvmx-helper-util.c b/arch/mips/mach-octeon/cvmx-helper-util.c\nnew file mode 100644\nindex 0000000000..4625b4591b\n--- /dev/null\n+++ b/arch/mips/mach-octeon/cvmx-helper-util.c\n@@ -0,0 +1,1225 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2020 Marvell International Ltd.\n+ *\n+ * Small helper utilities.\n+ */\n+\n+#include <log.h>\n+#include <time.h>\n+#include <linux/delay.h>\n+\n+#include <mach/cvmx-regs.h>\n+#include <mach/cvmx-csr-enums.h>\n+#include <mach/octeon-model.h>\n+#include <mach/octeon-feature.h>\n+#include <mach/cvmx-gmxx-defs.h>\n+#include <mach/cvmx-ipd-defs.h>\n+#include <mach/cvmx-pko-defs.h>\n+#include <mach/cvmx-ipd.h>\n+#include <mach/cvmx-hwpko.h>\n+#include <mach/cvmx-pki.h>\n+#include <mach/cvmx-pip.h>\n+#include <mach/cvmx-helper.h>\n+#include <mach/cvmx-helper-util.h>\n+#include <mach/cvmx-helper-pki.h>\n+\n+/**\n+ * @INTERNAL\n+ * These are the interface types needed to convert interface numbers to ipd\n+ * ports.\n+ *\n+ * @param GMII\n+ *\tThis type is used for sgmii, rgmii, xaui and rxaui interfaces.\n+ * @param ILK\n+ *\tThis type is used for ilk interfaces.\n+ * @param SRIO\n+ *\tThis type is used for serial-RapidIo interfaces.\n+ * @param NPI\n+ *\tThis type is used for npi interfaces.\n+ * @param LB\n+ *\tThis type is used for loopback interfaces.\n+ * @param INVALID_IF_TYPE\n+ *\tThis type indicates the interface hasn't been configured.\n+ */\n+enum port_map_if_type { INVALID_IF_TYPE = 0, GMII, ILK, SRIO, NPI, LB };\n+\n+/**\n+ * @INTERNAL\n+ * This structure is used to map interface numbers to ipd ports.\n+ *\n+ * @param type\n+ *\tInterface type\n+ * @param first_ipd_port\n+ *\tFirst IPD port number assigned to this interface.\n+ * @param last_ipd_port\n+ *\tLast IPD port number assigned to this interface.\n+ * @param ipd_port_adj\n+ *\tDifferent octeon chips require different ipd ports for the\n+ *\tsame interface port/mode configuration. This value is used\n+ *\tto account for that difference.\n+ */\n+struct ipd_port_map {\n+\tenum port_map_if_type type;\n+\tint first_ipd_port;\n+\tint last_ipd_port;\n+\tint ipd_port_adj;\n+};\n+\n+/**\n+ * @INTERNAL\n+ * Interface number to ipd port map for the octeon 68xx.\n+ */\n+static const struct ipd_port_map ipd_port_map_68xx[CVMX_HELPER_MAX_IFACE] = {\n+\t{ GMII, 0x800, 0x8ff, 0x40 }, /* Interface 0 */\n+\t{ GMII, 0x900, 0x9ff, 0x40 }, /* Interface 1 */\n+\t{ GMII, 0xa00, 0xaff, 0x40 }, /* Interface 2 */\n+\t{ GMII, 0xb00, 0xbff, 0x40 }, /* Interface 3 */\n+\t{ GMII, 0xc00, 0xcff, 0x40 }, /* Interface 4 */\n+\t{ ILK, 0x400, 0x4ff, 0x00 }, /* Interface 5 */\n+\t{ ILK, 0x500, 0x5ff, 0x00 }, /* Interface 6 */\n+\t{ NPI, 0x100, 0x120, 0x00 }, /* Interface 7 */\n+\t{ LB, 0x000, 0x008, 0x00 }, /* Interface 8 */\n+};\n+\n+/**\n+ * @INTERNAL\n+ * Interface number to ipd port map for the octeon 78xx.\n+ *\n+ * This mapping corresponds to WQE(CHAN) enumeration in\n+ * HRM Sections 11.15, PKI_CHAN_E, Section 11.6\n+ *\n+ */\n+static const struct ipd_port_map ipd_port_map_78xx[CVMX_HELPER_MAX_IFACE] = {\n+\t{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX0 */\n+\t{ GMII, 0x900, 0x93f, 0x00 }, /* Interface 1 -BGX1 */\n+\t{ GMII, 0xa00, 0xa3f, 0x00 }, /* Interface 2 -BGX2 */\n+\t{ GMII, 0xb00, 0xb3f, 0x00 }, /* Interface 3 - BGX3 */\n+\t{ GMII, 0xc00, 0xc3f, 0x00 }, /* Interface 4 - BGX4 */\n+\t{ GMII, 0xd00, 0xd3f, 0x00 }, /* Interface 5 - BGX5 */\n+\t{ ILK, 0x400, 0x4ff, 0x00 }, /* Interface 6 - ILK0 */\n+\t{ ILK, 0x500, 0x5ff, 0x00 }, /* Interface 7 - ILK1 */\n+\t{ NPI, 0x100, 0x13f, 0x00 }, /* Interface 8 - DPI */\n+\t{ LB, 0x000, 0x03f, 0x00 }, /* Interface 9 - LOOPBACK */\n+};\n+\n+/**\n+ * @INTERNAL\n+ * Interface number to ipd port map for the octeon 73xx.\n+ */\n+static const struct ipd_port_map ipd_port_map_73xx[CVMX_HELPER_MAX_IFACE] = {\n+\t{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX(0,0-3) */\n+\t{ GMII, 0x900, 0x93f, 0x00 }, /* Interface 1 -BGX(1,0-3) */\n+\t{ GMII, 0xa00, 0xa3f, 0x00 }, /* Interface 2 -BGX(2,0-3) */\n+\t{ NPI, 0x100, 0x17f, 0x00 }, /* Interface 3 - DPI */\n+\t{ LB, 0x000, 0x03f, 0x00 }, /* Interface 4 - LOOPBACK */\n+};\n+\n+/**\n+ * @INTERNAL\n+ * Interface number to ipd port map for the octeon 75xx.\n+ */\n+static const struct ipd_port_map ipd_port_map_75xx[CVMX_HELPER_MAX_IFACE] = {\n+\t{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX0 */\n+\t{ SRIO, 0x240, 0x241, 0x00 }, /* Interface 1 - SRIO 0 */\n+\t{ SRIO, 0x242, 0x243, 0x00 }, /* Interface 2 - SRIO 1 */\n+\t{ NPI, 0x100, 0x13f, 0x00 }, /* Interface 3 - DPI */\n+\t{ LB, 0x000, 0x03f, 0x00 }, /* Interface 4 - LOOPBACK */\n+};\n+\n+/**\n+ * Convert a interface mode into a human readable string\n+ *\n+ * @param mode Mode to convert\n+ *\n+ * @return String\n+ */\n+const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode)\n+{\n+\tswitch (mode) {\n+\tcase CVMX_HELPER_INTERFACE_MODE_DISABLED:\n+\t\treturn \"DISABLED\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_RGMII:\n+\t\treturn \"RGMII\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_GMII:\n+\t\treturn \"GMII\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_SPI:\n+\t\treturn \"SPI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_PCIE:\n+\t\treturn \"PCIE\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_XAUI:\n+\t\treturn \"XAUI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_RXAUI:\n+\t\treturn \"RXAUI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_SGMII:\n+\t\treturn \"SGMII\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_QSGMII:\n+\t\treturn \"QSGMII\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_PICMG:\n+\t\treturn \"PICMG\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_NPI:\n+\t\treturn \"NPI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_LOOP:\n+\t\treturn \"LOOP\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_SRIO:\n+\t\treturn \"SRIO\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_ILK:\n+\t\treturn \"ILK\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_AGL:\n+\t\treturn \"AGL\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_XLAUI:\n+\t\treturn \"XLAUI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_XFI:\n+\t\treturn \"XFI\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_40G_KR4:\n+\t\treturn \"40G_KR4\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_10G_KR:\n+\t\treturn \"10G_KR\";\n+\tcase CVMX_HELPER_INTERFACE_MODE_MIXED:\n+\t\treturn \"MIXED\";\n+\t}\n+\treturn \"UNKNOWN\";\n+}\n+\n+/**\n+ * Debug routine to dump the packet structure to the console\n+ *\n+ * @param work Work queue entry containing the packet to dump\n+ * @return\n+ */\n+int cvmx_helper_dump_packet(cvmx_wqe_t *work)\n+{\n+\tu64 count;\n+\tu64 remaining_bytes;\n+\tunion cvmx_buf_ptr buffer_ptr;\n+\tcvmx_buf_ptr_pki_t bptr;\n+\tcvmx_wqe_78xx_t *wqe = (void *)work;\n+\tu64 start_of_buffer;\n+\tu8 *data_address;\n+\tu8 *end_of_data;\n+\n+\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {\n+\t\tcvmx_pki_dump_wqe(wqe);\n+\t\tcvmx_wqe_pki_errata_20776(work);\n+\t} else {\n+\t\tdebug(\"WORD0 = %lx\\n\", (unsigned long)work->word0.u64);\n+\t\tdebug(\"WORD1 = %lx\\n\", (unsigned long)work->word1.u64);\n+\t\tdebug(\"WORD2 = %lx\\n\", (unsigned long)work->word2.u64);\n+\t\tdebug(\"Packet Length: %u\\n\", cvmx_wqe_get_len(work));\n+\t\tdebug(\" Input Port: %u\\n\", cvmx_wqe_get_port(work));\n+\t\tdebug(\" QoS: %u\\n\", cvmx_wqe_get_qos(work));\n+\t\tdebug(\" Buffers: %u\\n\", cvmx_wqe_get_bufs(work));\n+\t}\n+\n+\tif (cvmx_wqe_get_bufs(work) == 0) {\n+\t\tint wqe_pool;\n+\n+\t\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {\n+\t\t\tdebug(\"%s: ERROR: Unexpected bufs==0 in WQE\\n\", __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\t\twqe_pool = (int)cvmx_fpa_get_wqe_pool();\n+\t\tbuffer_ptr.u64 = 0;\n+\t\tbuffer_ptr.s.pool = wqe_pool;\n+\n+\t\tbuffer_ptr.s.size = 128;\n+\t\tbuffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data);\n+\t\tif (cvmx_likely(!work->word2.s.not_IP)) {\n+\t\t\tunion cvmx_pip_ip_offset pip_ip_offset;\n+\n+\t\t\tpip_ip_offset.u64 = csr_rd(CVMX_PIP_IP_OFFSET);\n+\t\t\tbuffer_ptr.s.addr +=\n+\t\t\t\t(pip_ip_offset.s.offset << 3) - work->word2.s.ip_offset;\n+\t\t\tbuffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * WARNING: This code assume that the packet\n+\t\t\t * is not RAW. If it was, we would use\n+\t\t\t * PIP_GBL_CFG[RAW_SHF] instead of\n+\t\t\t * PIP_GBL_CFG[NIP_SHF].\n+\t\t\t */\n+\t\t\tunion cvmx_pip_gbl_cfg pip_gbl_cfg;\n+\n+\t\t\tpip_gbl_cfg.u64 = csr_rd(CVMX_PIP_GBL_CFG);\n+\t\t\tbuffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf;\n+\t\t}\n+\t} else {\n+\t\tbuffer_ptr = work->packet_ptr;\n+\t}\n+\n+\tremaining_bytes = cvmx_wqe_get_len(work);\n+\n+\twhile (remaining_bytes) {\n+\t\t/* native cn78xx buffer format, unless legacy-translated */\n+\t\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) && !wqe->pki_wqe_translated) {\n+\t\t\tbptr.u64 = buffer_ptr.u64;\n+\t\t\t/* XXX- assumes cache-line aligned buffer */\n+\t\t\tstart_of_buffer = (bptr.addr >> 7) << 7;\n+\t\t\tdebug(\" Buffer Start:%llx\\n\", (unsigned long long)start_of_buffer);\n+\t\t\tdebug(\" Buffer Data: %llx\\n\", (unsigned long long)bptr.addr);\n+\t\t\tdebug(\" Buffer Size: %u\\n\", bptr.size);\n+\t\t\tdata_address = (uint8_t *)cvmx_phys_to_ptr(bptr.addr);\n+\t\t\tend_of_data = data_address + bptr.size;\n+\t\t} else {\n+\t\t\tstart_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7;\n+\t\t\tdebug(\" Buffer Start:%llx\\n\", (unsigned long long)start_of_buffer);\n+\t\t\tdebug(\" Buffer I : %u\\n\", buffer_ptr.s.i);\n+\t\t\tdebug(\" Buffer Back: %u\\n\", buffer_ptr.s.back);\n+\t\t\tdebug(\" Buffer Pool: %u\\n\", buffer_ptr.s.pool);\n+\t\t\tdebug(\" Buffer Data: %llx\\n\", (unsigned long long)buffer_ptr.s.addr);\n+\t\t\tdebug(\" Buffer Size: %u\\n\", buffer_ptr.s.size);\n+\t\t\tdata_address = (uint8_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr);\n+\t\t\tend_of_data = data_address + buffer_ptr.s.size;\n+\t\t}\n+\n+\t\tdebug(\"\\t\\t\");\n+\t\tcount = 0;\n+\t\twhile (data_address < end_of_data) {\n+\t\t\tif (remaining_bytes == 0)\n+\t\t\t\tbreak;\n+\n+\t\t\tremaining_bytes--;\n+\t\t\tdebug(\"%02x\", (unsigned int)*data_address);\n+\t\t\tdata_address++;\n+\t\t\tif (remaining_bytes && count == 7) {\n+\t\t\t\tdebug(\"\\n\\t\\t\");\n+\t\t\t\tcount = 0;\n+\t\t\t} else {\n+\t\t\t\tcount++;\n+\t\t\t}\n+\t\t}\n+\t\tdebug(\"\\n\");\n+\n+\t\tif (remaining_bytes) {\n+\t\t\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) &&\n+\t\t\t !wqe->pki_wqe_translated)\n+\t\t\t\tbuffer_ptr.u64 = *(uint64_t *)cvmx_phys_to_ptr(bptr.addr - 8);\n+\t\t\telse\n+\t\t\t\tbuffer_ptr.u64 =\n+\t\t\t\t\t*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * @INTERNAL\n+ *\n+ * Extract NO_WPTR mode from PIP/IPD register\n+ */\n+static int __cvmx_ipd_mode_no_wptr(void)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) {\n+\t\tcvmx_ipd_ctl_status_t ipd_ctl_status;\n+\n+\t\tipd_ctl_status.u64 = csr_rd(CVMX_IPD_CTL_STATUS);\n+\t\treturn ipd_ctl_status.s.no_wptr;\n+\t}\n+\treturn 0;\n+}\n+\n+static cvmx_buf_ptr_t __cvmx_packet_short_ptr[4];\n+static int8_t __cvmx_wqe_pool = -1;\n+\n+/**\n+ * @INTERNAL\n+ * Prepare packet pointer templace for dynamic short\n+ * packets.\n+ */\n+static void cvmx_packet_short_ptr_calculate(void)\n+{\n+\tunsigned int i, off;\n+\tunion cvmx_pip_gbl_cfg pip_gbl_cfg;\n+\tunion cvmx_pip_ip_offset pip_ip_offset;\n+\n+\t/* Fill in the common values for all cases */\n+\tfor (i = 0; i < 4; i++) {\n+\t\tif (__cvmx_ipd_mode_no_wptr())\n+\t\t\t/* packet pool, set to 0 in hardware */\n+\t\t\t__cvmx_wqe_pool = 0;\n+\t\telse\n+\t\t\t/* WQE pool as configured */\n+\t\t\t__cvmx_wqe_pool = csr_rd(CVMX_IPD_WQE_FPA_QUEUE) & 7;\n+\n+\t\t__cvmx_packet_short_ptr[i].s.pool = __cvmx_wqe_pool;\n+\t\t__cvmx_packet_short_ptr[i].s.size = cvmx_fpa_get_block_size(__cvmx_wqe_pool);\n+\t\t__cvmx_packet_short_ptr[i].s.size -= 32;\n+\t\t__cvmx_packet_short_ptr[i].s.addr = 32;\n+\t}\n+\n+\tpip_gbl_cfg.u64 = csr_rd(CVMX_PIP_GBL_CFG);\n+\tpip_ip_offset.u64 = csr_rd(CVMX_PIP_IP_OFFSET);\n+\n+\t/* RAW_FULL: index = 0 */\n+\ti = 0;\n+\toff = pip_gbl_cfg.s.raw_shf;\n+\t__cvmx_packet_short_ptr[i].s.addr += off;\n+\t__cvmx_packet_short_ptr[i].s.size -= off;\n+\t__cvmx_packet_short_ptr[i].s.back += off >> 7;\n+\n+\t/* NON-IP: index = 1 */\n+\ti = 1;\n+\toff = pip_gbl_cfg.s.nip_shf;\n+\t__cvmx_packet_short_ptr[i].s.addr += off;\n+\t__cvmx_packet_short_ptr[i].s.size -= off;\n+\t__cvmx_packet_short_ptr[i].s.back += off >> 7;\n+\n+\t/* IPv4: index = 2 */\n+\ti = 2;\n+\toff = (pip_ip_offset.s.offset << 3) + 4;\n+\t__cvmx_packet_short_ptr[i].s.addr += off;\n+\t__cvmx_packet_short_ptr[i].s.size -= off;\n+\t__cvmx_packet_short_ptr[i].s.back += off >> 7;\n+\n+\t/* IPv6: index = 3 */\n+\ti = 3;\n+\toff = (pip_ip_offset.s.offset << 3) + 0;\n+\t__cvmx_packet_short_ptr[i].s.addr += off;\n+\t__cvmx_packet_short_ptr[i].s.size -= off;\n+\t__cvmx_packet_short_ptr[i].s.back += off >> 7;\n+\n+\t/* For IPv4/IPv6: subtract work->word2.s.ip_offset\n+\t * to addr, if it is smaller than IP_OFFSET[OFFSET]*8\n+\t * which is stored in __cvmx_packet_short_ptr[3].s.addr\n+\t */\n+}\n+\n+/**\n+ * Extract packet data buffer pointer from work queue entry.\n+ *\n+ * Returns the legacy (Octeon1/Octeon2) buffer pointer structure\n+ * for the linked buffer list.\n+ * On CN78XX, the native buffer pointer structure is converted into\n+ * the legacy format.\n+ * The legacy buf_ptr is then stored in the WQE, and word0 reserved\n+ * field is set to indicate that the buffer pointers were translated.\n+ * If the packet data is only found inside the work queue entry,\n+ * a standard buffer pointer structure is created for it.\n+ */\n+cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {\n+\t\tcvmx_wqe_78xx_t *wqe = (void *)work;\n+\t\tcvmx_buf_ptr_t optr, lptr;\n+\t\tcvmx_buf_ptr_pki_t nptr;\n+\t\tunsigned int pool, bufs;\n+\t\tint node = cvmx_get_node_num();\n+\n+\t\t/* In case of repeated calls of this function */\n+\t\tif (wqe->pki_wqe_translated || wqe->word2.software) {\n+\t\t\toptr.u64 = wqe->packet_ptr.u64;\n+\t\t\treturn optr;\n+\t\t}\n+\n+\t\tbufs = wqe->word0.bufs;\n+\t\tpool = wqe->word0.aura;\n+\t\tnptr.u64 = wqe->packet_ptr.u64;\n+\n+\t\toptr.u64 = 0;\n+\t\toptr.s.pool = pool;\n+\t\toptr.s.addr = nptr.addr;\n+\t\tif (bufs == 1) {\n+\t\t\toptr.s.size = pki_dflt_pool[node].buffer_size -\n+\t\t\t\t pki_dflt_style[node].parm_cfg.first_skip - 8 -\n+\t\t\t\t wqe->word0.apad;\n+\t\t} else {\n+\t\t\toptr.s.size = nptr.size;\n+\t\t}\n+\n+\t\t/* Calculate the \"back\" offset */\n+\t\tif (!nptr.packet_outside_wqe) {\n+\t\t\toptr.s.back = (nptr.addr -\n+\t\t\t\t cvmx_ptr_to_phys(wqe)) >> 7;\n+\t\t} else {\n+\t\t\toptr.s.back =\n+\t\t\t\t(pki_dflt_style[node].parm_cfg.first_skip +\n+\t\t\t\t 8 + wqe->word0.apad) >> 7;\n+\t\t}\n+\t\tlptr = optr;\n+\n+\t\t/* Follow pointer and convert all linked pointers */\n+\t\twhile (bufs > 1) {\n+\t\t\tvoid *vptr;\n+\n+\t\t\tvptr = cvmx_phys_to_ptr(lptr.s.addr);\n+\n+\t\t\tmemcpy(&nptr, vptr - 8, 8);\n+\t\t\t/*\n+\t\t\t * Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped\n+\t\t\t * CN78XX pass 1.x has a bug where the packet pointer\n+\t\t\t * in each segment is written in the opposite\n+\t\t\t * endianness of the configured mode. Fix these here\n+\t\t\t */\n+\t\t\tif (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X))\n+\t\t\t\tnptr.u64 = __builtin_bswap64(nptr.u64);\n+\t\t\tlptr.u64 = 0;\n+\t\t\tlptr.s.pool = pool;\n+\t\t\tlptr.s.addr = nptr.addr;\n+\t\t\tlptr.s.size = nptr.size;\n+\t\t\tlptr.s.back = (pki_dflt_style[0].parm_cfg.later_skip + 8) >>\n+\t\t\t\t 7; /* TBD: not guaranteed !! */\n+\n+\t\t\tmemcpy(vptr - 8, &lptr, 8);\n+\t\t\tbufs--;\n+\t\t}\n+\t\t/* Store translated bufptr in WQE, and set indicator */\n+\t\twqe->pki_wqe_translated = 1;\n+\t\twqe->packet_ptr.u64 = optr.u64;\n+\t\treturn optr;\n+\n+\t} else {\n+\t\tunsigned int i;\n+\t\tunsigned int off = 0;\n+\t\tcvmx_buf_ptr_t bptr;\n+\n+\t\tif (cvmx_likely(work->word2.s.bufs > 0))\n+\t\t\treturn work->packet_ptr;\n+\n+\t\tif (cvmx_unlikely(work->word2.s.software))\n+\t\t\treturn work->packet_ptr;\n+\n+\t\t/* first packet, precalculate packet_ptr templaces */\n+\t\tif (cvmx_unlikely(__cvmx_packet_short_ptr[0].u64 == 0))\n+\t\t\tcvmx_packet_short_ptr_calculate();\n+\n+\t\t/* calculate templace index */\n+\t\ti = work->word2.s_cn38xx.not_IP | work->word2.s_cn38xx.rcv_error;\n+\t\ti = 2 ^ (i << 1);\n+\n+\t\t/* IPv4/IPv6: Adjust IP offset */\n+\t\tif (cvmx_likely(i & 2)) {\n+\t\t\ti |= work->word2.s.is_v6;\n+\t\t\toff = work->word2.s.ip_offset;\n+\t\t} else {\n+\t\t\t/* RAWFULL/RAWSCHED should be handled here */\n+\t\t\ti = 1; /* not-IP */\n+\t\t\toff = 0;\n+\t\t}\n+\n+\t\t/* Get the right templace */\n+\t\tbptr = __cvmx_packet_short_ptr[i];\n+\t\tbptr.s.addr -= off;\n+\t\tbptr.s.back = bptr.s.addr >> 7;\n+\n+\t\t/* Add actual WQE paddr to the templace offset */\n+\t\tbptr.s.addr += cvmx_ptr_to_phys(work);\n+\n+\t\t/* Adjust word2.bufs so that _free_data() handles it\n+\t\t * in the same way as PKO\n+\t\t */\n+\t\twork->word2.s.bufs = 1;\n+\n+\t\t/* Store the new buffer pointer back into WQE */\n+\t\twork->packet_ptr = bptr;\n+\n+\t\t/* Returned the synthetic buffer_pointer */\n+\t\treturn bptr;\n+\t}\n+}\n+\n+void cvmx_wqe_free(cvmx_wqe_t *work)\n+{\n+\tunsigned int bufs, ncl = 1;\n+\tu64 paddr, paddr1;\n+\n+\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {\n+\t\tcvmx_wqe_78xx_t *wqe = (void *)work;\n+\t\tcvmx_fpa3_gaura_t aura;\n+\t\tcvmx_buf_ptr_pki_t bptr;\n+\n+\t\tbufs = wqe->word0.bufs;\n+\n+\t\tif (!wqe->pki_wqe_translated && bufs != 0) {\n+\t\t\t/* Handle cn78xx native untralsated WQE */\n+\n+\t\t\tbptr = wqe->packet_ptr;\n+\n+\t\t\t/* Do nothing - first packet buffer shares WQE buffer */\n+\t\t\tif (!bptr.packet_outside_wqe)\n+\t\t\t\treturn;\n+\t\t} else if (cvmx_likely(bufs != 0)) {\n+\t\t\t/* Handle translated 78XX WQE */\n+\t\t\tpaddr = (work->packet_ptr.s.addr & (~0x7full)) -\n+\t\t\t\t(work->packet_ptr.s.back << 7);\n+\t\t\tpaddr1 = cvmx_ptr_to_phys(work);\n+\n+\t\t\t/* do not free WQE if contains first data buffer */\n+\t\t\tif (paddr == paddr1)\n+\t\t\t\treturn;\n+\t\t}\n+\n+\t\t/* WQE is separate from packet buffer, free it */\n+\t\taura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10, wqe->word0.aura & 0x3ff);\n+\n+\t\tcvmx_fpa3_free(work, aura, ncl);\n+\t} else {\n+\t\t/* handle legacy WQE */\n+\t\tbufs = work->word2.s_cn38xx.bufs;\n+\n+\t\tif (cvmx_likely(bufs != 0)) {\n+\t\t\t/* Check if the first data buffer is inside WQE */\n+\t\t\tpaddr = (work->packet_ptr.s.addr & (~0x7full)) -\n+\t\t\t\t(work->packet_ptr.s.back << 7);\n+\t\t\tpaddr1 = cvmx_ptr_to_phys(work);\n+\n+\t\t\t/* do not free WQE if contains first data buffer */\n+\t\t\tif (paddr == paddr1)\n+\t\t\t\treturn;\n+\t\t}\n+\n+\t\t/* precalculate packet_ptr, WQE pool number */\n+\t\tif (cvmx_unlikely(__cvmx_wqe_pool < 0))\n+\t\t\tcvmx_packet_short_ptr_calculate();\n+\t\tcvmx_fpa1_free(work, __cvmx_wqe_pool, ncl);\n+\t}\n+}\n+\n+/**\n+ * Free the packet buffers contained in a work queue entry.\n+ * The work queue entry is also freed if it contains packet data.\n+ * If however the packet starts outside the WQE, the WQE will\n+ * not be freed. The application should call cvmx_wqe_free()\n+ * to free the WQE buffer that contains no packet data.\n+ *\n+ * @param work Work queue entry with packet to free\n+ */\n+void cvmx_helper_free_packet_data(cvmx_wqe_t *work)\n+{\n+\tu64 number_buffers;\n+\tu64 start_of_buffer;\n+\tu64 next_buffer_ptr;\n+\tcvmx_fpa3_gaura_t aura;\n+\tunsigned int ncl;\n+\tcvmx_buf_ptr_t buffer_ptr;\n+\tcvmx_buf_ptr_pki_t bptr;\n+\tcvmx_wqe_78xx_t *wqe = (void *)work;\n+\tint o3_pki_wqe = 0;\n+\n+\tnumber_buffers = cvmx_wqe_get_bufs(work);\n+\n+\tbuffer_ptr.u64 = work->packet_ptr.u64;\n+\n+\t/* Zero-out WQE WORD3 so that the WQE is freed by cvmx_wqe_free() */\n+\twork->packet_ptr.u64 = 0;\n+\n+\tif (number_buffers == 0)\n+\t\treturn;\n+\n+\t/* Interpret PKI-style bufptr unless it has been translated */\n+\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) &&\n+\t !wqe->pki_wqe_translated) {\n+\t\to3_pki_wqe = 1;\n+\t\tcvmx_wqe_pki_errata_20776(work);\n+\t\taura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10,\n+\t\t\t\t\t wqe->word0.aura & 0x3ff);\n+\t} else {\n+\t\tstart_of_buffer = ((buffer_ptr.s.addr >> 7) -\n+\t\t\t\t buffer_ptr.s.back) << 7;\n+\t\tnext_buffer_ptr =\n+\t\t\t*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);\n+\t\t/*\n+\t\t * Since the number of buffers is not zero, we know this is not\n+\t\t * a dynamic short packet. We need to check if it is a packet\n+\t\t * received with IPD_CTL_STATUS[NO_WPTR]. If this is true,\n+\t\t * we need to free all buffers except for the first one.\n+\t\t * The caller doesn't expect their WQE pointer to be freed\n+\t\t */\n+\t\tif (cvmx_ptr_to_phys(work) == start_of_buffer) {\n+\t\t\tbuffer_ptr.u64 = next_buffer_ptr;\n+\t\t\tnumber_buffers--;\n+\t\t}\n+\t}\n+\twhile (number_buffers--) {\n+\t\tif (o3_pki_wqe) {\n+\t\t\tbptr.u64 = buffer_ptr.u64;\n+\n+\t\t\tncl = (bptr.size + CVMX_CACHE_LINE_SIZE - 1) /\n+\t\t\t\tCVMX_CACHE_LINE_SIZE;\n+\n+\t\t\t/* XXX- assumes the buffer is cache-line aligned */\n+\t\t\tstart_of_buffer = (bptr.addr >> 7) << 7;\n+\n+\t\t\t/*\n+\t\t\t * Read pointer to next buffer before we free the\n+\t\t\t * current buffer.\n+\t\t\t */\n+\t\t\tnext_buffer_ptr = *(uint64_t *)cvmx_phys_to_ptr(bptr.addr - 8);\n+\t\t\t/* FPA AURA comes from WQE, includes node */\n+\t\t\tcvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),\n+\t\t\t\t aura, ncl);\n+\t\t} else {\n+\t\t\tncl = (buffer_ptr.s.size + CVMX_CACHE_LINE_SIZE - 1) /\n+\t\t\t\t CVMX_CACHE_LINE_SIZE +\n+\t\t\t buffer_ptr.s.back;\n+\t\t\t/*\n+\t\t\t * Calculate buffer start using \"back\" offset,\n+\t\t\t * Remember the back pointer is in cache lines,\n+\t\t\t * not 64bit words\n+\t\t\t */\n+\t\t\tstart_of_buffer = ((buffer_ptr.s.addr >> 7) -\n+\t\t\t\t\t buffer_ptr.s.back) << 7;\n+\t\t\t/*\n+\t\t\t * Read pointer to next buffer before we free\n+\t\t\t * the current buffer.\n+\t\t\t */\n+\t\t\tnext_buffer_ptr =\n+\t\t\t\t*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);\n+\t\t\t/* FPA pool comes from buf_ptr itself */\n+\t\t\tif (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {\n+\t\t\t\taura = cvmx_fpa1_pool_to_fpa3_aura(buffer_ptr.s.pool);\n+\t\t\t\tcvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),\n+\t\t\t\t\t aura, ncl);\n+\t\t\t} else {\n+\t\t\t\tcvmx_fpa1_free(cvmx_phys_to_ptr(start_of_buffer),\n+\t\t\t\t\t buffer_ptr.s.pool, ncl);\n+\t\t\t}\n+\t\t}\n+\t\tbuffer_ptr.u64 = next_buffer_ptr;\n+\t}\n+}\n+\n+void cvmx_helper_setup_legacy_red(int pass_thresh, int drop_thresh)\n+{\n+\tunsigned int node = cvmx_get_node_num();\n+\tint aura, bpid;\n+\tint buf_cnt;\n+\tbool ena_red = 0, ena_drop = 0, ena_bp = 0;\n+\n+#define FPA_RED_AVG_DLY 1\n+#define FPA_RED_LVL_DLY 3\n+#define FPA_QOS_AVRG\t0\n+\t/* Trying to make it backward compatible with older chips */\n+\n+\t/* Setting up avg_dly and prb_dly, enable bits */\n+\tif (octeon_has_feature(OCTEON_FEATURE_FPA3)) {\n+\t\tcvmx_fpa3_config_red_params(node, FPA_QOS_AVRG,\n+\t\t\t\t\t FPA_RED_LVL_DLY, FPA_RED_AVG_DLY);\n+\t}\n+\n+\t/* Disable backpressure on queued buffers which is aura in 78xx*/\n+\t/*\n+\t * Assumption is that all packets from all interface and ports goes\n+\t * in same poolx/aurax for backward compatibility\n+\t */\n+\taura = cvmx_fpa_get_packet_pool();\n+\tbuf_cnt = cvmx_fpa_get_packet_pool_buffer_count();\n+\tpass_thresh = buf_cnt - pass_thresh;\n+\tdrop_thresh = buf_cnt - drop_thresh;\n+\t/* Map aura to bpid 0*/\n+\tbpid = 0;\n+\tcvmx_pki_write_aura_bpid(node, aura, bpid);\n+\t/* Don't enable back pressure */\n+\tena_bp = 0;\n+\t/* enable RED */\n+\tena_red = 1;\n+\t/*\n+\t * This will enable RED on all interfaces since\n+\t * they all have packet buffer coming from same aura\n+\t */\n+\tcvmx_helper_setup_aura_qos(node, aura, ena_red, ena_drop, pass_thresh,\n+\t\t\t\t drop_thresh, ena_bp, 0);\n+}\n+\n+/**\n+ * Setup Random Early Drop to automatically begin dropping packets.\n+ *\n+ * @param pass_thresh\n+ * Packets will begin slowly dropping when there are less than\n+ * this many packet buffers free in FPA 0.\n+ * @param drop_thresh\n+ * All incoming packets will be dropped when there are less\n+ * than this many free packet buffers in FPA 0.\n+ * @return Zero on success. Negative on failure\n+ */\n+int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_PKI))\n+\t\tcvmx_helper_setup_legacy_red(pass_thresh, drop_thresh);\n+\telse\n+\t\tcvmx_ipd_setup_red(pass_thresh, drop_thresh);\n+\treturn 0;\n+}\n+\n+/**\n+ * @INTERNAL\n+ * Setup the common GMX settings that determine the number of\n+ * ports. These setting apply to almost all configurations of all\n+ * chips.\n+ *\n+ * @param xiface Interface to configure\n+ * @param num_ports Number of ports on the interface\n+ *\n+ * @return Zero on success, negative on failure\n+ */\n+int __cvmx_helper_setup_gmx(int xiface, int num_ports)\n+{\n+\tunion cvmx_gmxx_tx_prts gmx_tx_prts;\n+\tunion cvmx_gmxx_rx_prts gmx_rx_prts;\n+\tunion cvmx_pko_reg_gmx_port_mode pko_mode;\n+\tunion cvmx_gmxx_txx_thresh gmx_tx_thresh;\n+\tstruct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);\n+\tint index;\n+\n+\t/*\n+\t * The common BGX settings are already done in the appropriate\n+\t * enable functions, nothing to do here.\n+\t */\n+\tif (octeon_has_feature(OCTEON_FEATURE_BGX))\n+\t\treturn 0;\n+\n+\t/* Tell GMX the number of TX ports on this interface */\n+\tgmx_tx_prts.u64 = csr_rd(CVMX_GMXX_TX_PRTS(xi.interface));\n+\tgmx_tx_prts.s.prts = num_ports;\n+\tcsr_wr(CVMX_GMXX_TX_PRTS(xi.interface), gmx_tx_prts.u64);\n+\n+\t/*\n+\t * Tell GMX the number of RX ports on this interface. This only applies\n+\t * to *GMII and XAUI ports.\n+\t */\n+\tswitch (cvmx_helper_interface_get_mode(xiface)) {\n+\tcase CVMX_HELPER_INTERFACE_MODE_RGMII:\n+\tcase CVMX_HELPER_INTERFACE_MODE_SGMII:\n+\tcase CVMX_HELPER_INTERFACE_MODE_QSGMII:\n+\tcase CVMX_HELPER_INTERFACE_MODE_GMII:\n+\tcase CVMX_HELPER_INTERFACE_MODE_XAUI:\n+\tcase CVMX_HELPER_INTERFACE_MODE_RXAUI:\n+\t\tif (num_ports > 4) {\n+\t\t\tdebug(\"%s: Illegal num_ports\\n\", __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tgmx_rx_prts.u64 = csr_rd(CVMX_GMXX_RX_PRTS(xi.interface));\n+\t\tgmx_rx_prts.s.prts = num_ports;\n+\t\tcsr_wr(CVMX_GMXX_RX_PRTS(xi.interface), gmx_rx_prts.u64);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, 50XX,\n+\t * and 68XX.\n+\t */\n+\tif (!OCTEON_IS_MODEL(OCTEON_CN68XX)) {\n+\t\t/* Tell PKO the number of ports on this interface */\n+\t\tpko_mode.u64 = csr_rd(CVMX_PKO_REG_GMX_PORT_MODE);\n+\t\tif (xi.interface == 0) {\n+\t\t\tif (num_ports == 1)\n+\t\t\t\tpko_mode.s.mode0 = 4;\n+\t\t\telse if (num_ports == 2)\n+\t\t\t\tpko_mode.s.mode0 = 3;\n+\t\t\telse if (num_ports <= 4)\n+\t\t\t\tpko_mode.s.mode0 = 2;\n+\t\t\telse if (num_ports <= 8)\n+\t\t\t\tpko_mode.s.mode0 = 1;\n+\t\t\telse\n+\t\t\t\tpko_mode.s.mode0 = 0;\n+\t\t} else {\n+\t\t\tif (num_ports == 1)\n+\t\t\t\tpko_mode.s.mode1 = 4;\n+\t\t\telse if (num_ports == 2)\n+\t\t\t\tpko_mode.s.mode1 = 3;\n+\t\t\telse if (num_ports <= 4)\n+\t\t\t\tpko_mode.s.mode1 = 2;\n+\t\t\telse if (num_ports <= 8)\n+\t\t\t\tpko_mode.s.mode1 = 1;\n+\t\t\telse\n+\t\t\t\tpko_mode.s.mode1 = 0;\n+\t\t}\n+\t\tcsr_wr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);\n+\t}\n+\n+\t/*\n+\t * Set GMX to buffer as much data as possible before starting\n+\t * transmit. This reduces the chances that we have a TX under run\n+\t * due to memory contention. Any packet that fits entirely in the\n+\t * GMX FIFO can never have an under run regardless of memory load.\n+\t */\n+\tgmx_tx_thresh.u64 = csr_rd(CVMX_GMXX_TXX_THRESH(0, xi.interface));\n+\t/* ccn - common cnt numberator */\n+\tint ccn = 0x100;\n+\n+\t/* Choose the max value for the number of ports */\n+\tif (num_ports <= 1)\n+\t\tgmx_tx_thresh.s.cnt = ccn / 1;\n+\telse if (num_ports == 2)\n+\t\tgmx_tx_thresh.s.cnt = ccn / 2;\n+\telse\n+\t\tgmx_tx_thresh.s.cnt = ccn / 4;\n+\n+\t/*\n+\t * SPI and XAUI can have lots of ports but the GMX hardware\n+\t * only ever has a max of 4\n+\t */\n+\tif (num_ports > 4)\n+\t\tnum_ports = 4;\n+\tfor (index = 0; index < num_ports; index++)\n+\t\tcsr_wr(CVMX_GMXX_TXX_THRESH(index, xi.interface), gmx_tx_thresh.u64);\n+\n+\t/*\n+\t * For o68, we need to setup the pipes\n+\t */\n+\tif (OCTEON_IS_MODEL(OCTEON_CN68XX) && xi.interface < CVMX_HELPER_MAX_GMX) {\n+\t\tunion cvmx_gmxx_txx_pipe config;\n+\n+\t\tfor (index = 0; index < num_ports; index++) {\n+\t\t\tconfig.u64 = 0;\n+\n+\t\t\tif (__cvmx_helper_cfg_pko_port_base(xiface, index) >= 0) {\n+\t\t\t\tconfig.u64 = csr_rd(CVMX_GMXX_TXX_PIPE(index,\n+\t\t\t\t\t\t\t\t xi.interface));\n+\t\t\t\tconfig.s.nump = __cvmx_helper_cfg_pko_port_num(xiface,\n+\t\t\t\t\t\t\t\t\t index);\n+\t\t\t\tconfig.s.base = __cvmx_helper_cfg_pko_port_base(xiface,\n+\t\t\t\t\t\t\t\t\t\tindex);\n+\t\t\t\tcsr_wr(CVMX_GMXX_TXX_PIPE(index, xi.interface),\n+\t\t\t\t config.u64);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int cvmx_helper_get_pko_port(int interface, int port)\n+{\n+\treturn cvmx_pko_get_base_pko_port(interface, port);\n+}\n+\n+int cvmx_helper_get_ipd_port(int xiface, int index)\n+{\n+\tstruct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);\n+\n+\tif (octeon_has_feature(OCTEON_FEATURE_PKND)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint ipd_port;\n+\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN68XX)) {\n+\t\t\tport_map = ipd_port_map_68xx;\n+\t\t\tipd_port = 0;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {\n+\t\t\tport_map = ipd_port_map_78xx;\n+\t\t\tipd_port = cvmx_helper_node_to_ipd_port(xi.node, 0);\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {\n+\t\t\tport_map = ipd_port_map_73xx;\n+\t\t\tipd_port = 0;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {\n+\t\t\tport_map = ipd_port_map_75xx;\n+\t\t\tipd_port = 0;\n+\t\t} else {\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tipd_port += port_map[xi.interface].first_ipd_port;\n+\t\tif (port_map[xi.interface].type == GMII) {\n+\t\t\tcvmx_helper_interface_mode_t mode;\n+\n+\t\t\tmode = cvmx_helper_interface_get_mode(xiface);\n+\t\t\tif (mode == CVMX_HELPER_INTERFACE_MODE_XAUI ||\n+\t\t\t (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI &&\n+\t\t\t OCTEON_IS_MODEL(OCTEON_CN68XX))) {\n+\t\t\t\tipd_port += port_map[xi.interface].ipd_port_adj;\n+\t\t\t\treturn ipd_port;\n+\t\t\t} else {\n+\t\t\t\treturn ipd_port + (index * 16);\n+\t\t\t}\n+\t\t} else if (port_map[xi.interface].type == ILK) {\n+\t\t\treturn ipd_port + index;\n+\t\t} else if (port_map[xi.interface].type == NPI) {\n+\t\t\treturn ipd_port + index;\n+\t\t} else if (port_map[xi.interface].type == SRIO) {\n+\t\t\treturn ipd_port + index;\n+\t\t} else if (port_map[xi.interface].type == LB) {\n+\t\t\treturn ipd_port + index;\n+\t\t}\n+\n+\t\tdebug(\"ERROR: %s: interface %u:%u bad mode\\n\",\n+\t\t __func__, xi.node, xi.interface);\n+\t\treturn -1;\n+\t} else if (cvmx_helper_interface_get_mode(xiface) ==\n+\t\t CVMX_HELPER_INTERFACE_MODE_AGL) {\n+\t\treturn 24;\n+\t}\n+\n+\tswitch (xi.interface) {\n+\tcase 0:\n+\t\treturn index;\n+\tcase 1:\n+\t\treturn index + 16;\n+\tcase 2:\n+\t\treturn index + 32;\n+\tcase 3:\n+\t\treturn index + 36;\n+\tcase 4:\n+\t\treturn index + 40;\n+\tcase 5:\n+\t\treturn index + 42;\n+\tcase 6:\n+\t\treturn index + 44;\n+\tcase 7:\n+\t\treturn index + 46;\n+\t}\n+\treturn -1;\n+}\n+\n+int cvmx_helper_get_pknd(int xiface, int index)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_PKND))\n+\t\treturn __cvmx_helper_cfg_pknd(xiface, index);\n+\n+\treturn CVMX_INVALID_PKND;\n+}\n+\n+int cvmx_helper_get_bpid(int interface, int port)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_PKND))\n+\t\treturn __cvmx_helper_cfg_bpid(interface, port);\n+\n+\treturn CVMX_INVALID_BPID;\n+}\n+\n+/**\n+ * Display interface statistics.\n+ *\n+ * @param port IPD/PKO port number\n+ *\n+ * @return none\n+ */\n+void cvmx_helper_show_stats(int port)\n+{\n+\tcvmx_pip_port_status_t status;\n+\tcvmx_pko_port_status_t pko_status;\n+\n+\t/* ILK stats */\n+\tif (octeon_has_feature(OCTEON_FEATURE_ILK))\n+\t\t__cvmx_helper_ilk_show_stats();\n+\n+\t/* PIP stats */\n+\tcvmx_pip_get_port_stats(port, 0, &status);\n+\tdebug(\"port %d: the number of packets - ipd: %d\\n\", port,\n+\t (int)status.packets);\n+\n+\t/* PKO stats */\n+\tcvmx_pko_get_port_status(port, 0, &pko_status);\n+\tdebug(\"port %d: the number of packets - pko: %d\\n\", port,\n+\t (int)pko_status.packets);\n+\n+\t/* TODO: other stats */\n+}\n+\n+/**\n+ * Returns the interface number for an IPD/PKO port number.\n+ *\n+ * @param ipd_port IPD/PKO port number\n+ *\n+ * @return Interface number\n+ */\n+int cvmx_helper_get_interface_num(int ipd_port)\n+{\n+\tif (OCTEON_IS_MODEL(OCTEON_CN68XX)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint i;\n+\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\tport_map = ipd_port_map_68xx;\n+\t\tfor (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {\n+\t\t\tif (xp.port >= port_map[i].first_ipd_port &&\n+\t\t\t xp.port <= port_map[i].last_ipd_port)\n+\t\t\t\treturn i;\n+\t\t}\n+\t\treturn -1;\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint i;\n+\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\tport_map = ipd_port_map_78xx;\n+\t\tfor (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {\n+\t\t\tif (xp.port >= port_map[i].first_ipd_port &&\n+\t\t\t xp.port <= port_map[i].last_ipd_port)\n+\t\t\t\treturn cvmx_helper_node_interface_to_xiface(xp.node, i);\n+\t\t}\n+\t\treturn -1;\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint i;\n+\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\tport_map = ipd_port_map_73xx;\n+\t\tfor (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {\n+\t\t\tif (xp.port >= port_map[i].first_ipd_port &&\n+\t\t\t xp.port <= port_map[i].last_ipd_port)\n+\t\t\t\treturn i;\n+\t\t}\n+\t\treturn -1;\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint i;\n+\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\tport_map = ipd_port_map_75xx;\n+\t\tfor (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {\n+\t\t\tif (xp.port >= port_map[i].first_ipd_port &&\n+\t\t\t xp.port <= port_map[i].last_ipd_port)\n+\t\t\t\treturn i;\n+\t\t}\n+\t\treturn -1;\n+\t} else if (OCTEON_IS_MODEL(OCTEON_CN70XX) && ipd_port == 24) {\n+\t\treturn 4;\n+\t}\n+\n+\tif (ipd_port < 16)\n+\t\treturn 0;\n+\telse if (ipd_port < 32)\n+\t\treturn 1;\n+\telse if (ipd_port < 36)\n+\t\treturn 2;\n+\telse if (ipd_port < 40)\n+\t\treturn 3;\n+\telse if (ipd_port < 42)\n+\t\treturn 4;\n+\telse if (ipd_port < 44)\n+\t\treturn 5;\n+\telse if (ipd_port < 46)\n+\t\treturn 6;\n+\telse if (ipd_port < 48)\n+\t\treturn 7;\n+\n+\tdebug(\"%s: Illegal IPD port number %d\\n\", __func__, ipd_port);\n+\treturn -1;\n+}\n+\n+/**\n+ * Returns the interface index number for an IPD/PKO port\n+ * number.\n+ *\n+ * @param ipd_port IPD/PKO port number\n+ *\n+ * @return Interface index number\n+ */\n+int cvmx_helper_get_interface_index_num(int ipd_port)\n+{\n+\tif (octeon_has_feature(OCTEON_FEATURE_PKND)) {\n+\t\tconst struct ipd_port_map *port_map;\n+\t\tint port;\n+\t\tenum port_map_if_type type = INVALID_IF_TYPE;\n+\t\tint i;\n+\t\tint num_interfaces;\n+\n+\t\tif (OCTEON_IS_MODEL(OCTEON_CN68XX)) {\n+\t\t\tport_map = ipd_port_map_68xx;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {\n+\t\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\t\tport_map = ipd_port_map_78xx;\n+\t\t\tipd_port = xp.port;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {\n+\t\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\t\tport_map = ipd_port_map_73xx;\n+\t\t\tipd_port = xp.port;\n+\t\t} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {\n+\t\t\tstruct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);\n+\n+\t\t\tport_map = ipd_port_map_75xx;\n+\t\t\tipd_port = xp.port;\n+\t\t} else {\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tnum_interfaces = cvmx_helper_get_number_of_interfaces();\n+\n+\t\t/* Get the interface type of the ipd port */\n+\t\tfor (i = 0; i < num_interfaces; i++) {\n+\t\t\tif (ipd_port >= port_map[i].first_ipd_port &&\n+\t\t\t ipd_port <= port_map[i].last_ipd_port) {\n+\t\t\t\ttype = port_map[i].type;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Convert the ipd port to the interface port */\n+\t\tswitch (type) {\n+\t\t/* Ethernet interfaces have a channel in lower 4 bits\n+\t\t * that is does not discriminate traffic, and is ignored.\n+\t\t */\n+\t\tcase GMII:\n+\t\t\tport = ipd_port - port_map[i].first_ipd_port;\n+\n+\t\t\t/* CN68XX adds 0x40 to IPD_PORT when in XAUI/RXAUI\n+\t\t\t * mode of operation, adjust for that case\n+\t\t\t */\n+\t\t\tif (port >= port_map[i].ipd_port_adj)\n+\t\t\t\tport -= port_map[i].ipd_port_adj;\n+\n+\t\t\tport >>= 4;\n+\t\t\treturn port;\n+\n+\t\t/*\n+\t\t * These interfaces do not have physical ports,\n+\t\t * but have logical channels instead that separate\n+\t\t * traffic into logical streams\n+\t\t */\n+\t\tcase ILK:\n+\t\tcase SRIO:\n+\t\tcase NPI:\n+\t\tcase LB:\n+\t\t\tport = ipd_port - port_map[i].first_ipd_port;\n+\t\t\treturn port;\n+\n+\t\tdefault:\n+\t\t\tprintf(\"ERROR: %s: Illegal IPD port number %#x\\n\",\n+\t\t\t __func__, ipd_port);\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\tif (OCTEON_IS_MODEL(OCTEON_CN70XX))\n+\t\treturn ipd_port & 3;\n+\tif (ipd_port < 32)\n+\t\treturn ipd_port & 15;\n+\telse if (ipd_port < 40)\n+\t\treturn ipd_port & 3;\n+\telse if (ipd_port < 48)\n+\t\treturn ipd_port & 1;\n+\n+\tdebug(\"%s: Illegal IPD port number\\n\", __func__);\n+\n+\treturn -1;\n+}\n+\n+/**\n+ * Prints out a buffer with the address, hex bytes, and ASCII\n+ *\n+ * @param\taddr\tStart address to print on the left\n+ * @param[in]\tbuffer\tarray of bytes to print\n+ * @param\tcount\tNumber of bytes to print\n+ */\n+void cvmx_print_buffer_u8(unsigned int addr, const uint8_t *buffer,\n+\t\t\t size_t count)\n+{\n+\tuint i;\n+\n+\twhile (count) {\n+\t\tunsigned int linelen = count < 16 ? count : 16;\n+\n+\t\tdebug(\"%08x:\", addr);\n+\n+\t\tfor (i = 0; i < linelen; i++)\n+\t\t\tdebug(\" %0*x\", 2, buffer[i]);\n+\n+\t\twhile (i++ < 17)\n+\t\t\tdebug(\" \");\n+\n+\t\tfor (i = 0; i < linelen; i++) {\n+\t\t\tif (buffer[i] >= 0x20 && buffer[i] < 0x7f)\n+\t\t\t\tdebug(\"%c\", buffer[i]);\n+\t\t\telse\n+\t\t\t\tdebug(\".\");\n+\t\t}\n+\t\tdebug(\"\\n\");\n+\t\taddr += linelen;\n+\t\tbuffer += linelen;\n+\t\tcount -= linelen;\n+\t}\n+}\n", "prefixes": [ "v1", "39/50" ] }