On Mon 13 Dec 2021 at 19:08:25 +0100, Anders Magnusson wrote: > Hi, > > 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. My first proof of concept I copied the code, so I know that it works. It amounts to this below. The lance_setladrf() will need to be renamed or made static to avoid clashing with the original copy. /* * 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; #ifdef m68k /* * The post-increment-pointer form produces the best * machine code for m68k. This was carefully tuned * so it compiles to just 8 short (2-byte) op-codes! */ diff = *a++ - *b++; diff |= *a++ - *b++; diff |= *a++ - *b++; #else /* * 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]); #endif 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; } -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