On Mon 13 Dec 2021 at 19:08:25 +0100, Anders Magnusson wrote: > good start, but I think it would be a bad idea to require to include the > lance code just for the multicast hash. > I assume that what you really want is to call the function ether_crc32_le() > which is already included. The GENERIC code already contains the lance code, probably at least because of sys/arch/vax/if/if_le.c, so for GENERIC it wastes a bit of space to make a copy. For a trimmed down kernel it is a win, though. I trimmed out the m68k code variant though, since I don't expect this file to be compiled on a m68k cpu (but there are le drivers for m68k in e.g. sys/arch/mvme68k/dev/if_le.c and sys/arch/sun3/dev/if_le.c, so the code works regardless of endianness). Unless somebody tells me this is bad to do I propose to commit it early next week or so. I was made aware of the "ifmcstat" commaand to tell me about multicast addresses that should be associated with interfaces. localhost# ifmcstat qt0: inet6 fe80::a00:2bff:feaf:2ce8%qt0 group ff02::2:65d0:d71e%qt0 refcount 1 group ff02::1:ff2e:f242%qt0 refcount 1 group ff01:1::1 refcount 3 group ff02::1%qt0 refcount 3 group ff02::1:ffaf:2ce8%qt0 refcount 2 enaddr 08:00:2b:af:2c:e8: multicnt 5 33:33:65:d0:d7:1e: -- 33:33:65:d0:d7:1e: 1 01:00:5e:00:00:01: -- 01:00:5e:00:00:01: 1 33:33:ff:2e:f2:42: -- 33:33:ff:2e:f2:42: 1 33:33:00:00:00:01: -- 33:33:00:00:00:01: 2 33:33:ff:af:2c:e8: -- 33:33:ff:af:2c:e8: 1 lo0: inet6 ::1 group ff01:2::1 refcount 2 group ff02::1%lo0 refcount 2 group ff02::1:ff00:1%lo0 refcount 2 localhost# Simulation stopped, PC: 801A1A0F (MTPR R0,#12) sim> show xq filter Physical Address=08:00:2B:AF:2C:E8 Multicast Hash: 00 00 80 40 80 10 40 00 33:33:* are for IPv6, and 01:00:5e:* for IPv4, and the number of addresses matches the number of bits in the hash. So the patch is now like this: cvs diff: Diffing dev/qbus Index: dev/qbus/if_qt.c =================================================================== RCS file: /cvsroot/src/sys/dev/qbus/if_qt.c,v retrieving revision 1.25 diff -u -r1.25 if_qt.c --- dev/qbus/if_qt.c 29 Jan 2020 05:57:21 -0000 1.25 +++ dev/qbus/if_qt.c 14 Dec 2021 14:37:48 -0000 @@ -162,6 +162,7 @@ static int qtmatch(device_t, cfdata_t, void *); static void qtattach(device_t, device_t, void *); +static void lance_setladrf(struct ethercom *ec, uint16_t *af); static void qtintr(void *); static int qtinit(struct ifnet *); static int qtioctl(struct ifnet *, u_long, void *); @@ -332,6 +333,98 @@ return(1); } +/* + * Compare two Ether/802 addresses for equality, inlined and + * unrolled for speed. Use this like memcmp(). + * + * XXX: Add <machine/inlines.h> for stuff like this? + * XXX: or maybe add it to libkern.h instead? + * + * "I'd love to have an inline assembler version of this." + * XXX: Who wanted that? mycroft? I wrote one, but this + * version in C is as good as hand-coded assembly. -gwr + * + * Please do NOT tweak this without looking at the actual + * assembly code generated before and after your tweaks! + */ +static inline uint16_t +ether_cmp(void *one, void *two) +{ + uint16_t *a = (uint16_t *)one; + uint16_t *b = (uint16_t *)two; + uint16_t diff; + + /* + * Most modern CPUs do better with a single expression. + * Note that short-cut evaluation is NOT helpful here, + * because it just makes the code longer, not faster! + */ + diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); + + return (diff); +} + +#define ETHER_CMP ether_cmp + +/* + * Set up the logical address filter. + */ +void +lance_setladrf(struct ethercom *ec, uint16_t *af) +{ + struct ifnet *ifp = &ec->ec_if; + struct ether_multi *enm; + uint32_t crc; + struct ether_multistep step; + + /* + * Set up multicast address filter by passing all multicast addresses + * through a crc generator, and then using the high order 6 bits as an + * index into the 64 bit logical address filter. The high order bit + * selects the word, while the rest of the bits select the bit within + * the word. + */ + + if (ifp->if_flags & IFF_PROMISC) + goto allmulti; + + af[0] = af[1] = af[2] = af[3] = 0x0000; + + ETHER_LOCK(ec); + ETHER_FIRST_MULTI(step, ec, enm); + while (enm != NULL) { + if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { + /* + * 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.) + */ + ETHER_UNLOCK(ec); + goto allmulti; + } + + crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); + + /* Just want the 6 most significant bits. */ + crc >>= 26; + + /* Set the corresponding bit in the filter. */ + af[crc >> 4] |= 1 << (crc & 0xf); + + ETHER_NEXT_MULTI(step, enm); + } + ETHER_UNLOCK(ec); + ifp->if_flags &= ~IFF_ALLMULTI; + return; + +allmulti: + ifp->if_flags |= IFF_ALLMULTI; + af[0] = af[1] = af[2] = af[3] = 0xffff; +} + int qtinit(struct ifnet *ifp) { @@ -388,7 +481,10 @@ } iniblk = &sc->sc_ib->qc_init; iniblk->mode = ifp->if_flags & IFF_PROMISC ? INIT_MODE_PRO : 0; - +/* + * The multicast filter works "like LANCE". + */ + lance_setladrf(&sc->is_ec, iniblk->laddr); /* * Now initialize the receive ring descriptors. Because this routine can be Index: dev/qbus/if_qtreg.h =================================================================== RCS file: /cvsroot/src/sys/dev/qbus/if_qtreg.h,v retrieving revision 1.5 diff -u -r1.5 if_qtreg.h --- dev/qbus/if_qtreg.h 11 Dec 2005 12:23:29 -0000 1.5 +++ dev/qbus/if_qtreg.h 14 Dec 2021 14:37:48 -0000 @@ -207,18 +207,18 @@ struct qt_init { - short mode; - u_char paddr[6]; /* 48 bit physical address */ - u_char laddr[8]; /* 64 bit logical address filter */ - u_short rx_lo; /* low 16 bits of receive ring addr */ - u_short rx_hi; /* high 6 bits of receive ring addr */ - u_short tx_lo; /* low 16 bits of transmit ring addr */ - u_short tx_hi; /* high 6 bits of transmit ring addr */ - u_short options; - u_short vector; - u_short hit; - char passwd[6]; - char pad[4]; /* even on 40 byte for alignment */ + int16_t mode; + u_char paddr[6]; /* 48 bit physical address */ + uint16_t laddr[4]; /* 64 bit logical address filter */ + uint16_t rx_lo; /* low 16 bits of receive ring addr */ + uint16_t rx_hi; /* high 6 bits of receive ring addr */ + uint16_t tx_lo; /* low 16 bits of transmit ring addr */ + uint16_t tx_hi; /* high 6 bits of transmit ring addr */ + uint16_t options; + uint16_t vector; + uint16_t hit; + char passwd[6]; + char pad[4]; /* even on 40 byte for alignment */ }; #define INIT_MODE_PRO 0x8000 /* Promiscuous mode */ -Olaf. -- ___ "Buying carbon credits is a bit like a serial killer paying someone else to \X/ have kids to make his activity cost neutral." -The BOFH falu.nl@rhialto
Attachment:
signature.asc
Description: PGP signature