diff -u -r -N sys/mips/atheros/ar71xx_macaddr.c sys/mips/atheros/ar71xx_macaddr.c --- sys/mips/atheros/ar71xx_macaddr.c 2018-07-07 20:50:15.479230000 +0200 +++ sys/mips/atheros/ar71xx_macaddr.c 2018-07-09 23:49:15.371993000 +0200 @@ -35,6 +35,8 @@ #include +#include + #include /* @@ -61,9 +63,10 @@ int t; if (dst == NULL || src == NULL) - return (-1); + return (EINVAL); - /* XXX TODO: validate 'src' is a valid MAC address */ + if (ETHER_IS_MULTICAST(src) != 0) + return (-1); t = (((uint32_t) src[3]) << 16) + (((uint32_t) src[4]) << 8) @@ -108,3 +111,110 @@ return (0); } + +/* + * Initialize MAC Address by hints mechanism. + * + * Returns 1 if MAC Address exists, 0 if not. + */ +int +ar71xx_mac_addr_hint_init(device_t dev, unsigned char *addr) +{ + char dev_id[32]; + char * mac_addr; + uint32_t tmp_addr[ETHER_ADDR_LEN]; + int count; + int i; + int local_mac; + + (void)snprintf(dev_id, 32, "hint.%s.%d.macaddr", + device_get_name(dev), device_get_unit(dev)); + + if ((mac_addr = kern_getenv(dev_id)) != NULL) { + /* Have a MAC address; should use it. */ + device_printf(dev, "Overriding MAC address " + "from environment: '%s'\n", mac_addr); + + /* Extract out the MAC address. */ + count = sscanf(mac_addr, + "%x%*c%x%*c%x%*c%x%*c%x%*c%x", + &tmp_addr[0], &tmp_addr[1], + &tmp_addr[2], &tmp_addr[3], + &tmp_addr[4], &tmp_addr[5]); + + /* Valid! */ + if (count == ETHER_ADDR_LEN) { + for (i = 0; i < count; i++) + addr[i] = tmp_addr[i]; + + local_mac = 1; + } else + local_mac = 0; + + /* Done! */ + freeenv(mac_addr); + mac_addr = NULL; + } else + local_mac = 0; + + return (local_mac); +} + +/* + * Initialize MAC Address by reading EEPROM. + * + * Some units (eg the TP-Link WR-1043ND) do not have a convenient + * EEPROM location to read the ethernet MAC address from. + * OpenWRT simply snaffles it from a fixed location. + * + * Since multiple units seem to use this feature, include + * a method of setting the MAC address based on an flash location + * in CPU address space. + * + * Some vendors have decided to store the mac address as a literal + * string of 18 characters in xx:xx:xx:xx:xx:xx format instead of + * an array of numbers. Expose a hint to turn on this conversion + * feature via strtol(). + * + * Returns 1 if MAC Address exists, 0 if not. + */ +int +ar71xx_mac_addr_eeprom_init(device_t dev, unsigned char *addr) +{ + const char *name; + int unit; + long eeprom_mac_addr; + const char *mac_addr; + int readascii; + int i; + int local_mac; + + name = device_get_name(dev); + unit = device_get_unit(dev); + eeprom_mac_addr = 0; + + if (resource_long_value(name, unit, + "eeprommac", &eeprom_mac_addr) == 0) { + device_printf(dev, "Overriding MAC from EEPROM\n"); + + mac_addr = (const char *)MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); + readascii = 0; + + if (resource_int_value(name, unit, + "readascii", &readascii) == 0) { + device_printf(dev, "Vendor stores MAC in ASCII format\n"); + + for (i = 0; i < ETHER_ADDR_LEN; i++) { + addr[i] = strtol(&(mac_addr[i*3]), NULL, 16); + } + } else { + for (i = 0; i < ETHER_ADDR_LEN; i++) { + addr[i] = mac_addr[i]; + } + } + local_mac = 1; + } else + local_mac = 0; + + return (local_mac); +} diff -u -r -N sys/mips/atheros/ar71xx_macaddr.h sys/mips/atheros/ar71xx_macaddr.h --- sys/mips/atheros/ar71xx_macaddr.h 2018-07-07 20:50:15.231507000 +0200 +++ sys/mips/atheros/ar71xx_macaddr.h 2018-07-06 23:03:17.000000000 +0200 @@ -35,5 +35,6 @@ extern int ar71xx_mac_addr_init(unsigned char *dst, const unsigned char *src, int offset, int is_local); extern int ar71xx_mac_addr_random_init(unsigned char *dst); - +extern int ar71xx_mac_addr_hint_init(device_t dev, unsigned char *addr); +extern int ar71xx_mac_addr_eeprom_init(device_t dev, unsigned char *addr); #endif /* __ATHEROS_AR71XX_MACADDR_H__ */ diff -u -r -N sys/mips/atheros/ar71xxreg.h sys/mips/atheros/ar71xxreg.h --- sys/mips/atheros/ar71xxreg.h 2018-07-07 20:50:15.191989000 +0200 +++ sys/mips/atheros/ar71xxreg.h 2018-07-10 01:39:00.458571000 +0200 @@ -31,6 +31,13 @@ #ifndef _AR71XX_REG_H_ #define _AR71XX_REG_H_ +#define AR71XX_GE0 0 +#define AR71XX_GE1 1 + +#define AR71XX_GE_SPEED_10 10 +#define AR71XX_GE_SPEED_100 100 +#define AR71XX_GE_SPEED_1000 1000 + /* PCI region */ #define AR71XX_PCI_MEM_BASE 0x10000000 /* diff -u -r -N sys/mips/atheros/if_arge.c sys/mips/atheros/if_arge.c --- sys/mips/atheros/if_arge.c 2018-07-09 18:58:16.785548000 +0200 +++ sys/mips/atheros/if_arge.c 2018-07-11 22:44:12.383726000 +0200 @@ -55,6 +55,7 @@ #include #include +#include #include #include #include @@ -143,6 +144,7 @@ static void arge_link_task(void *, int); static void arge_update_link_locked(struct arge_softc *sc); static void arge_set_pll(struct arge_softc *, int, int); +static void arge_rxfilter(struct arge_softc *sc); static int arge_miibus_readreg(device_t, int, int); static void arge_miibus_statchg(device_t); static int arge_miibus_writereg(device_t, int, int, int); @@ -258,10 +260,10 @@ arge_flush_ddr(struct arge_softc *sc) { switch (sc->arge_mac_unit) { - case 0: + case AR71XX_GE0: ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE0); break; - case 1: + case AR71XX_GE1: ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE1); break; default: @@ -641,15 +643,10 @@ struct arge_softc *sc; int error = 0, rid, i; uint32_t hint; - long eeprom_mac_addr = 0; int miicfg = 0; - int readascii = 0; - int local_mac = 0; + int local_mac; uint8_t local_macaddr[ETHER_ADDR_LEN]; - char * local_macstr; - char devid_str[32]; - int count; - + sc = device_get_softc(dev); sc->arge_dev = dev; sc->arge_mac_unit = device_get_unit(dev); @@ -662,32 +659,7 @@ * routines, but at the moment the system is booting, the resource hints * are set to the 'static' map so they're not pulling from kenv. */ - snprintf(devid_str, 32, "hint.%s.%d.macaddr", - device_get_name(dev), - device_get_unit(dev)); - if ((local_macstr = kern_getenv(devid_str)) != NULL) { - uint32_t tmpmac[ETHER_ADDR_LEN]; - - /* Have a MAC address; should use it */ - device_printf(dev, "Overriding MAC address from environment: '%s'\n", - local_macstr); - - /* Extract out the MAC address */ - /* XXX this should all be a generic method */ - count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", - &tmpmac[0], &tmpmac[1], - &tmpmac[2], &tmpmac[3], - &tmpmac[4], &tmpmac[5]); - if (count == 6) { - /* Valid! */ - local_mac = 1; - for (i = 0; i < ETHER_ADDR_LEN; i++) - local_macaddr[i] = tmpmac[i]; - } - /* Done! */ - freeenv(local_macstr); - local_macstr = NULL; - } + local_mac = ar71xx_mac_addr_hint_init(dev, local_macaddr); /* * Hardware workarounds. @@ -726,25 +698,8 @@ * an array of numbers. Expose a hint to turn on this conversion * feature via strtol() */ - if (local_mac == 0 && resource_long_value(device_get_name(dev), - device_get_unit(dev), "eeprommac", &eeprom_mac_addr) == 0) { - local_mac = 1; - int i; - const char *mac = - (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); - device_printf(dev, "Overriding MAC from EEPROM\n"); - if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "readascii", &readascii) == 0) { - device_printf(dev, "Vendor stores MAC in ASCII format\n"); - for (i = 0; i < 6; i++) { - local_macaddr[i] = strtol(&(mac[i*3]), NULL, 16); - } - } else { - for (i = 0; i < 6; i++) { - local_macaddr[i] = mac[i]; - } - } - } + if (local_mac == 0) + local_mac = ar71xx_mac_addr_eeprom_init(dev, local_macaddr); KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)), ("if_arge: Only MAC0 and MAC1 supported")); @@ -790,11 +745,11 @@ "media", &hint) != 0) hint = 0; - if (hint == 1000) + if (hint == AR71XX_GE_SPEED_1000) sc->arge_media_type = IFM_1000_T; - else if (hint == 100) + else if (hint == AR71XX_GE_SPEED_100) sc->arge_media_type = IFM_100_TX; - else if (hint == 10) + else if (hint == AR71XX_GE_SPEED_10) sc->arge_media_type = IFM_10_T; else sc->arge_media_type = 0; @@ -867,8 +822,12 @@ /* If there's a local mac defined, copy that in */ if (local_mac == 1) { - (void) ar71xx_mac_addr_init(sc->arge_eaddr, - local_macaddr, 0, 0); + if (ar71xx_mac_addr_init(sc->arge_eaddr, + local_macaddr, 0, 0) != 0) { + device_printf(dev, + "Generating random ethernet address.\n"); + (void) ar71xx_mac_addr_random_init(sc->arge_eaddr); + } } else { /* * No MAC address configured. Generate the random one. @@ -941,6 +900,11 @@ ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff); } + /* + * If bit of AR71XX_MAC_FIFO_RX_FILTMATCH does + * not match with AR71XX_MAC_FIFO_RX_FILTMASK + * then the frame is dropped. + */ ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH, FIFO_RX_FILTMATCH_DEFAULT); @@ -1274,21 +1238,21 @@ switch(media) { case IFM_10_T: cfg |= MAC_CFG2_IFACE_MODE_10_100; - if_speed = 10; + if_speed = AR71XX_GE_SPEED_10; break; case IFM_100_TX: cfg |= MAC_CFG2_IFACE_MODE_10_100; ifcontrol |= MAC_IFCONTROL_SPEED; - if_speed = 100; + if_speed = AR71XX_GE_SPEED_100; break; case IFM_1000_T: case IFM_1000_SX: cfg |= MAC_CFG2_IFACE_MODE_1000; rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; - if_speed = 1000; + if_speed = AR71XX_GE_SPEED_1000; break; default: - if_speed = 100; + if_speed = AR71XX_GE_SPEED_100; device_printf(sc->arge_dev, "Unknown media %d\n", media); } @@ -1330,11 +1294,11 @@ ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: pll=0x%x\n", __func__, pll); /* Override if required by platform data */ - if (if_speed == 10 && sc->arge_pllcfg.pll_10 != 0) + if (if_speed == AR71XX_GE_SPEED_10 && sc->arge_pllcfg.pll_10 != 0) pll = sc->arge_pllcfg.pll_10; - else if (if_speed == 100 && sc->arge_pllcfg.pll_100 != 0) + else if (if_speed == AR71XX_GE_SPEED_100 && sc->arge_pllcfg.pll_100 != 0) pll = sc->arge_pllcfg.pll_100; - else if (if_speed == 1000 && sc->arge_pllcfg.pll_1000 != 0) + else if (if_speed == AR71XX_GE_SPEED_1000 && sc->arge_pllcfg.pll_1000 != 0) pll = sc->arge_pllcfg.pll_1000; ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: final pll=0x%x\n", __func__, pll); @@ -1357,6 +1321,34 @@ #endif } +/* + * Enable / disable promiscuous, multicast or broadcast flags. + */ +static void +arge_rxfilter(struct arge_softc *sc) +{ + struct ifnet *ifp; + uint32_t rxcfg; + + ARGE_LOCK_ASSERT(sc); + + ifp = sc->arge_ifp; + + rxcfg = ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); + rxcfg &= ~(FIFO_RX_MASK_BCAST|FIFO_RX_MASK_MCAST); + + if ((ifp->if_flags & IFF_BROADCAST) != 0) + rxcfg |= FIFO_RX_MASK_BCAST; + + if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { + if ((ifp->if_flags & IFF_PROMISC) != 0) + rxcfg |= (FIFO_RX_MASK_BCAST|FIFO_RX_MASK_MCAST); + if ((ifp->if_flags & IFF_ALLMULTI) != 0) + rxcfg |= FIFO_RX_MASK_MCAST; + } + + ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, rxcfg); +} static void arge_reset_dma(struct arge_softc *sc) @@ -1424,7 +1416,22 @@ return; } + /* Setup MAC address */ + if (ar71xx_mac_addr_init(sc->arge_eaddr, + IF_LLADDR(ifp), 0, 0) != 0) { + device_printf(sc->arge_dev, + "initialization failed: invalid MAC Address\n"); + arge_stop(sc); + return; + } + ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24) + | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8) + | sc->arge_eaddr[5]); + ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8) + | sc->arge_eaddr[1]); + /* Setup rx filter */ + arge_rxfilter(sc); /* Init tx descriptors. */ arge_tx_ring_init(sc); @@ -1738,7 +1745,7 @@ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { if (((ifp->if_flags ^ sc->arge_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { - /* XXX: handle promisc & multi flags */ + arge_rxfilter(sc); } } else { @@ -1755,7 +1762,9 @@ break; case SIOCADDMULTI: case SIOCDELMULTI: - /* XXX: implement SIOCDELMULTI */ + ARGE_LOCK(sc); + arge_rxfilter(sc); + ARGE_UNLOCK(sc); error = 0; break; case SIOCGIFMEDIA: