Date: Wed, 17 Dec 2003 09:59:24 -0500 From: Keith Mitchell <kmitch@guru.org> To: freebsd-current@freebsd.org, freebsd-hardware@freebsd.org Subject: sk driver (yukon based card) and multicast Message-ID: <20031217145924.GA12258@weenix.guru.org>
next in thread | raw e-mail | index | archive | help
--vtzGhvizbBRQ85DL Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, I just got a couple of Linksys EG1032 cards that are based on the Marvell Yukon Chipset. I built a kernel with the sk driver in it and the basic stuff seemed to work fine, but multicast didn't work at all unless I was also running tcpdump (i.e. promiscuous mode was turned on). I traced this down to the hash calculation routine used to program the GMAC on the Yukon controller. Apparently the Yukon chip uses a different algorithm than the XMAC (Genesis chipset) uses. I ported the algorithm used by the linux driver over and now it seems to work fine. The diffs are attached. -- Keith Mitchell Email: kmitch@guru.org PGP key available upon request --vtzGhvizbBRQ85DL Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="sk.diff" Index: if_sk.c =================================================================== RCS file: /pub/cvs/src/sys/pci/if_sk.c,v retrieving revision 1.19.2.10 diff -c -r1.19.2.10 if_sk.c *** if_sk.c 14 Oct 2003 18:22:42 -0000 1.19.2.10 --- if_sk.c 17 Dec 2003 14:52:14 -0000 *************** *** 214,220 **** int)); static void sk_marv_miibus_statchg __P((struct sk_if_softc *)); ! static u_int32_t sk_calchash __P((caddr_t)); static void sk_setfilt __P((struct sk_if_softc *, caddr_t, int)); static void sk_setmulti __P((struct sk_if_softc *)); --- 219,226 ---- int)); static void sk_marv_miibus_statchg __P((struct sk_if_softc *)); ! static u_int32_t xmac_calchash __P((caddr_t)); ! static u_int32_t gmac_calchash __P((caddr_t)); static void sk_setfilt __P((struct sk_if_softc *, caddr_t, int)); static void sk_setmulti __P((struct sk_if_softc *)); *************** *** 668,677 **** return; } ! #define SK_POLY 0xEDB88320 ! #define SK_BITS 6 ! static u_int32_t sk_calchash(addr) caddr_t addr; { u_int32_t idx, bit, data, crc; --- 674,684 ---- return; } ! #define XMAC_POLY 0xEDB88320 ! #define GMAC_POLY 0x04C11DB7L ! #define HASH_BITS 6 ! static u_int32_t xmac_calchash(addr) caddr_t addr; { u_int32_t idx, bit, data, crc; *************** *** 681,690 **** for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) ! crc = (crc >> 1) ^ (((crc ^ data) & 1) ? SK_POLY : 0); } ! return (~crc & ((1 << SK_BITS) - 1)); } static void sk_setfilt(sc_if, addr, slot) --- 688,734 ---- for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) ! crc = (crc >> 1) ^ (((crc ^ data) & 1) ? XMAC_POLY : 0); } ! return (~crc & ((1 << HASH_BITS) - 1)); ! } ! ! static u_int32_t gmac_calchash(addr) ! caddr_t addr; ! { ! u_int32_t idx, bit, crc, tmpData, data; ! ! /* Compute CRC for the address value. */ ! crc = 0xFFFFFFFF; /* initial value */ ! ! for (idx = 0; idx < 6; idx++) { ! data = *addr++; ! ! /* Change bit order in byte. */ ! tmpData = data; ! for (bit = 0; bit < 8; bit++) { ! if (tmpData & 1) { ! data |= 1 << (7 - bit); ! } ! else { ! data &= ~(1 << (7 - bit)); ! } ! ! tmpData >>= 1; ! } ! ! crc ^= (data << 24); ! for (bit = 0; bit < 8; bit++) { ! if (crc & 0x80000000) { ! crc = (crc << 1) ^ GMAC_POLY; ! } else { ! crc <<= 1; ! } ! } ! } ! ! return (crc & ((1 << HASH_BITS) - 1)); } static void sk_setfilt(sc_if, addr, slot) *************** *** 760,771 **** continue; } ! h = sk_calchash( ! LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); ! if (h < 32) ! hashes[0] |= (1 << h); ! else ! hashes[1] |= (1 << (h - 32)); } } --- 804,828 ---- continue; } ! switch(sc->sk_type) { ! case SK_GENESIS: ! h = xmac_calchash( ! LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); ! if (h < 32) ! hashes[0] |= (1 << h); ! else ! hashes[1] |= (1 << (h - 32)); ! break; ! ! case SK_YUKON: ! h = gmac_calchash( ! LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); ! if (h < 32) ! hashes[0] |= (1 << h); ! else ! hashes[1] |= (1 << (h - 32)); ! break; ! } } } --vtzGhvizbBRQ85DL--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20031217145924.GA12258>