Module Name:    src
Committed By:   jmcneill
Date:           Mon Jan  5 22:16:49 UTC 2015

Modified Files:
        src/sys/arch/arm/rockchip: rockchip_emac.c

Log Message:
add multicast filter support


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/rockchip/rockchip_emac.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/rockchip/rockchip_emac.c
diff -u src/sys/arch/arm/rockchip/rockchip_emac.c:1.3 src/sys/arch/arm/rockchip/rockchip_emac.c:1.4
--- src/sys/arch/arm/rockchip/rockchip_emac.c:1.3	Mon Jan  5 21:57:49 2015
+++ src/sys/arch/arm/rockchip/rockchip_emac.c	Mon Jan  5 22:16:49 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: rockchip_emac.c,v 1.3 2015/01/05 21:57:49 jmcneill Exp $ */
+/* $NetBSD: rockchip_emac.c,v 1.4 2015/01/05 22:16:49 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca>
@@ -29,7 +29,7 @@
 #include "opt_rkemac.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rockchip_emac.c,v 1.3 2015/01/05 21:57:49 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rockchip_emac.c,v 1.4 2015/01/05 22:16:49 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -144,6 +144,7 @@ static int	rkemac_queue(struct rkemac_so
 static void	rkemac_txdesc_sync(struct rkemac_softc *, int, int, int);
 static void	rkemac_txintr(struct rkemac_softc *);
 static void	rkemac_rxintr(struct rkemac_softc *);
+static void	rkemac_setmulti(struct rkemac_softc *);
 
 CFATTACH_DECL_NEW(rkemac, sizeof(struct rkemac_softc),
 	rkemac_match, rkemac_attach, NULL, NULL);
@@ -502,8 +503,6 @@ static int
 rkemac_init(struct ifnet *ifp)
 {
 	struct rkemac_softc *sc = ifp->if_softc;
-	struct ether_multi *em;
-	struct ether_multistep ems;
 	uint32_t control;
 
 	if (ifp->if_flags & IFF_RUNNING)
@@ -511,6 +510,11 @@ rkemac_init(struct ifnet *ifp)
 
 	rkemac_stop(ifp, 0);
 
+	EMAC_WRITE(sc, EMAC_POLLRATE_REG, RKEMAC_POLLRATE);
+	EMAC_WRITE(sc, EMAC_RXRINGPTR_REG, sc->sc_rxq.r_physaddr);
+	EMAC_WRITE(sc, EMAC_TXRINGPTR_REG, sc->sc_txq.t_physaddr);
+
+	control &= ~EMAC_CONTROL_RXBDTLEN;
 	control = EMAC_READ(sc, EMAC_CONTROL_REG);
 	if (ifp->if_flags & IFF_PROMISC) {
 		control |= EMAC_CONTROL_PROM;
@@ -522,24 +526,16 @@ rkemac_init(struct ifnet *ifp)
 	} else {
 		control |= EMAC_CONTROL_DISBC;
 	}
-	ETHER_FIRST_MULTI(ems, &sc->sc_ec, em);
-	if (em) {
-		ifp->if_flags |= IFF_ALLMULTI;
-		control |= EMAC_CONTROL_PROM;
-	} else {
-		ifp->if_flags &= ~IFF_ALLMULTI;
-	}
 
-	EMAC_WRITE(sc, EMAC_POLLRATE_REG, RKEMAC_POLLRATE);
-	EMAC_WRITE(sc, EMAC_RXRINGPTR_REG, sc->sc_rxq.r_physaddr);
-	EMAC_WRITE(sc, EMAC_TXRINGPTR_REG, sc->sc_txq.t_physaddr);
-
-	control &= ~EMAC_CONTROL_RXBDTLEN;
 	control |= __SHIFTIN(RKEMAC_RX_RING_COUNT, EMAC_CONTROL_RXBDTLEN);
 	control &= ~EMAC_CONTROL_TXBDTLEN;
 	control |= __SHIFTIN(RKEMAC_TX_RING_COUNT, EMAC_CONTROL_TXBDTLEN);
 	control |= EMAC_CONTROL_RXRN;
 	control |= EMAC_CONTROL_TXRN;
+	EMAC_WRITE(sc, EMAC_CONTROL_REG, control);
+
+	rkemac_setmulti(sc);
+
 	control |= EMAC_CONTROL_EN;
 	EMAC_WRITE(sc, EMAC_CONTROL_REG, control);
 
@@ -630,30 +626,16 @@ static int
 rkemac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
 	struct rkemac_softc *sc = ifp->if_softc;
-	struct ether_multi *em;
-	struct ether_multistep ems;
-	uint32_t control;
 	int s, error;
 
 	s = splnet();
 
 	if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
 		error = 0;
-		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
-			;
-		else if (ifp->if_flags & IFF_RUNNING) {
-			control = EMAC_READ(sc, EMAC_CONTROL_REG);
-			ETHER_FIRST_MULTI(ems, &sc->sc_ec, em);
-			if (em) {
-				ifp->if_flags |= IFF_ALLMULTI;
-				control |= EMAC_CONTROL_PROM;
-			} else {
-				ifp->if_flags &= ~IFF_ALLMULTI;
-				if ((ifp->if_flags & IFF_PROMISC) == 0) {
-					control &= ~EMAC_CONTROL_PROM;
-				}
+		if (ifp->if_flags & IFF_RUNNING) {
+			if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) {
+				rkemac_setmulti(sc);
 			}
-			EMAC_WRITE(sc, EMAC_CONTROL_REG, control);
 		}
 	}
 
@@ -895,3 +877,46 @@ skip:
 	sc->sc_rxq.r_cur = i;
 }
 
+static void
+rkemac_setmulti(struct rkemac_softc *sc)
+{
+	struct ifnet *ifp = &sc->sc_ec.ec_if;
+	struct ether_multi *enm;
+	struct ether_multistep step;
+	uint32_t hashes[2] = { 0, 0 };
+	uint32_t control, h;
+	int s;
+
+	s = splnet();
+
+	control = EMAC_READ(sc, EMAC_CONTROL_REG);
+
+	if (ifp->if_flags & IFF_PROMISC) {
+		control |= EMAC_CONTROL_PROM;
+		hashes[0] = hashes[1] = 0xffffffff;
+		goto done;
+	}
+
+	ifp->if_flags &= ~IFF_ALLMULTI;
+	control &= ~EMAC_CONTROL_PROM;
+
+	ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
+	while (enm != NULL) {
+		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+			control |= EMAC_CONTROL_PROM;
+			ifp->if_flags |= IFF_ALLMULTI;
+			hashes[0] = hashes[1] = 0xffffffff;
+			goto done;
+		}
+		h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+		hashes[h >> 5] |= (1 << (h & 0x1f));
+		ETHER_NEXT_MULTI(step, enm);
+	}
+
+done:
+	EMAC_WRITE(sc, EMAC_CONTROL_REG, control);
+	EMAC_WRITE(sc, EMAC_LAFL_REG, hashes[0]);
+	EMAC_WRITE(sc, EMAC_LAFH_REG, hashes[1]);
+
+	splx(s);
+}

Reply via email to