Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/vnic/thunder_bgx_fdt.c
Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
#include "thunder_bgx.h" | #include "thunder_bgx.h" | ||||
#include "thunder_bgx_var.h" | #include "thunder_bgx_var.h" | ||||
#define CONN_TYPE_MAXLEN 16 | #define CONN_TYPE_MAXLEN 16 | ||||
#define CONN_TYPE_OFFSET 2 | #define CONN_TYPE_OFFSET 2 | ||||
#define BGX_NODE_NAME "bgx" | #define BGX_NODE_NAME "bgx" | ||||
#define BGX_MAXID 9 | #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 | #define FDT_NAME_MAXLEN 31 | ||||
int bgx_fdt_init_phy(struct bgx *); | int bgx_fdt_init_phy(struct bgx *); | ||||
static void | static void | ||||
bgx_fdt_get_macaddr(phandle_t phy, uint8_t *hwaddr) | bgx_fdt_get_macaddr(phandle_t phy, uint8_t *hwaddr) | ||||
{ | { | ||||
uint8_t addr[ETHER_ADDR_LEN]; | uint8_t addr[ETHER_ADDR_LEN]; | ||||
if (OF_getprop(phy, "local-mac-address", addr, ETHER_ADDR_LEN) == -1) { | if (OF_getprop(phy, "local-mac-address", addr, ETHER_ADDR_LEN) == -1) { | ||||
/* Missing MAC address should be marked by clearing it */ | /* Missing MAC address should be marked by clearing it */ | ||||
memset(hwaddr, 0, ETHER_ADDR_LEN); | memset(hwaddr, 0, ETHER_ADDR_LEN); | ||||
} else | } else | ||||
memcpy(hwaddr, addr, ETHER_ADDR_LEN); | memcpy(hwaddr, addr, ETHER_ADDR_LEN); | ||||
} | } | ||||
static boolean_t | 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) | ||||
{ | { | ||||
const char *type; | |||||
ssize_t sz; | |||||
ssize_t offset; | |||||
size -= CONN_TYPE_OFFSET; | |||||
switch (bgx->qlm_mode) { | switch (bgx->qlm_mode) { | ||||
case QLM_MODE_SGMII: | case QLM_MODE_SGMII: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "sgmii", size) == 0) | type = "sgmii"; | ||||
return (TRUE); | sz = sizeof("sgmii") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_XAUI_1X4: | case QLM_MODE_XAUI_1X4: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xaui", 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); | return (TRUE); | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "dxaui", size) == 0) | type = "dxaui"; | ||||
return (TRUE); | sz = sizeof("dxaui") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_RXAUI_2X2: | case QLM_MODE_RXAUI_2X2: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "raui", size) == 0) | type = "raui"; | ||||
return (TRUE); | sz = sizeof("raui") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_XFI_4X1: | case QLM_MODE_XFI_4X1: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xfi", size) == 0) | type = "xfi"; | ||||
return (TRUE); | sz = sizeof("xfi") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_XLAUI_1X4: | case QLM_MODE_XLAUI_1X4: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xlaui", size) == 0) | type = "xlaui"; | ||||
return (TRUE); | sz = sizeof("xlaui") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_10G_KR_4X1: | case QLM_MODE_10G_KR_4X1: | ||||
if (strncmp(&qlm_mode[CONN_TYPE_OFFSET], "xfi-10g-kr", size) == 0) | type = "xfi-10g-kr"; | ||||
return (TRUE); | sz = sizeof("xfi-10g-kr") - 1; | ||||
offset = size - sz; | |||||
break; | break; | ||||
case QLM_MODE_40G_KR4_1X4: | 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 (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; | 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: | default: | ||||
return (FALSE); | return (FALSE); | ||||
} | } | ||||
if (sz > size) | |||||
return (FALSE); | return (FALSE); | ||||
if (strncmp(phy_name, type, sz) == 0) | |||||
return (TRUE); | |||||
return (FALSE); | |||||
} | } | ||||
static phandle_t | 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; | phandle_t node, ret; | ||||
uint32_t *reg; | |||||
size_t buf_size; | size_t buf_size; | ||||
ssize_t proplen; | |||||
char *node_name; | char *node_name; | ||||
int err; | 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; | buf_size = sizeof(*node_name) * FDT_NAME_MAXLEN; | ||||
if (len > buf_size) { | if (len > buf_size) { | ||||
/* | /* | ||||
* This is an erroneous situation since the string | * This is an erroneous situation since the string | ||||
* to compare cannot be longer than FDT_NAME_MAXLEN. | * to compare cannot be longer than FDT_NAME_MAXLEN. | ||||
*/ | */ | ||||
return (0); | return (0); | ||||
} | } | ||||
node_name = malloc(buf_size, M_BGX, M_WAITOK); | node_name = malloc(buf_size, M_BGX, M_WAITOK); | ||||
for (node = OF_child(start); node != 0; node = OF_peer(node)) { | for (node = OF_child(start); node != 0; node = OF_peer(node)) { | ||||
/* Clean-up the buffer */ | /* Clean-up the buffer */ | ||||
memset(node_name, 0, buf_size); | memset(node_name, 0, buf_size); | ||||
/* Recurse to children */ | /* Recurse to children */ | ||||
if (OF_child(node) != 0) { | 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) { | if (ret != 0) { | ||||
free(node_name, M_BGX); | free(node_name, M_BGX); | ||||
return (ret); | 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); | free(node_name, M_BGX); | ||||
return (node); | 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); | free(node_name, M_BGX); | ||||
return (node); | |||||
} | |||||
free(reg, M_OFWPROP); | |||||
} | |||||
free(node_name, M_BGX); | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Similar functionality to pci_find_pcie_root_port() | * Similar functionality to pci_find_pcie_root_port() | ||||
* but this one works for ThunderX. | * but this one works for ThunderX. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | bgx_fdt_find_node(struct bgx *bgx) | ||||
} | } | ||||
node = ofw_bus_get_node(root_pcib); | node = ofw_bus_get_node(root_pcib); | ||||
if ((int)node <= 0) { | if ((int)node <= 0) { | ||||
device_printf(bgx->dev, "No parent FDT node for BGX\n"); | device_printf(bgx->dev, "No parent FDT node for BGX\n"); | ||||
goto out; | goto out; | ||||
} | } | ||||
node = bgx_fdt_traverse_nodes(node, bgx_sel, len); | node = bgx_fdt_traverse_nodes(bgx->bgx_id, node, bgx_sel, len); | ||||
out: | out: | ||||
free(bgx_sel, M_BGX); | free(bgx_sel, M_BGX); | ||||
return (node); | return (node); | ||||
} | } | ||||
int | int | ||||
bgx_fdt_init_phy(struct bgx *bgx) | bgx_fdt_init_phy(struct bgx *bgx) | ||||
{ | { | ||||
char *node_name; | |||||
phandle_t node, child; | phandle_t node, child; | ||||
phandle_t phy, mdio; | phandle_t phy, mdio; | ||||
ssize_t len; | |||||
uint8_t lmac; | uint8_t lmac; | ||||
char qlm_mode[CONN_TYPE_MAXLEN]; | char qlm_mode[CONN_TYPE_MAXLEN]; | ||||
node = bgx_fdt_find_node(bgx); | node = bgx_fdt_find_node(bgx); | ||||
if (node == 0) { | if (node == 0) { | ||||
device_printf(bgx->dev, | device_printf(bgx->dev, | ||||
"Could not find bgx%d node in FDT\n", bgx->bgx_id); | "Could not find bgx%d node in FDT\n", bgx->bgx_id); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
lmac = 0; | lmac = 0; | ||||
for (child = OF_child(node); child > 0; child = OF_peer(child)) { | for (child = OF_child(node); child > 0; child = OF_peer(child)) { | ||||
if (OF_getprop(child, "qlm-mode", qlm_mode, | len = OF_getprop(child, "qlm-mode", qlm_mode, sizeof(qlm_mode)); | ||||
sizeof(qlm_mode)) <= 0) { | if (len > 0) { | ||||
/* Missing qlm-mode, skipping */ | if (!bgx_fdt_phy_mode_match(bgx, qlm_mode, len)) { | ||||
continue; | |||||
} | |||||
if (!bgx_fdt_phy_mode_match(bgx, qlm_mode, sizeof(qlm_mode))) { | |||||
/* | /* | ||||
* Connection type not match with BGX mode. | * Connection type not match with BGX mode. | ||||
*/ | */ | ||||
continue; | continue; | ||||
} | } | ||||
} else { | |||||
len = OF_getprop_alloc(child, "name", 1, | |||||
(void **)&node_name); | |||||
if (len <= 0) { | |||||
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 */ | /* Acquire PHY address */ | ||||
if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr, | if (OF_getencprop(child, "reg", &bgx->lmac[lmac].phyaddr, | ||||
sizeof(bgx->lmac[lmac].phyaddr)) <= 0) { | sizeof(bgx->lmac[lmac].phyaddr)) <= 0) { | ||||
if (bootverbose) { | if (bootverbose) { | ||||
device_printf(bgx->dev, | device_printf(bgx->dev, | ||||
"Could not retrieve PHY address\n"); | "Could not retrieve PHY address\n"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |