Date: Fri, 31 Mar 2017 18:04:35 +0000 (UTC) From: Zbigniew Bodek <zbb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r316336 - head/sys/dev/vnic Message-ID: <201703311804.v2VI4ZTF078937@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: zbb Date: Fri Mar 31 18:04:34 2017 New Revision: 316336 URL: https://svnweb.freebsd.org/changeset/base/316336 Log: Rework BGX detection to support both new and old firmware Improve existing BGX detection and adjust it to support both new and older ThunderX firmwares. Match BGX FDT nodes by name and reg. Match PHY instances by qlm-mode and name. Tested on Firmware Version: 2016-09-30 09:12:11 Obtained from: Semihalf Differential Revision: https://reviews.freebsd.org/D9863 Modified: head/sys/dev/vnic/thunder_bgx_fdt.c Modified: head/sys/dev/vnic/thunder_bgx_fdt.c ============================================================================== --- head/sys/dev/vnic/thunder_bgx_fdt.c Fri Mar 31 15:46:47 2017 (r316335) +++ head/sys/dev/vnic/thunder_bgx_fdt.c Fri Mar 31 18:04:34 2017 (r316336) @@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$"); #define BGX_NODE_NAME "bgx" #define BGX_MAXID 9 +/* BGX func. 0, i.e.: reg = <0x8000 0 0 0 0>; DEVFN = 0x80 */ +#define BGX_DEVFN_0 0x80 #define FDT_NAME_MAXLEN 31 @@ -82,57 +84,136 @@ bgx_fdt_get_macaddr(phandle_t phy, uint8 } static boolean_t -bgx_fdt_phy_mode_match(struct bgx *bgx, char *qlm_mode, size_t size) +bgx_fdt_phy_mode_match(struct bgx *bgx, char *qlm_mode, ssize_t size) { - - size -= CONN_TYPE_OFFSET; + const char *type; + ssize_t sz; + ssize_t offset; switch (bgx->qlm_mode) { case QLM_MODE_SGMII: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "sgmii", size) == 0) - return (TRUE); + type = "sgmii"; + sz = sizeof("sgmii") - 1; + offset = size - sz; break; case QLM_MODE_XAUI_1X4: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xaui", size) == 0) - return (TRUE); - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "dxaui", size) == 0) + type = "xaui"; + sz = sizeof("xaui") - 1; + offset = size - sz; + if (offset < 0) + return (FALSE); + if (strncmp(&qlm_mode[offset], type, sz) == 0) return (TRUE); + type = "dxaui"; + sz = sizeof("dxaui") - 1; + offset = size - sz; break; case QLM_MODE_RXAUI_2X2: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "raui", size) == 0) - return (TRUE); + type = "raui"; + sz = sizeof("raui") - 1; + offset = size - sz; break; case QLM_MODE_XFI_4X1: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xfi", size) == 0) - return (TRUE); + type = "xfi"; + sz = sizeof("xfi") - 1; + offset = size - sz; break; case QLM_MODE_XLAUI_1X4: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xlaui", size) == 0) - return (TRUE); + type = "xlaui"; + sz = sizeof("xlaui") - 1; + offset = size - sz; break; case QLM_MODE_10G_KR_4X1: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xfi-10g-kr", size) == 0) - return (TRUE); + type = "xfi-10g-kr"; + sz = sizeof("xfi-10g-kr") - 1; + offset = size - sz; break; case QLM_MODE_40G_KR4_1X4: - if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xlaui-40g-kr", size) == 0) + type = "xlaui-40g-kr"; + sz = sizeof("xlaui-40g-kr") - 1; + offset = size - sz; + break; + default: + return (FALSE); + } + + if (offset < 0) + return (FALSE); + + if (strncmp(&qlm_mode[offset], type, sz) == 0) + return (TRUE); + + return (FALSE); +} + +static boolean_t +bgx_fdt_phy_name_match(struct bgx *bgx, char *phy_name, ssize_t size) +{ + const char *type; + ssize_t sz; + + switch (bgx->qlm_mode) { + case QLM_MODE_SGMII: + type = "sgmii"; + sz = sizeof("sgmii") - 1; + break; + case QLM_MODE_XAUI_1X4: + type = "xaui"; + sz = sizeof("xaui") - 1; + if (sz < size) + return (FALSE); + if (strncmp(phy_name, type, sz) == 0) return (TRUE); + type = "dxaui"; + sz = sizeof("dxaui") - 1; + break; + case QLM_MODE_RXAUI_2X2: + type = "raui"; + sz = sizeof("raui") - 1; + break; + case QLM_MODE_XFI_4X1: + type = "xfi"; + sz = sizeof("xfi") - 1; + break; + case QLM_MODE_XLAUI_1X4: + type = "xlaui"; + sz = sizeof("xlaui") - 1; + break; + case QLM_MODE_10G_KR_4X1: + type = "xfi-10g-kr"; + sz = sizeof("xfi-10g-kr") - 1; + break; + case QLM_MODE_40G_KR4_1X4: + type = "xlaui-40g-kr"; + sz = sizeof("xlaui-40g-kr") - 1; break; default: return (FALSE); } + if (sz > size) + return (FALSE); + if (strncmp(phy_name, type, sz) == 0) + return (TRUE); + return (FALSE); } static phandle_t -bgx_fdt_traverse_nodes(phandle_t start, char *name, size_t len) +bgx_fdt_traverse_nodes(uint8_t unit, phandle_t start, char *name, + size_t len) { phandle_t node, ret; + uint32_t *reg; size_t buf_size; + ssize_t proplen; char *node_name; int err; + /* + * Traverse all subordinate nodes of 'start' to find BGX instance. + * This supports both old (by name) and new (by reg) methods. + */ buf_size = sizeof(*node_name) * FDT_NAME_MAXLEN; if (len > buf_size) { /* @@ -148,17 +229,49 @@ bgx_fdt_traverse_nodes(phandle_t start, memset(node_name, 0, buf_size); /* Recurse to children */ if (OF_child(node) != 0) { - ret = bgx_fdt_traverse_nodes(node, name, len); + ret = bgx_fdt_traverse_nodes(unit, node, name, len); if (ret != 0) { free(node_name, M_BGX); return (ret); } } - err = OF_getprop(node, "name", node_name, FDT_NAME_MAXLEN); - if ((err > 0) && (strncmp(node_name, name, len) == 0)) { + /* + * Old way - by name + */ + proplen = OF_getproplen(node, "name"); + if ((proplen <= 0) || (proplen < len)) + continue; + + err = OF_getprop(node, "name", node_name, proplen); + if (err <= 0) + continue; + + if (strncmp(node_name, name, len) == 0) { free(node_name, M_BGX); return (node); } + /* + * New way - by reg + */ + /* Check if even BGX */ + if (strncmp(node_name, + BGX_NODE_NAME, sizeof(BGX_NODE_NAME) - 1) != 0) + continue; + /* Get reg */ + err = OF_getencprop_alloc(node, "reg", sizeof(*reg), + (void **)®); + if (err == -1) { + free(reg, M_OFWPROP); + continue; + } + + /* Match BGX device function */ + if ((BGX_DEVFN_0 + unit) == (reg[0] >> 8)) { + free(reg, M_OFWPROP); + free(node_name, M_BGX); + return (node); + } + free(reg, M_OFWPROP); } free(node_name, M_BGX); @@ -249,7 +362,7 @@ bgx_fdt_find_node(struct bgx *bgx) goto out; } - node = bgx_fdt_traverse_nodes(node, bgx_sel, len); + node = bgx_fdt_traverse_nodes(bgx->bgx_id, node, bgx_sel, len); out: free(bgx_sel, M_BGX); return (node); @@ -258,8 +371,10 @@ out: int bgx_fdt_init_phy(struct bgx *bgx) { + char *node_name; phandle_t node, child; phandle_t phy, mdio; + ssize_t len; uint8_t lmac; char qlm_mode[CONN_TYPE_MAXLEN]; @@ -272,20 +387,28 @@ bgx_fdt_init_phy(struct bgx *bgx) lmac = 0; for (child = OF_child(node); child > 0; child = OF_peer(child)) { - if (OF_getprop(child, "qlm-mode", qlm_mode, - sizeof(qlm_mode)) <= 0) { - /* Missing qlm-mode, skipping */ - continue; - } + len = OF_getprop(child, "qlm-mode", qlm_mode, sizeof(qlm_mode)); + if (len > 0) { + if (!bgx_fdt_phy_mode_match(bgx, qlm_mode, len)) { + /* + * Connection type not match with BGX mode. + */ + continue; + } + } else { + len = OF_getprop_alloc(child, "name", 1, + (void **)&node_name); + if (len <= 0) { + continue; + } - if (!bgx_fdt_phy_mode_match(bgx, qlm_mode, sizeof(qlm_mode))) { - /* - * Connection type not match with BGX mode. - */ - continue; + if (!bgx_fdt_phy_name_match(bgx, node_name, len)) { + free(node_name, M_OFWPROP); + continue; + } + free(node_name, M_OFWPROP); } - /* Acquire PHY address */ if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr, sizeof(bgx->lmac[lmac].phyaddr)) <= 0) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703311804.v2VI4ZTF078937>