svn commit: r316336 - head/sys/dev/vnic
Zbigniew Bodek
zbb at FreeBSD.org
Fri Mar 31 18:04:36 UTC 2017
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) {
More information about the svn-src-all
mailing list