sk driver (yukon based card) and multicast
Keith Mitchell
kmitch at guru.org
Wed Dec 17 07:00:31 PST 2003
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 at guru.org PGP key available upon request
-------------- next part --------------
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;
! }
}
}
More information about the freebsd-current
mailing list