Skip site navigation (1)Skip section navigation (2)
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 **)&reg);
+		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>