fix multicast filter on imxenet(4)

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

fix multicast filter on imxenet(4)

Matthieu Herrb
Hi,

The patch below is from brad@. It corrects the input filter on
imxenet(4) to correctly let multicat packets through.

With this patch my sabre lite board is able to auto-configure IPv6
correctly and do neighbour discovery.

Inspired by the FreeBSD driver
http://svnweb.freebsd.org/base/head/sys/dev/ffec/if_ffec.c

ok?

PS: Brad, I don't want to steal the commit from you. If someone ok's
the diff, please commit it if you can.

Index: imxenet.c
===================================================================
RCS file: /cvs/OpenBSD/src/sys/arch/armv7/imx/imxenet.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 imxenet.c
--- imxenet.c 6 Nov 2013 19:03:07 -0000 1.4
+++ imxenet.c 29 Jun 2014 14:25:05 -0000
@@ -477,10 +477,6 @@ imxenet_init(struct imxenet_softc *sc)
  /* clear outstanding interrupts */
  HWRITE4(sc, ENET_EIR, 0xffffffff);
 
- /* set address filter */
- HWRITE4(sc, ENET_GAUR, 0);
- HWRITE4(sc, ENET_GALR, 0);
-
  /* set max receive buffer size, 3-0 bits always zero for alignment */
  HWRITE4(sc, ENET_MRBR, ENET_MAX_PKT_SIZE);
 
@@ -534,6 +530,9 @@ imxenet_init(struct imxenet_softc *sc)
  /* rx descriptors are ready */
  HWRITE4(sc, ENET_RDAR, ENET_RDAR_RDAR);
 
+ /* program promiscuous mode and multicast filters */
+ imxenet_iff(sc);
+
  /* Indicate we are up and running. */
  ifp->if_flags |= IFF_RUNNING;
  ifp->if_flags &= ~IFF_OACTIVE;
@@ -556,7 +555,37 @@ imxenet_stop(struct imxenet_softc *sc)
 void
 imxenet_iff(struct imxenet_softc *sc)
 {
- // Set interface features
+ struct arpcom *ac = &sc->sc_ac;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ uint64_t ghash = 0, ihash = 0;
+ uint32_t h;
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+
+ if (ifp->if_flags & IFF_PROMISC) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ ihash = 0xffffffffffffffffLLU;
+ } else if (ac->ac_multirangecnt > 0) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ ghash = 0xffffffffffffffffLLU;
+ } else {
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+ ghash |= 1LLU << (((uint8_t *)&h)[3] >> 2);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+ }
+
+ HWRITE4(sc, ENET_GAUR, (uint32_t)(ghash >> 32));
+ HWRITE4(sc, ENET_GALR, (uint32_t)ghash);
+
+ HWRITE4(sc, ENET_IAUR, (uint32_t)(ihash >> 32));
+ HWRITE4(sc, ENET_IALR, (uint32_t)ihash);
 }
 
 int



--
Matthieu Herrb