Rewrite RX filter logic and provide controller specific filter
handler for 3C90x and 3C90xB/C respectively. This simplifies ioctl handler as well as enhancing readability. While I'm here don't reprogram multicast filter when driver is not running.
This commit is contained in:
parent
d2d0470dc6
commit
dd0a76883f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=221555
@ -263,10 +263,11 @@ static void xl_mii_send(struct xl_softc *, u_int32_t, int);
|
||||
static int xl_mii_readreg(struct xl_softc *, struct xl_mii_frame *);
|
||||
static int xl_mii_writereg(struct xl_softc *, struct xl_mii_frame *);
|
||||
|
||||
static void xl_rxfilter(struct xl_softc *);
|
||||
static void xl_rxfilter_90x(struct xl_softc *);
|
||||
static void xl_rxfilter_90xB(struct xl_softc *);
|
||||
static void xl_setcfg(struct xl_softc *);
|
||||
static void xl_setmode(struct xl_softc *, int);
|
||||
static void xl_setmulti(struct xl_softc *);
|
||||
static void xl_setmulti_hash(struct xl_softc *);
|
||||
static void xl_reset(struct xl_softc *);
|
||||
static int xl_list_rx_init(struct xl_softc *);
|
||||
static int xl_list_tx_init(struct xl_softc *);
|
||||
@ -701,101 +702,133 @@ xl_read_eeprom(struct xl_softc *sc, caddr_t dest, int off, int cnt, int swap)
|
||||
return (err ? 1 : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
xl_rxfilter(struct xl_softc *sc)
|
||||
{
|
||||
|
||||
if (sc->xl_type == XL_TYPE_905B)
|
||||
xl_rxfilter_90xB(sc);
|
||||
else
|
||||
xl_rxfilter_90x(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* NICs older than the 3c905B have only one multicast option, which
|
||||
* is to enable reception of all multicast frames.
|
||||
*/
|
||||
static void
|
||||
xl_setmulti(struct xl_softc *sc)
|
||||
xl_rxfilter_90x(struct xl_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = sc->xl_ifp;
|
||||
struct ifnet *ifp;
|
||||
struct ifmultiaddr *ifma;
|
||||
u_int8_t rxfilt;
|
||||
int mcnt = 0;
|
||||
|
||||
XL_LOCK_ASSERT(sc);
|
||||
|
||||
ifp = sc->xl_ifp;
|
||||
|
||||
XL_SEL_WIN(5);
|
||||
rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
|
||||
rxfilt &= ~(XL_RXFILTER_ALLFRAMES | XL_RXFILTER_ALLMULTI |
|
||||
XL_RXFILTER_BROADCAST | XL_RXFILTER_INDIVIDUAL);
|
||||
|
||||
if (ifp->if_flags & IFF_ALLMULTI) {
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
return;
|
||||
/* Set the individual bit to receive frames for this host only. */
|
||||
rxfilt |= XL_RXFILTER_INDIVIDUAL;
|
||||
/* Set capture broadcast bit to capture broadcast frames. */
|
||||
if (ifp->if_flags & IFF_BROADCAST)
|
||||
rxfilt |= XL_RXFILTER_BROADCAST;
|
||||
|
||||
/* If we want promiscuous mode, set the allframes bit. */
|
||||
if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
|
||||
if (ifp->if_flags & IFF_PROMISC)
|
||||
rxfilt |= XL_RXFILTER_ALLFRAMES;
|
||||
if (ifp->if_flags & IFF_ALLMULTI)
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
} else {
|
||||
if_maddr_rlock(ifp);
|
||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
break;
|
||||
}
|
||||
if_maddr_runlock(ifp);
|
||||
}
|
||||
|
||||
if_maddr_rlock(ifp);
|
||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
|
||||
mcnt++;
|
||||
if_maddr_runlock(ifp);
|
||||
|
||||
if (mcnt)
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
else
|
||||
rxfilt &= ~XL_RXFILTER_ALLMULTI;
|
||||
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
CSR_WRITE_2(sc, XL_COMMAND, rxfilt | XL_CMD_RX_SET_FILT);
|
||||
XL_SEL_WIN(7);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3c905B adapters have a hash filter that we can program.
|
||||
*/
|
||||
static void
|
||||
xl_setmulti_hash(struct xl_softc *sc)
|
||||
xl_rxfilter_90xB(struct xl_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = sc->xl_ifp;
|
||||
int h = 0, i;
|
||||
struct ifnet *ifp;
|
||||
struct ifmultiaddr *ifma;
|
||||
int i, mcnt;
|
||||
u_int16_t h;
|
||||
u_int8_t rxfilt;
|
||||
int mcnt = 0;
|
||||
|
||||
XL_LOCK_ASSERT(sc);
|
||||
|
||||
ifp = sc->xl_ifp;
|
||||
|
||||
XL_SEL_WIN(5);
|
||||
rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
|
||||
rxfilt &= ~(XL_RXFILTER_ALLFRAMES | XL_RXFILTER_ALLMULTI |
|
||||
XL_RXFILTER_BROADCAST | XL_RXFILTER_INDIVIDUAL |
|
||||
XL_RXFILTER_MULTIHASH);
|
||||
|
||||
if (ifp->if_flags & IFF_ALLMULTI) {
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
return;
|
||||
} else
|
||||
rxfilt &= ~XL_RXFILTER_ALLMULTI;
|
||||
/* Set the individual bit to receive frames for this host only. */
|
||||
rxfilt |= XL_RXFILTER_INDIVIDUAL;
|
||||
/* Set capture broadcast bit to capture broadcast frames. */
|
||||
if (ifp->if_flags & IFF_BROADCAST)
|
||||
rxfilt |= XL_RXFILTER_BROADCAST;
|
||||
|
||||
/* first, zot all the existing hash bits */
|
||||
for (i = 0; i < XL_HASHFILT_SIZE; i++)
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);
|
||||
/* If we want promiscuous mode, set the allframes bit. */
|
||||
if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
|
||||
if (ifp->if_flags & IFF_PROMISC)
|
||||
rxfilt |= XL_RXFILTER_ALLFRAMES;
|
||||
if (ifp->if_flags & IFF_ALLMULTI)
|
||||
rxfilt |= XL_RXFILTER_ALLMULTI;
|
||||
} else {
|
||||
/* First, zot all the existing hash bits. */
|
||||
for (i = 0; i < XL_HASHFILT_SIZE; i++)
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH | i);
|
||||
|
||||
/* now program new ones */
|
||||
if_maddr_rlock(ifp);
|
||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
/*
|
||||
* Note: the 3c905B currently only supports a 64-bit hash
|
||||
* table, which means we really only need 6 bits, but the
|
||||
* manual indicates that future chip revisions will have a
|
||||
* 256-bit hash table, hence the routine is set up to
|
||||
* calculate 8 bits of position info in case we need it some
|
||||
* day.
|
||||
* Note II, The Sequel: _CURRENT_ versions of the 3c905B have
|
||||
* a 256 bit hash table. This means we have to use all 8 bits
|
||||
* regardless. On older cards, the upper 2 bits will be
|
||||
* ignored. Grrrr....
|
||||
*/
|
||||
h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
|
||||
ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
|
||||
CSR_WRITE_2(sc, XL_COMMAND,
|
||||
h | XL_CMD_RX_SET_HASH | XL_HASH_SET);
|
||||
mcnt++;
|
||||
/* Now program new ones. */
|
||||
mcnt = 0;
|
||||
if_maddr_rlock(ifp);
|
||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
/*
|
||||
* Note: the 3c905B currently only supports a 64-bit
|
||||
* hash table, which means we really only need 6 bits,
|
||||
* but the manual indicates that future chip revisions
|
||||
* will have a 256-bit hash table, hence the routine
|
||||
* is set up to calculate 8 bits of position info in
|
||||
* case we need it some day.
|
||||
* Note II, The Sequel: _CURRENT_ versions of the
|
||||
* 3c905B have a 256 bit hash table. This means we have
|
||||
* to use all 8 bits regardless. On older cards, the
|
||||
* upper 2 bits will be ignored. Grrrr....
|
||||
*/
|
||||
h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
|
||||
ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
|
||||
CSR_WRITE_2(sc, XL_COMMAND,
|
||||
h | XL_CMD_RX_SET_HASH | XL_HASH_SET);
|
||||
mcnt++;
|
||||
}
|
||||
if_maddr_runlock(ifp);
|
||||
if (mcnt > 0)
|
||||
rxfilt |= XL_RXFILTER_MULTIHASH;
|
||||
}
|
||||
if_maddr_runlock(ifp);
|
||||
|
||||
if (mcnt)
|
||||
rxfilt |= XL_RXFILTER_MULTIHASH;
|
||||
else
|
||||
rxfilt &= ~XL_RXFILTER_MULTIHASH;
|
||||
|
||||
CSR_WRITE_2(sc, XL_COMMAND, rxfilt | XL_CMD_RX_SET_FILT);
|
||||
XL_SEL_WIN(7);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2763,7 +2796,6 @@ xl_init_locked(struct xl_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = sc->xl_ifp;
|
||||
int error, i;
|
||||
u_int16_t rxfilt = 0;
|
||||
struct mii_data *mii = NULL;
|
||||
|
||||
XL_LOCK_ASSERT(sc);
|
||||
@ -2862,39 +2894,7 @@ xl_init_locked(struct xl_softc *sc)
|
||||
}
|
||||
|
||||
/* Set RX filter bits. */
|
||||
XL_SEL_WIN(5);
|
||||
rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
|
||||
|
||||
/* Set the individual bit to receive frames for this host only. */
|
||||
rxfilt |= XL_RXFILTER_INDIVIDUAL;
|
||||
|
||||
/* If we want promiscuous mode, set the allframes bit. */
|
||||
if (ifp->if_flags & IFF_PROMISC) {
|
||||
rxfilt |= XL_RXFILTER_ALLFRAMES;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
} else {
|
||||
rxfilt &= ~XL_RXFILTER_ALLFRAMES;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set capture broadcast bit to capture broadcast frames.
|
||||
*/
|
||||
if (ifp->if_flags & IFF_BROADCAST) {
|
||||
rxfilt |= XL_RXFILTER_BROADCAST;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
} else {
|
||||
rxfilt &= ~XL_RXFILTER_BROADCAST;
|
||||
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Program the multicast filter, if necessary.
|
||||
*/
|
||||
if (sc->xl_type == XL_TYPE_905B)
|
||||
xl_setmulti_hash(sc);
|
||||
else
|
||||
xl_setmulti(sc);
|
||||
xl_rxfilter(sc);
|
||||
|
||||
/*
|
||||
* Load the address of the RX list. We have to
|
||||
@ -3123,30 +3123,16 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
struct ifreq *ifr = (struct ifreq *) data;
|
||||
int error = 0, mask;
|
||||
struct mii_data *mii = NULL;
|
||||
u_int8_t rxfilt;
|
||||
|
||||
switch (command) {
|
||||
case SIOCSIFFLAGS:
|
||||
XL_LOCK(sc);
|
||||
|
||||
XL_SEL_WIN(5);
|
||||
rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
|
||||
if (ifp->if_flags & IFF_UP) {
|
||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
|
||||
ifp->if_flags & IFF_PROMISC &&
|
||||
!(sc->xl_if_flags & IFF_PROMISC)) {
|
||||
rxfilt |= XL_RXFILTER_ALLFRAMES;
|
||||
CSR_WRITE_2(sc, XL_COMMAND,
|
||||
XL_CMD_RX_SET_FILT|rxfilt);
|
||||
XL_SEL_WIN(7);
|
||||
} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
|
||||
!(ifp->if_flags & IFF_PROMISC) &&
|
||||
sc->xl_if_flags & IFF_PROMISC) {
|
||||
rxfilt &= ~XL_RXFILTER_ALLFRAMES;
|
||||
CSR_WRITE_2(sc, XL_COMMAND,
|
||||
XL_CMD_RX_SET_FILT|rxfilt);
|
||||
XL_SEL_WIN(7);
|
||||
} else
|
||||
(ifp->if_flags ^ sc->xl_if_flags) &
|
||||
(IFF_PROMISC | IFF_ALLMULTI))
|
||||
xl_rxfilter(sc);
|
||||
else
|
||||
xl_init_locked(sc);
|
||||
} else {
|
||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
@ -3154,18 +3140,14 @@ xl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
}
|
||||
sc->xl_if_flags = ifp->if_flags;
|
||||
XL_UNLOCK(sc);
|
||||
error = 0;
|
||||
break;
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
/* XXX Downcall from if_addmulti() possibly with locks held. */
|
||||
XL_LOCK(sc);
|
||||
if (sc->xl_type == XL_TYPE_905B)
|
||||
xl_setmulti_hash(sc);
|
||||
else
|
||||
xl_setmulti(sc);
|
||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
xl_rxfilter(sc);
|
||||
XL_UNLOCK(sc);
|
||||
error = 0;
|
||||
break;
|
||||
case SIOCGIFMEDIA:
|
||||
case SIOCSIFMEDIA:
|
||||
|
Loading…
Reference in New Issue
Block a user