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
This commit is contained in:
zbb 2016-01-28 15:30:58 +00:00
parent a0d10caff7
commit 2b71e630bd
3 changed files with 143 additions and 11 deletions

View File

@ -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

View File

@ -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, char *qlm_mode, size_t size)
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) {

View File

@ -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;