summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2009-12-23 18:24:22 +0000
committeryongari <yongari@FreeBSD.org>2009-12-23 18:24:22 +0000
commit88a3836722325328a2c0354043bf45029b914c6b (patch)
tree85fc42d6633d36e4ac5dc7ad7adfba58cea5c63d
parentdc94299fa0109c531087d1d3e7bd195fa0226d3c (diff)
downloadFreeBSD-src-88a3836722325328a2c0354043bf45029b914c6b.zip
FreeBSD-src-88a3836722325328a2c0354043bf45029b914c6b.tar.gz
Overhaul RX filter programming.
o Let RX filter handler program promiscuous/multicast filter as well as broadcasting. o Remove unnecessary register access. o Simplify ioctl handler and have set_rxfilter to handle IFF_PROMISC and IFF_ALLMULTI change instead of directly programming the controller. o Removed unnecessary error variable reinitialization in ioctl handler. o Add IFF_DRV_RUNNING check before programming multicast filter. o Configure maximum allowed frame length before enabling MAC. Datasheet didn't say the exact ordering of programming sequence but it looks more natural to set maximum allowed frame length first prior to enabling controller.
-rw-r--r--sys/dev/ste/if_ste.c100
1 files changed, 38 insertions, 62 deletions
diff --git a/sys/dev/ste/if_ste.c b/sys/dev/ste/if_ste.c
index 7249f84..b2cb4d5 100644
--- a/sys/dev/ste/if_ste.c
+++ b/sys/dev/ste/if_ste.c
@@ -123,7 +123,7 @@ static int ste_read_eeprom(struct ste_softc *, caddr_t, int, int, int);
static void ste_reset(struct ste_softc *);
static void ste_restart_tx(struct ste_softc *);
static int ste_rxeof(struct ste_softc *, int);
-static void ste_setmulti(struct ste_softc *);
+static void ste_rxfilter(struct ste_softc *);
static void ste_start(struct ifnet *);
static void ste_start_locked(struct ifnet *);
static void ste_stats_update(struct ste_softc *);
@@ -563,27 +563,33 @@ ste_read_eeprom(struct ste_softc *sc, caddr_t dest, int off, int cnt, int swap)
}
static void
-ste_setmulti(struct ste_softc *sc)
+ste_rxfilter(struct ste_softc *sc)
{
struct ifnet *ifp;
struct ifmultiaddr *ifma;
uint32_t hashes[2] = { 0, 0 };
+ uint8_t rxcfg;
int h;
- ifp = sc->ste_ifp;
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
- return;
- }
-
- /* first, zot all the existing hash bits */
- CSR_WRITE_2(sc, STE_MAR0, 0);
- CSR_WRITE_2(sc, STE_MAR1, 0);
- CSR_WRITE_2(sc, STE_MAR2, 0);
- CSR_WRITE_2(sc, STE_MAR3, 0);
+ STE_LOCK_ASSERT(sc);
- /* now program new ones */
+ ifp = sc->ste_ifp;
+ rxcfg = CSR_READ_1(sc, STE_RX_MODE);
+ rxcfg |= STE_RXMODE_UNICAST;
+ rxcfg &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_MULTIHASH |
+ STE_RXMODE_BROADCAST | STE_RXMODE_PROMISC);
+ if (ifp->if_flags & IFF_BROADCAST)
+ rxcfg |= STE_RXMODE_BROADCAST;
+ if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
+ if ((ifp->if_flags & IFF_ALLMULTI) != 0)
+ rxcfg |= STE_RXMODE_ALLMULTI;
+ if ((ifp->if_flags & IFF_PROMISC) != 0)
+ rxcfg |= STE_RXMODE_PROMISC;
+ goto chipit;
+ }
+
+ rxcfg |= STE_RXMODE_MULTIHASH;
+ /* Now program new ones. */
if_maddr_rlock(ifp);
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
@@ -597,12 +603,13 @@ ste_setmulti(struct ste_softc *sc)
}
if_maddr_runlock(ifp);
+chipit:
CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_ALLMULTI);
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_MULTIHASH);
+ CSR_WRITE_1(sc, STE_RX_MODE, rxcfg);
+ CSR_READ_1(sc, STE_RX_MODE);
}
#ifdef DEVICE_POLLING
@@ -1590,24 +1597,11 @@ ste_init_locked(struct ste_softc *sc)
/* Set the TX reclaim threshold. */
CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (STE_PACKET_SIZE >> 4));
- /* Set up the RX filter. */
- CSR_WRITE_1(sc, STE_RX_MODE, STE_RXMODE_UNICAST);
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
- } else {
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_PROMISC);
- }
-
- /* Set capture broadcast bit to accept broadcast frames. */
- if (ifp->if_flags & IFF_BROADCAST) {
- STE_SETBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
- } else {
- STE_CLRBIT1(sc, STE_RX_MODE, STE_RXMODE_BROADCAST);
- }
+ /* Accept VLAN length packets */
+ CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
- ste_setmulti(sc);
+ /* Set up the RX filter. */
+ ste_rxfilter(sc);
/* Load the address of the RX list. */
STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
@@ -1647,9 +1641,6 @@ ste_init_locked(struct ste_softc *sc)
/* Enable interrupts. */
CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
- /* Accept VLAN length packets */
- CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
-
ste_ifmedia_upd_locked(ifp);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -1792,39 +1783,24 @@ ste_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
switch (command) {
case SIOCSIFFLAGS:
STE_LOCK(sc);
- if (ifp->if_flags & IFF_UP) {
- if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- ifp->if_flags & IFF_PROMISC &&
- !(sc->ste_if_flags & IFF_PROMISC)) {
- STE_SETBIT1(sc, STE_RX_MODE,
- STE_RXMODE_PROMISC);
- } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- !(ifp->if_flags & IFF_PROMISC) &&
- sc->ste_if_flags & IFF_PROMISC) {
- STE_CLRBIT1(sc, STE_RX_MODE,
- STE_RXMODE_PROMISC);
- }
- if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
- (ifp->if_flags ^ sc->ste_if_flags) & IFF_ALLMULTI)
- ste_setmulti(sc);
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
- sc->ste_tx_thresh = STE_TXSTART_THRESH;
+ if ((ifp->if_flags & IFF_UP) != 0) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
+ ((ifp->if_flags ^ sc->ste_if_flags) &
+ (IFF_PROMISC | IFF_ALLMULTI)) != 0)
+ ste_rxfilter(sc);
+ else
ste_init_locked(sc);
- }
- } else {
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- ste_stop(sc);
- }
+ } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ ste_stop(sc);
sc->ste_if_flags = ifp->if_flags;
STE_UNLOCK(sc);
- error = 0;
break;
case SIOCADDMULTI:
case SIOCDELMULTI:
STE_LOCK(sc);
- ste_setmulti(sc);
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ ste_rxfilter(sc);
STE_UNLOCK(sc);
- error = 0;
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
OpenPOWER on IntegriCloud