xe(4) multicast filter fix
Christian Weisgerber
naddy at mips.inka.de
Thu Jun 3 19:50:40 GMT 2004
Our xe(4) multicast hash filter setup is particularly convoluted.
First a big-endian ethernet CRC is calculated, then the top six
bits are taken and reversed--i.e., we really just want the six lower
bits of a little-endian CRC. On top of that, a drunken commit in
revision 1.45 of if_xe.c broke the CRC calculation.
The patch below cuts through the whole mess by calling ether_crc32_le()
directly.
PLEASE TEST. I don't have access to xe(4) hardware.
Index: dev/xe/if_xe.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/xe/if_xe.c,v
retrieving revision 1.50
diff -u -r1.50 if_xe.c
--- dev/xe/if_xe.c 23 May 2004 16:11:53 -0000 1.50
+++ dev/xe/if_xe.c 3 Jun 2004 19:33:12 -0000
@@ -143,11 +143,6 @@
#define XE_AUTONEG_FAIL 4 /* Autonegotiation failed */
/*
- * Multicast hashing CRC constants
- */
-#define XE_CRC_POLY 0x04c11db6
-
-/*
* Prototypes start here
*/
static void xe_init (void *xscp);
@@ -1409,49 +1404,19 @@
*/
static void
xe_mchash(struct xe_softc* scp, const uint8_t *addr) {
- uint32_t crc = 0xffffffff;
- int idx, bit;
- uint8_t carry, byte, data, crc31, hash;
-
- /* Compute CRC of the address -- standard Ethernet CRC function */
- for (data = *addr++, idx = 0; idx < 6; idx++, data >>= 1) {
- for (bit = 1; bit <= 8; bit++) {
- if (crc & 0x80000000)
- crc31 = 0x01;
- else
- crc31 = 0;
- carry = crc31 ^ (data & 0x01);
- crc <<= 1;
- data >>= 1;
- crc = (crc ^ XE_CRC_POLY) | (carry|0x1);
- }
- }
+ int bit;
+ uint8_t byte, hash;
- DEVPRINTF(3, (scp->dev, "set_hash: CRC = 0x%08x\n", crc));
-
- /*
- * Convert a CRC into an index into the multicast hash table. What we do is
- * take the most-significant 6 bits of the CRC, reverse them, and use that as
- * the bit number in the hash table. Bits 5:3 of the result give the byte
- * within the table (0-7); bits 2:0 give the bit number within that byte (also
- * 0-7), ie. the number of shifts needed to get it into the lsb position.
- */
- for (idx = 0, hash = 0; idx < 6; idx++) {
- hash >>= 1;
- if (crc & 0x80000000) {
- hash |= 0x20;
- }
- crc <<= 1;
- }
+ hash = ether_crc32_le(addr, ETHER_ADDR_LEN) & 0x3F;
/* Top 3 bits of hash give register - 8, bottom 3 give bit within register */
byte = hash >> 3 | 0x08;
- carry = 0x01 << (hash & 0x07);
+ bit = 0x01 << (hash & 0x07);
- DEVPRINTF(3, (scp->dev, "set_hash: hash = 0x%02x, byte = 0x%02x, carry = 0x%02x\n", hash, byte, carry));
+ DEVPRINTF(3, (scp->dev, "set_hash: hash = 0x%02x, byte = 0x%02x, bit = 0x%02x\n", hash, byte, bit));
XE_SELECT_PAGE(0x58);
- XE_OUTB(byte, XE_INB(byte) | carry);
+ XE_OUTB(byte, XE_INB(byte) | bit);
}
--
Christian "naddy" Weisgerber naddy at mips.inka.de
More information about the freebsd-current
mailing list