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