Index: head/sys/dev/vnic/thunder_bgx.c =================================================================== --- head/sys/dev/vnic/thunder_bgx.c +++ head/sys/dev/vnic/thunder_bgx.c @@ -68,7 +68,7 @@ #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 Index: head/sys/dev/vnic/thunder_bgx_fdt.c =================================================================== --- head/sys/dev/vnic/thunder_bgx_fdt.c +++ head/sys/dev/vnic/thunder_bgx_fdt.c @@ -53,6 +53,7 @@ #include #include +#include #include #include "thunder_bgx.h" @@ -61,6 +62,11 @@ #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 @@ 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; /* ++<\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) { Index: head/sys/dev/vnic/thunder_bgx_var.h =================================================================== --- head/sys/dev/vnic/thunder_bgx_var.h +++ head/sys/dev/vnic/thunder_bgx_var.h @@ -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;