From owner-freebsd-current@FreeBSD.ORG Wed Dec 17 07:00:31 2003 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 34FDF16A4CF; Wed, 17 Dec 2003 07:00:31 -0800 (PST) Received: from weenix.guru.org (weenix.guru.org [24.199.153.98]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6E52543D5A; Wed, 17 Dec 2003 06:59:29 -0800 (PST) (envelope-from kmitch@guru.org) Received: from localhost (localhost.guru.org [127.0.0.1]) by weenix.guru.org (Postfix) with ESMTP id 8FDC5ACA94; Wed, 17 Dec 2003 09:59:26 -0500 (EST) Received: from weenix.guru.org ([127.0.0.1]) by localhost (weenix.guru.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 51079-04; Wed, 17 Dec 2003 09:59:24 -0500 (EST) Received: by weenix.guru.org (Postfix, from userid 3000) id 83450ACA96; Wed, 17 Dec 2003 09:59:24 -0500 (EST) Date: Wed, 17 Dec 2003 09:59:24 -0500 From: Keith Mitchell To: freebsd-current@freebsd.org, freebsd-hardware@freebsd.org Message-ID: <20031217145924.GA12258@weenix.guru.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="vtzGhvizbBRQ85DL" Content-Disposition: inline User-Agent: Mutt/1.4.1i X-Virus-Scanned: by amavisd-new at guru.org Subject: sk driver (yukon based card) and multicast X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Dec 2003 15:00:31 -0000 --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--