From ecb1ab17614fdc090c1d9924dfcf7f49160bb17b Mon Sep 17 00:00:00 2001 From: Rafal Jaworowski Date: Wed, 12 Mar 2008 16:32:08 +0000 Subject: [PATCH] Obtain TSEC h/w address from the parent bus (OCP) and not rely blindly on what might be currently programmed into the registers. Underlying firmware (U-Boot) would typically program MAC address into the first unit only, and others are left uninitialized. It is now possible to retrieve and program MAC address for all units properly, provided they were passed on in the bootinfo metadata. Reviewed by: imp, marcel Approved by: cognet (mentor) --- sys/dev/tsec/if_tsec.c | 24 ++++++++++++++---------- sys/powerpc/booke/machdep.c | 25 ++++++++++++++++++++++++- sys/powerpc/include/bootinfo.h | 3 +++ sys/powerpc/include/ocpbus.h | 1 + sys/powerpc/mpc85xx/ocpbus.c | 9 +++++++++ 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/sys/dev/tsec/if_tsec.c b/sys/dev/tsec/if_tsec.c index 8ea171aaa98..ccee8f7de32 100644 --- a/sys/dev/tsec/if_tsec.c +++ b/sys/dev/tsec/if_tsec.c @@ -170,22 +170,26 @@ tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr) uint8_t addr[6]; } curmac; uint32_t a[6]; - int count, i; - char *cp; + device_t parent; + uintptr_t macaddr; + int i; - /* Use the currently programmed MAC address by default. */ + parent = device_get_parent(sc->dev); + if (BUS_READ_IVAR(parent, sc->dev, OCPBUS_IVAR_MACADDR, + &macaddr) == 0) { + bcopy((uint8_t *)macaddr, addr, 6); + return; + } + + /* + * Fall back -- use the currently programmed address in the hope that + * it was set be firmware... + */ curmac.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1); curmac.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2); for (i = 0; i < 6; i++) a[5-i] = curmac.addr[i]; - cp = getenv("ethaddr"); - if (cp != NULL) { - count = sscanf(cp, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], - &a[3], &a[4], &a[5]); - freeenv(cp); - } - addr[0] = a[0]; addr[1] = a[1]; addr[2] = a[2]; diff --git a/sys/powerpc/booke/machdep.c b/sys/powerpc/booke/machdep.c index f5a1e068ab1..98d1b770fb7 100644 --- a/sys/powerpc/booke/machdep.c +++ b/sys/powerpc/booke/machdep.c @@ -313,6 +313,29 @@ print_kernel_section_addr(void) debugf(" _end = 0x%08x\n", (u_int32_t)_end); } +struct bi_mem_region * +bootinfo_mr(void) +{ + + return((struct bi_mem_region *)bootinfo->bi_data); +} + +struct bi_eth_addr * +bootinfo_eth(void) +{ + struct bi_mem_region *mr; + struct bi_eth_addr *eth; + int i; + + /* Advance to the eth section */ + mr = bootinfo_mr(); + for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) + ; + + eth = (struct bi_eth_addr *)mr; + return (eth); +} + void e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) { @@ -358,7 +381,7 @@ e500_init(u_int32_t startkernel, u_int32_t endkernel, void *mdp) } /* Initialize memory regions table */ - mr = (struct bi_mem_region *)bootinfo->bi_data; + mr = bootinfo_mr(); for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) { if (i == MEM_REGIONS) break; diff --git a/sys/powerpc/include/bootinfo.h b/sys/powerpc/include/bootinfo.h index 0125465853d..599516e57e6 100644 --- a/sys/powerpc/include/bootinfo.h +++ b/sys/powerpc/include/bootinfo.h @@ -64,6 +64,9 @@ struct bootinfo { }; extern struct bootinfo *bootinfo; + +struct bi_mem_region *bootinfo_mr(void); +struct bi_eth_addr *bootinfo_eth(void); #endif #endif /* _MACHINE_BOOTINFO_H_ */ diff --git a/sys/powerpc/include/ocpbus.h b/sys/powerpc/include/ocpbus.h index 6cd7f9efe5c..cbe4cf994dc 100644 --- a/sys/powerpc/include/ocpbus.h +++ b/sys/powerpc/include/ocpbus.h @@ -32,6 +32,7 @@ #define OCPBUS_IVAR_DEVTYPE 1 #define OCPBUS_IVAR_CLOCK 2 #define OCPBUS_IVAR_HWUNIT 3 +#define OCPBUS_IVAR_MACADDR 4 /* Device types. */ #define OCPBUS_DEVTYPE_PIC 1 diff --git a/sys/powerpc/mpc85xx/ocpbus.c b/sys/powerpc/mpc85xx/ocpbus.c index a62e78b8bca..cf86eed0cce 100644 --- a/sys/powerpc/mpc85xx/ocpbus.c +++ b/sys/powerpc/mpc85xx/ocpbus.c @@ -555,6 +555,8 @@ static int ocpbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) { struct ocp_devinfo *dinfo; + struct bi_eth_addr *eth; + int unit; if (device_get_parent(child) != dev) return (EINVAL); @@ -571,6 +573,13 @@ ocpbus_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) case OCPBUS_IVAR_HWUNIT: *result = dinfo->ocp_unit; return (0); + case OCPBUS_IVAR_MACADDR: + unit = device_get_unit(child); + if (unit > bootinfo->bi_eth_addr_no - 1) + return (EINVAL); + eth = bootinfo_eth() + unit; + *result = (uintptr_t)eth; + return (0); } return (EINVAL);