diff -u -r -N ssrc/sys/mips/atheros/ar71xx_macaddr.c head/src/sys/mips/atheros/ar71xx_macaddr.c
--- src/sys/mips/atheros/ar71xx_macaddr.c 2018-07-07 20:50:15.479230000 +0200
+++ head/src/sys/mips/atheros/ar71xx_macaddr.c 2018-07-09 23:49:15.3719916 04:07:45.482053000 +0200
@@ -35,6 +35,8 @@
#include <net/ethernet.h>
+#include <sys/bus.h>
+
#include <mips/atheros/ar71xx_macaddr.h>
/*
@@ -61,9 +63,10 @@3,7 +65,8 @@
int t;
if (dst == NULL || src == NULL)
- return (-1);
+ return (-1);
- /* 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 src/sys/mips/atheros/ar71xx_macaddr.h head/src/sys/mips/atheros/ar71xx_macaddr.h
diff -u -r -N --- src/sys/mips/atheros/ar71xx_macaddr.h sys/mips/atheros/ar71xx_macaddr.h 2018-07-07 20:50:15.231507000 +0200
--- +++ head/src/sys/mips/atheros/ar71xx_macaddr.h 2018-07-07 20:50:15.2315076 23:03:17.000000000 +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 ssrc/sys/mips/atheros/ar71xxreg.h head/src/sys/mips/atheros/ar71xxreg.h
--- src/sys/mips/atheros/ar71xxreg.h 2018-07-07 20:50:15.191989000 +0200
+++ head/src/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 ssrc/sys/mips/atheros/if_arge.c head/src/sys/mips/atheros/if_arge.c
--- src/sys/mips/atheros/if_arge.c 2018-07-09 18:58:16.785548000 +0200
+++ head/src/sys/mips/atheros/if_arge.c 2018-07-11 22:44:12.383726000 +0200
@@ -55,6 +55,7 @@
#include <net/if.h>
#include <net/if_var.h>
+#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/ethernet.h>
#include <net/if_types.h>
@@ -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: