Index: sys/dev/dwc/if_dwc.c =================================================================== --- sys/dev/dwc/if_dwc.c +++ sys/dev/dwc/if_dwc.c @@ -1007,39 +1007,61 @@ } static int -dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr) +dwc_get_hwaddr_fdt(struct dwc_softc *sc, struct ether_addr *hwaddr) { - uint32_t hi, lo, rnd; + phandle_t node; + int len; + node = ofw_bus_get_node(sc->dev); + len = OF_getprop(node, "local-mac-address", hwaddr->octet, + ETHER_ADDR_LEN); + if (len != ETHER_ADDR_LEN) { + if (bootverbose) + device_printf(sc->dev, "%s: OF_getprop(" + "local-mac-address) failed %d\n", __func__, len); + return (ENOENT); + } + if (hwaddr->octet[0] == 0x00 && hwaddr->octet[1] == 0x00 && + hwaddr->octet[2] == 0x00) + return (EINVAL); + + return (0); +} + +static int +dwc_get_hwaddr(struct dwc_softc *sc, struct ether_addr *hwaddr) +{ + uint32_t hi, lo; + int error; + /* * Try to recover a MAC address from the running hardware. If there's * 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); + error = dwc_get_hwaddr_fdt(sc, hwaddr); + if (error != 0) + memset(hwaddr->octet, 0x00, ETHER_ADDR_LEN); + + return (error); } #define GPIO_ACTIVE_LOW 1 @@ -1142,10 +1164,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 +1194,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 +1281,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);