Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Jan 2016 15:30:59 +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: r294990 - head/sys/dev/vnic
Message-ID:  <201601281530.u0SFUxjO015505@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: zbb
Date: Thu Jan 28 15:30:58 2016
New Revision: 294990
URL: https://svnweb.freebsd.org/changeset/base/294990

Log:
  Fix finding appropriate BGX node in DTB and move it to a separate function
  
  Search for BGX node in DTS in two ways:
  1. Try to find it uder root node first
  2. If not found under root, find the top level PCI bridge node
     and search all nodes below it until appropriate BGX node is found.
  Move search code to another function to make the code more clear.
  Remove unused variable by the way.
  
  Reviewed by:   wma
  Obtained from: Semihalf
  Sponsored by:  Cavium
  Differential Revision: https://reviews.freebsd.org/D5066

Modified:
  head/sys/dev/vnic/thunder_bgx.c
  head/sys/dev/vnic/thunder_bgx_fdt.c
  head/sys/dev/vnic/thunder_bgx_var.h

Modified: head/sys/dev/vnic/thunder_bgx.c
==============================================================================
--- head/sys/dev/vnic/thunder_bgx.c	Thu Jan 28 14:11:59 2016	(r294989)
+++ head/sys/dev/vnic/thunder_bgx.c	Thu Jan 28 15:30:58 2016	(r294990)
@@ -68,7 +68,7 @@ __FBSDID("$FreeBSD$");
 
 #define	THUNDER_BGX_DEVSTR	"ThunderX BGX Ethernet I/O Interface"
 
-static MALLOC_DEFINE(M_BGX, "thunder_bgx", "ThunderX BGX dynamic memory");
+MALLOC_DEFINE(M_BGX, "thunder_bgx", "ThunderX BGX dynamic memory");
 
 #define BGX_NODE_ID_MASK	0x1
 #define BGX_NODE_ID_SHIFT	24

Modified: head/sys/dev/vnic/thunder_bgx_fdt.c
==============================================================================
--- head/sys/dev/vnic/thunder_bgx_fdt.c	Thu Jan 28 14:11:59 2016	(r294989)
+++ head/sys/dev/vnic/thunder_bgx_fdt.c	Thu Jan 28 15:30:58 2016	(r294990)
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <net/if_media.h>
 
 #include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
 #include <dev/mii/miivar.h>
 
 #include "thunder_bgx.h"
@@ -61,6 +62,11 @@ __FBSDID("$FreeBSD$");
 #define	CONN_TYPE_MAXLEN	16
 #define	CONN_TYPE_OFFSET	2
 
+#define	BGX_NODE_NAME		"bgx"
+#define	BGX_MAXID		9
+
+#define	FDT_NAME_MAXLEN		31
+
 int bgx_fdt_init_phy(struct bgx *);
 
 static void
@@ -119,28 +125,152 @@ bgx_fdt_phy_mode_match(struct bgx *bgx, 
 	return (FALSE);
 }
 
+static phandle_t
+bgx_fdt_traverse_nodes(phandle_t start, char *name, size_t len)
+{
+	phandle_t node, ret;
+	size_t buf_size;
+	char *node_name;
+	int err;
+
+	buf_size = sizeof(*node_name) * FDT_NAME_MAXLEN;
+	if (len > buf_size) {
+		/*
+		 * This is an erroneous situation since the string
+		 * to compare cannot be longer than FDT_NAME_MAXLEN.
+		 */
+		return (0);
+	}
+
+	node_name = malloc(buf_size, M_BGX, M_WAITOK);
+	for (node = OF_child(start); node != 0; node = OF_peer(node)) {
+		/* Clean-up the buffer */
+		memset(node_name, 0, buf_size);
+		/* Recurse to children */
+		if (OF_child(node) != 0) {
+			ret = bgx_fdt_traverse_nodes(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)) {
+			free(node_name, M_BGX);
+			return (node);
+		}
+	}
+	free(node_name, M_BGX);
+
+	return (0);
+}
+
+/*
+ * Similar functionality to pci_find_pcie_root_port()
+ * but this one works for ThunderX.
+ */
+static device_t
+bgx_find_root_pcib(device_t dev)
+{
+	devclass_t pci_class;
+	device_t pcib, bus;
+
+	pci_class = devclass_find("pci");
+	KASSERT(device_get_devclass(device_get_parent(dev)) == pci_class,
+	    ("%s: non-pci device %s", __func__, device_get_nameunit(dev)));
+
+	/* Walk the bridge hierarchy until we find a non-PCI device */
+	for (;;) {
+		bus = device_get_parent(dev);
+		KASSERT(bus != NULL, ("%s: null parent of %s", __func__,
+		    device_get_nameunit(dev)));
+
+		if (device_get_devclass(bus) != pci_class)
+			return (NULL);
+
+		pcib = device_get_parent(bus);
+		KASSERT(pcib != NULL, ("%s: null bridge of %s", __func__,
+		    device_get_nameunit(bus)));
+
+		/*
+		 * If the parent of this PCIB is not PCI
+		 * then we found our root PCIB.
+		 */
+		if (device_get_devclass(device_get_parent(pcib)) != pci_class)
+			return (pcib);
+
+		dev = pcib;
+	}
+}
+
+static __inline phandle_t
+bgx_fdt_find_node(struct bgx *bgx)
+{
+	device_t root_pcib;
+	phandle_t node;
+	char *bgx_sel;
+	size_t len;
+
+	KASSERT(bgx->bgx_id <= BGX_MAXID,
+	    ("Invalid BGX ID: %d, max: %d", bgx->bgx_id, BGX_MAXID));
+
+	len = sizeof(BGX_NODE_NAME) + 1; /* <bgx_name>+<digit>+<\0> */
+	/* Allocate memory for BGX node name + "/" character */
+	bgx_sel = malloc(sizeof(*bgx_sel) * (len + 1), M_BGX,
+	    M_ZERO | M_WAITOK);
+
+	/* Prepare node's name */
+	snprintf(bgx_sel, len + 1, "/"BGX_NODE_NAME"%d", bgx->bgx_id);
+	/* First try the root node */
+	node =  OF_finddevice(bgx_sel);
+	if ((int)node > 0) {
+		/* Found relevant node */
+		goto out;
+	}
+	/*
+	 * Clean-up and try to find BGX in DT
+	 * starting from the parent PCI bridge node.
+	 */
+	memset(bgx_sel, 0, sizeof(*bgx_sel) * (len + 1));
+	snprintf(bgx_sel, len, BGX_NODE_NAME"%d", bgx->bgx_id);
+
+	/* Find PCI bridge that we are connected to */
+
+	root_pcib = bgx_find_root_pcib(bgx->dev);
+	if (root_pcib == NULL) {
+		device_printf(bgx->dev, "Unable to find BGX root bridge\n");
+		node = 0;
+		goto out;
+	}
+
+	node = ofw_bus_get_node(root_pcib);
+	if (node == 0) {
+		device_printf(bgx->dev, "No parent FDT node for BGX\n");
+		goto out;
+	}
+
+	node = bgx_fdt_traverse_nodes(node, bgx_sel, len);
+out:
+	free(bgx_sel, M_BGX);
+	return (node);
+}
+
 int
 bgx_fdt_init_phy(struct bgx *bgx)
 {
 	phandle_t node, child;
 	phandle_t phy, mdio;
 	uint8_t lmac;
-	char bgx_sel[6];
 	char qlm_mode[CONN_TYPE_MAXLEN];
-	const char *mac;
-
-	(void)mac;
 
-	lmac = 0;
-	/* Get BGX node from DT */
-	snprintf(bgx_sel, 6, "/bgx%d", bgx->bgx_id);
-	node = OF_finddevice(bgx_sel);
-	if (node == 0 || node == -1) {
+	node = bgx_fdt_find_node(bgx);
+	if (node == 0) {
 		device_printf(bgx->dev,
-		    "Could not find %s node in FDT\n", bgx_sel);
+		    "Could not find bgx%d node in FDT\n", bgx->bgx_id);
 		return (ENXIO);
 	}
 
+	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) {

Modified: head/sys/dev/vnic/thunder_bgx_var.h
==============================================================================
--- head/sys/dev/vnic/thunder_bgx_var.h	Thu Jan 28 14:11:59 2016	(r294989)
+++ head/sys/dev/vnic/thunder_bgx_var.h	Thu Jan 28 15:30:58 2016	(r294990)
@@ -30,6 +30,8 @@
 #ifndef __THUNDER_BGX_VAR_H__
 #define	__THUNDER_BGX_VAR_H__
 
+MALLOC_DECLARE(M_BGX);
+
 struct lmac {
 	struct bgx		*bgx;
 	int			dmac;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201601281530.u0SFUxjO015505>