From 195be17bb9be8739c7243b1534008acecf80c433 Mon Sep 17 00:00:00 2001 From: rhialto Date: Mon, 20 Dec 2021 17:12:41 +0000 Subject: [PATCH] Set up multicast (input) filter on qt (DELQA-Turbo). --- sys/dev/qbus/if_qt.c | 71 +++++++++++++++++++++++++++++++++++++++-- sys/dev/qbus/if_qtreg.h | 26 +++++++-------- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/sys/dev/qbus/if_qt.c b/sys/dev/qbus/if_qt.c index d631081c8d53..a993636566b1 100644 --- a/sys/dev/qbus/if_qt.c +++ b/sys/dev/qbus/if_qt.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_qt.c,v 1.25 2020/01/29 05:57:21 thorpej Exp $ */ +/* $NetBSD: if_qt.c,v 1.26 2021/12/20 17:12:41 rhialto Exp $ */ /* * Copyright (c) 1992 Steven M. Schultz * All rights reserved. @@ -80,7 +80,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_qt.c,v 1.25 2020/01/29 05:57:21 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_qt.c,v 1.26 2021/12/20 17:12:41 rhialto Exp $"); #include "opt_inet.h" @@ -162,6 +162,7 @@ struct qt_softc { 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,67 @@ qtturbo(struct qt_softc *sc) return(1); } +#define ETHER_CMP(a,b) memcmp((a), (b), 6) + +/* + * 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 +450,10 @@ qtinit(struct ifnet *ifp) } 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 diff --git a/sys/dev/qbus/if_qtreg.h b/sys/dev/qbus/if_qtreg.h index e2716ffac77a..3572e95695e5 100644 --- a/sys/dev/qbus/if_qtreg.h +++ b/sys/dev/qbus/if_qtreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_qtreg.h,v 1.5 2005/12/11 12:23:29 christos Exp $ */ +/* $NetBSD: if_qtreg.h,v 1.6 2021/12/20 17:12:41 rhialto Exp $ */ /* * Copyright (c) 1992 Steven M. Schultz * All rights reserved. @@ -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 */