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)
This commit is contained in:
Rafal Jaworowski 2008-03-12 16:32:08 +00:00
parent 7cc9e5030e
commit ecb1ab1761
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=177110
5 changed files with 51 additions and 11 deletions

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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