Subject: port-powerpc/23892: Correspond promisc & multicast
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <kiyohara@kk.iij4u.or.jp>
List: netbsd-bugs
Date: 12/26/2003 18:06:25
>Number:         23892
>Category:       port-powerpc
>Synopsis:       Correspond promisc & multicast
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    port-powerpc-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Dec 26 18:07:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     KIYOHARA Takashi
>Release:        1.6ZG
>Organization:
>Environment:
NetBSD evbppc.fool 1.6ZG NetBSD 1.6ZG (OPENBLOCKS266) #0: Sun Dec 21 12:58:20 JST 2003 lance@highpriestess.fool:/sys/arch/evbppc/compile/OPENBLOCKS266 evbppc
>Description:
Don't work promisc & multicast on ibm4xx emac. Correspond promisc & multicast mode. ibm4xx bridgeing OK.
>How-To-Repeat:

>Fix:
Index: arch/powerpc/ibm4xx/dev/if_emac.c
===================================================================
RCS file: /cvsroot/src/sys/arch/powerpc/ibm4xx/dev/if_emac.c,v
retrieving revision 1.17
diff -c -r1.17 if_emac.c
*** arch/powerpc/ibm4xx/dev/if_emac.c   2003/10/27 03:58:17     1.17
--- arch/powerpc/ibm4xx/dev/if_emac.c   2003/12/19 17:39:44
***************
*** 242,247 ****
--- 242,250 ----
  #define       EMAC_READ(sc, reg) \
        bus_space_read_stream_4((sc)->sc_st, (sc)->sc_sh, (reg))
  
+ #define EMAC_SET_FILTER(aht, category) \
+       (aht)[3 - ((category) >> 4)] |= 1 << ((category) & 0xf);
+ 
  static int    emac_match(struct device *, struct cfdata *, void *);
  static void   emac_attach(struct device *, struct device *, void *);
  
***************
*** 255,260 ****
--- 258,264 ----
  static void   emac_start(struct ifnet *);
  static void   emac_stop(struct ifnet *, int);
  static void   emac_watchdog(struct ifnet *);
+ static int    emac_set_filter(struct emac_softc *);
  
  static int    emac_wol_intr(void *);
  static int    emac_serr_intr(void *);
***************
*** 794,799 ****
--- 798,804 ----
         *      dealt with here!
         */
        EMAC_WRITE(sc, EMAC_RMR, RMR_IAE | RMR_RRP | RMR_SP |
+           (ifp->if_flags & IFF_PROMISC ? RMR_PME : 0) |
            (ifp->if_flags & IFF_BROADCAST ? RMR_BAE : 0));
  
        /*
***************
*** 1010,1020 ****
                         * Multicast list has changed; set the hardware filter
                         * accordingly.
                         */
! #if 0
!                       error = emac_set_filter(sc);    /* XXX not done yet */
! #else
!                       error = emac_init(ifp);
! #endif
                }
                break;
        }
--- 1015,1021 ----
                         * Multicast list has changed; set the hardware filter
                         * accordingly.
                         */
!                       error = emac_set_filter(sc);
                }
                break;
        }
***************
*** 1044,1049 ****
--- 1045,1107 ----
        /* set the MAL config register */
        mtdcr(DCR_MAL0_CFG, MAL0_CFG_PLBB | MAL0_CFG_OPBBL | MAL0_CFG_LEA |
            MAL0_CFG_SD | MAL0_CFG_PLBLT);
+ }
+ 
+ static int
+ emac_set_filter(struct emac_softc *sc)
+ {
+       struct ether_multistep step;
+       struct ether_multi *enm;
+       struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+       u_int32_t rmr, crc, gaht[4] = {0, 0, 0, 0};
+       int category, cnt = 0;
+ 
+       rmr = EMAC_READ(sc, EMAC_RMR);
+       rmr &= ~(RMR_PMME | RMR_MAE);
+       ifp->if_flags &= ~IFF_ALLMULTI;
+ 
+       ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
+       while (enm != NULL) {
+               if (memcmp(enm->enm_addrlo,
+                   enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
+                       /*
+                        * We must listen to a range of multicast addresses.
+                        * For now, just accept all multicasts, rather than
+                        * trying to set only those filter bits needed to match
+                        * the range.  (At this time, the only use of address
+                        * ranges is for IP multicast routing, for which the
+                        * range is big enough to require all bits set.)
+                        */
+                       gaht[0] = gaht[1] = gaht[2] = gaht[3] = 0xffff;
+                       break;
+               }
+ 
+               crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
+ 
+               /* Just want the 6 most significant bits. */
+               category = crc >> 26;
+               EMAC_SET_FILTER(gaht, category);
+ 
+               ETHER_NEXT_MULTI(step, enm);
+               cnt ++;
+       }
+ 
+       if ((gaht[0] & gaht[1] & gaht[2] & gaht[3]) == 0xffff) {
+               /* all category is true */
+               ifp->if_flags |= IFF_ALLMULTI;
+               rmr |= RMR_PMME;
+       } else if (cnt != 0) {
+               /* some category is true */
+               EMAC_WRITE(sc, EMAC_GAHT1, gaht[0]); 
+               EMAC_WRITE(sc, EMAC_GAHT2, gaht[1]);
+               EMAC_WRITE(sc, EMAC_GAHT3, gaht[2]);
+               EMAC_WRITE(sc, EMAC_GAHT4, gaht[3]);
+ 
+               rmr |= RMR_MAE;
+       }
+       EMAC_WRITE(sc, EMAC_RMR, rmr);
+ 
+       return (0);
  }
  
  /*
>Release-Note:
>Audit-Trail:
>Unformatted: