Index: sys/dev/dwc/if_dwc.c =================================================================== --- sys/dev/dwc/if_dwc.c +++ sys/dev/dwc/if_dwc.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -1007,9 +1008,9 @@ } static int -dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) +dwc_get_hwaddr(struct dwc_softc *sc, struct ether_addr *hwaddr) { - uint32_t hi, lo, rnd; + uint32_t hi, lo; /* * Try to recover a MAC address from the running hardware. If there's @@ -1016,30 +1017,25 @@ * something non-zero there, assume the bootloader did the right thing * and just use it. * - * Otherwise, set the address to a convenient locally assigned address, - * 'bsd' + random 24 low-order bits. 'b' is 0x62, which has the locally - * assigned bit set, and the broadcast/multicast bit clear. + * Otherwise check if there is a "local-mac-address" property. + * + * If everything fails, zero the address and call ether_gen_addr() later + * once we have an ifp. */ lo = READ4(sc, MAC_ADDRESS_LOW(0)); hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff; if ((lo != 0xffffffff) || (hi != 0xffff)) { - hwaddr[0] = (lo >> 0) & 0xff; - hwaddr[1] = (lo >> 8) & 0xff; - hwaddr[2] = (lo >> 16) & 0xff; - hwaddr[3] = (lo >> 24) & 0xff; - hwaddr[4] = (hi >> 0) & 0xff; - hwaddr[5] = (hi >> 8) & 0xff; - } else { - rnd = arc4random() & 0x00ffffff; - hwaddr[0] = 'b'; - hwaddr[1] = 's'; - hwaddr[2] = 'd'; - hwaddr[3] = rnd >> 16; - hwaddr[4] = rnd >> 8; - hwaddr[5] = rnd >> 0; + hwaddr->octet[0] = (lo >> 0) & 0xff; + hwaddr->octet[1] = (lo >> 8) & 0xff; + hwaddr->octet[2] = (lo >> 16) & 0xff; + hwaddr->octet[3] = (lo >> 24) & 0xff; + hwaddr->octet[4] = (hi >> 0) & 0xff; + hwaddr->octet[5] = (hi >> 8) & 0xff; + + return (0); } - return (0); + return (fdt_get_hwaddr(sc->dev, hwaddr)); } #define GPIO_ACTIVE_LOW 1 @@ -1142,10 +1138,10 @@ static int dwc_attach(device_t dev) { - uint8_t macaddr[ETHER_ADDR_LEN]; + struct ether_addr hwaddr; struct dwc_softc *sc; struct ifnet *ifp; - int error, i; + int error, hwaddrerr, i; uint32_t reg; sc = device_get_softc(dev); @@ -1172,11 +1168,10 @@ sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); - /* Read MAC before reset */ - if (dwc_get_hwaddr(sc, macaddr)) { - device_printf(sc->dev, "can't get mac\n"); - return (ENXIO); - } + /* Read HW MAC (and FDT) before reset. */ + hwaddrerr = dwc_get_hwaddr(sc, &hwaddr); + if (hwaddrerr && bootverbose) + device_printf(sc->dev, "cannot get HW Ethernet MAC\n"); /* Reset the PHY if needed */ if (dwc_reset(dev) != 0) { @@ -1260,8 +1255,12 @@ } sc->mii_softc = device_get_softc(sc->miibus); + /* If we could not get a HW Ethernet MAC, generate one. */ + if (hwaddrerr != 0) + ether_gen_addr(ifp, &hwaddr); + /* All ready to run, attach the ethernet interface. */ - ether_ifattach(ifp, macaddr); + ether_ifattach(ifp, hwaddr.octet); sc->is_attached = true; return (0); Index: sys/dev/fdt/fdt_common.h =================================================================== --- sys/dev/fdt/fdt_common.h +++ sys/dev/fdt/fdt_common.h @@ -38,6 +38,7 @@ #include #include #include +#include #define FDT_MEM_REGIONS 16 @@ -94,5 +95,6 @@ int fdt_is_compatible_strict(phandle_t, const char *); int fdt_parent_addr_cells(phandle_t); int fdt_get_chosen_bootargs(char *bootargs, size_t max_size); +int fdt_get_hwaddr(device_t, struct ether_addr *); #endif /* _FDT_COMMON_H_ */ Index: sys/dev/fdt/fdt_common.c =================================================================== --- sys/dev/fdt/fdt_common.c +++ sys/dev/fdt/fdt_common.c @@ -620,3 +620,37 @@ return (ENXIO); return (0); } + +int +fdt_get_hwaddr(device_t dev, struct ether_addr *hwaddr) +{ + phandle_t node; + ssize_t i, len; + static const char *properties[] = { + "mac-address", + "local-mac-address" + }; + + node = ofw_bus_get_node(dev); + if (node == -1) + return (ENXIO); + + for (i = 0; i < nitems(properties); ++i) { + + len = OF_getprop(node, properties[i], hwaddr->octet, + ETHER_ADDR_LEN); + if (len != ETHER_ADDR_LEN) + continue; + if (hwaddr->octet[0] == 0x00 && hwaddr->octet[1] == 0x00 && + hwaddr->octet[2] == 0x00) + continue; + if (hwaddr->octet[0] == 0xff && hwaddr->octet[1] == 0xff && + hwaddr->octet[2] == 0xff) + continue; + return (0); + } + + memset(hwaddr->octet, 0x00, ETHER_ADDR_LEN); + return (ENXIO); +} +