void smsc_setmulti(struct smsc_softc *sc) { struct ifnet *ifp = &sc->sc_ec.ec_if; struct ether_multi *enm; struct ether_multistep step; uint32_t hashtbl[2] = { 0, 0 }; uint32_t hash; if (sc->sc_dying) return; if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { allmulti: smsc_dbg_printf(sc, "receive all multicast enabled\n"); sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); return; } else { sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); } ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); while (enm != NULL) { if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN) != 0) goto allmulti; hash = smsc_hash(enm->enm_addrlo); hashtbl[hash >> 5] |= 1 << (hash & 0x1F); ETHER_NEXT_MULTI(step, enm); } /* Debug */ if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { smsc_dbg_printf(sc, "receive select group of macs\n"); } else { smsc_dbg_printf(sc, "receive own packets only\n"); } /* Write the hash table and mac control registers */ ifp->if_flags &= ~IFF_ALLMULTI; smsc_write_reg(sc, SMSC_HASHH, hashtbl[1]); smsc_write_reg(sc, SMSC_HASHL, hashtbl[0]); smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); }
void smsc_iff(struct smsc_softc *sc) { struct ifnet *ifp = &sc->sc_ac.ac_if; struct arpcom *ac = &sc->sc_ac; struct ether_multi *enm; struct ether_multistep step; uint32_t hashtbl[2] = { 0, 0 }; uint32_t hash; if (usbd_is_dying(sc->sc_udev)) return; sc->sc_mac_csr &= ~(SMSC_MAC_CSR_HPFILT | SMSC_MAC_CSR_MCPAS | SMSC_MAC_CSR_PRMS); ifp->if_flags &= ~IFF_ALLMULTI; if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { ifp->if_flags |= IFF_ALLMULTI; sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; if (ifp->if_flags & IFF_PROMISC) sc->sc_mac_csr |= SMSC_MAC_CSR_PRMS; } else { sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { hash = smsc_hash(enm->enm_addrlo); hashtbl[hash >> 5] |= 1 << (hash & 0x1F); ETHER_NEXT_MULTI(step, enm); } } /* Debug */ if (sc->sc_mac_csr & SMSC_MAC_CSR_MCPAS) smsc_dbg_printf(sc, "receive all multicast enabled\n"); else if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) smsc_dbg_printf(sc, "receive select group of macs\n"); /* Write the hash table and mac control registers */ smsc_write_reg(sc, SMSC_HASHH, hashtbl[1]); smsc_write_reg(sc, SMSC_HASHL, hashtbl[0]); smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); }
int smsc_setmacaddress(struct smsc_softc *sc, const uint8_t *addr) { int err; uint32_t val; smsc_dbg_printf(sc, "setting mac address to " "%02x:%02x:%02x:%02x:%02x:%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); val = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; if ((err = smsc_write_reg(sc, SMSC_MAC_ADDRL, val)) != 0) goto done; val = (addr[5] << 8) | addr[4]; err = smsc_write_reg(sc, SMSC_MAC_ADDRH, val); done: return (err); }
void smsc_miibus_statchg(struct device *dev) { struct smsc_softc *sc = (struct smsc_softc *)dev; struct mii_data *mii = &sc->sc_mii; struct ifnet *ifp = &sc->sc_ac.ac_if; int err; uint32_t flow; uint32_t afc_cfg; if (mii == NULL || ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) return; /* Use the MII status to determine link status */ sc->sc_flags &= ~SMSC_FLAG_LINK; if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == (IFM_ACTIVE | IFM_AVALID)) { switch (IFM_SUBTYPE(mii->mii_media_active)) { case IFM_10_T: case IFM_100_TX: sc->sc_flags |= SMSC_FLAG_LINK; break; case IFM_1000_T: /* Gigabit ethernet not supported by chipset */ break; default: break; } } /* Lost link, do nothing. */ if ((sc->sc_flags & SMSC_FLAG_LINK) == 0) { smsc_dbg_printf(sc, "link flag not set\n"); return; } err = smsc_read_reg(sc, SMSC_AFC_CFG, &afc_cfg); if (err) { smsc_warn_printf(sc, "failed to read initial AFC_CFG, " "error %d\n", err); return; } /* Enable/disable full duplex operation and TX/RX pause */ if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { smsc_dbg_printf(sc, "full duplex operation\n"); sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) flow = 0xffff0002; else flow = 0; if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) afc_cfg |= 0xf; else afc_cfg &= ~0xf; } else { smsc_dbg_printf(sc, "half duplex operation\n"); sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; flow = 0; afc_cfg |= 0xf; } err = smsc_write_reg(sc, SMSC_MAC_CSR, sc->sc_mac_csr); err += smsc_write_reg(sc, SMSC_FLOW, flow); err += smsc_write_reg(sc, SMSC_AFC_CFG, afc_cfg); if (err) smsc_warn_printf(sc, "media change failed, error %d\n", err); }