示例#1
0
Static void
url_setmulti(struct url_softc *sc)
{
	struct ifnet *ifp;
	struct ether_multi *enm;
	struct ether_multistep step;
	u_int32_t hashes[2] = { 0, 0 };
	int h = 0;
	int mcnt = 0;

	DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev), __func__));

	if (sc->sc_dying)
		return;

	ifp = GET_IFP(sc);

	if (ifp->if_flags & IFF_PROMISC) {
		URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);
		return;
	} else if (ifp->if_flags & IFF_ALLMULTI) {
	allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		URL_SETBIT2(sc, URL_RCR, URL_RCR_AAM);
		URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAP);
		return;
	}

	/* first, zot all the existing hash bits */
	url_csr_write_4(sc, URL_MAR0, 0);
	url_csr_write_4(sc, URL_MAR4, 0);

	/* now program new ones */
	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
			   ETHER_ADDR_LEN) != 0)
			goto allmulti;

		h = url_calchash(enm->enm_addrlo);
		if (h < 32)
			hashes[0] |= (1 << h);
		else
			hashes[1] |= (1 << (h -32));
		mcnt++;
		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	URL_CLRBIT2(sc, URL_RCR, URL_RCR_AAM|URL_RCR_AAP);

	if (mcnt){
		URL_SETBIT2(sc, URL_RCR, URL_RCR_AM);
	} else {
		URL_CLRBIT2(sc, URL_RCR, URL_RCR_AM);
	}
	url_csr_write_4(sc, URL_MAR0, hashes[0]);
	url_csr_write_4(sc, URL_MAR4, hashes[1]);
}
示例#2
0
/*
 * Set up the logical address filter.
 */
void
bmac_setladrf(struct bmac_softc *sc)
{
	struct arpcom *ac = &sc->arpcom;
	struct ifnet *ifp = &sc->arpcom.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	u_int32_t crc;
	u_int16_t hash[4];
	int x;

	/*
	 * 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) {
		bmac_set_bits(sc, RXCFG, RxPromiscEnable);
		return;
	}

	if (ac->ac_multirangecnt > 0)
		ifp->if_flags |= IFF_ALLMULTI;

	if (ifp->if_flags & IFF_ALLMULTI) {
		hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
		goto chipit;
	}

	hash[3] = hash[2] = hash[1] = hash[0] = 0;
	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		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. */
		hash[crc >> 4] |= 1 << (crc & 0xf);

		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

chipit:
	bmac_write_reg(sc, HASH0, hash[0]);
	bmac_write_reg(sc, HASH1, hash[1]);
	bmac_write_reg(sc, HASH2, hash[2]);
	bmac_write_reg(sc, HASH3, hash[3]);
	x = bmac_read_reg(sc, RXCFG);
	x &= ~RxPromiscEnable;
	x |= RxHashFilterEnable;
	bmac_write_reg(sc, RXCFG, x);
}
示例#3
0
/*
 * Program the 64-bit multicast hash filter.
 */
static void
vr_setmulti(struct vr_softc *sc)
{
	struct ifnet *ifp;
	int h = 0;
	uint32_t hashes[2] = { 0, 0 };
	struct ether_multistep step;
	struct ether_multi *enm;
	int mcnt = 0;
	uint8_t rxfilt;

	ifp = &sc->vr_ec.ec_if;

	rxfilt = CSR_READ_1(sc, VR_RXCFG);

	if (ifp->if_flags & IFF_PROMISC) {
allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		rxfilt |= VR_RXCFG_RX_MULTI;
		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
		CSR_WRITE_4(sc, VR_MAR1, 0xFFFFFFFF);
		return;
	}

	/* first, zot all the existing hash bits */
	CSR_WRITE_4(sc, VR_MAR0, 0);
	CSR_WRITE_4(sc, VR_MAR1, 0);

	/* now program new ones */
	ETHER_FIRST_MULTI(step, &sc->vr_ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
		    ETHER_ADDR_LEN) != 0)
			goto allmulti;

		h = vr_calchash(enm->enm_addrlo);

		if (h < 32)
			hashes[0] |= (1 << h);
		else
			hashes[1] |= (1 << (h - 32));
		ETHER_NEXT_MULTI(step, enm);
		mcnt++;
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	if (mcnt)
		rxfilt |= VR_RXCFG_RX_MULTI;
	else
		rxfilt &= ~VR_RXCFG_RX_MULTI;

	CSR_WRITE_4(sc, VR_MAR0, hashes[0]);
	CSR_WRITE_4(sc, VR_MAR1, hashes[1]);
	CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
}
/*
 * Create setup packet and put in queue for sending.
 */
void
ni_setup(struct ni_softc *sc)
{
	struct ifnet *ifp = &sc->sc_if;
	struct ni_msg *msg;
	struct ni_ptdb *ptdb;
	struct ether_multi *enm;
	struct ether_multistep step;
	int i, res;

	msg = REMQHI(&fqb->nf_mforw);
	if ((int)msg == Q_EMPTY)
		return; /* What to do? */

	ptdb = (struct ni_ptdb *)&msg->nm_text[0];
	memset(ptdb, 0, sizeof(struct ni_ptdb));

	msg->nm_opcode = BVP_MSG;
	msg->nm_len = 18;
	ptdb->np_index = 2; /* definition type index */
	ptdb->np_fque = 2; /* Free queue */
	if (ifp->if_flags & IFF_RUNNING) {
		msg->nm_opcode2 = NI_STPTDB;
		ptdb->np_type = ETHERTYPE_IP;
		ptdb->np_flags = PTDB_UNKN|PTDB_BDC;
		if (ifp->if_flags & IFF_PROMISC)
			ptdb->np_flags |= PTDB_PROMISC;
		memset(ptdb->np_mcast[0], 0xff, ETHER_ADDR_LEN); /* Broadcast */
		ptdb->np_adrlen = 1;
		msg->nm_len += 8;
		ifp->if_flags &= ~IFF_ALLMULTI;
		if ((ifp->if_flags & IFF_PROMISC) == 0) {
			ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
			i = 1;
			while (enm != NULL) {
				if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
					ifp->if_flags |= IFF_ALLMULTI;
					ptdb->np_flags |= PTDB_AMC;
					break;
				}
				msg->nm_len += 8;
				ptdb->np_adrlen++;
				memcpy(ptdb->np_mcast[i++], enm->enm_addrlo,
				    ETHER_ADDR_LEN);
				ETHER_NEXT_MULTI(step, enm);
			}
		}
	} else
		msg->nm_opcode2 = NI_CLPTDB;

	res = INSQTI(msg, &gvp->nc_forw0);
	if (res == Q_EMPTY) {
		WAITREG(NI_PCR, PCR_OWN);
		NI_WREG(NI_PCR, PCR_CMDQNE|PCR_CMDQ0|PCR_OWN);
	}
}
示例#5
0
void
dme_set_addr_filter(struct dme_softc *sc)
{
    struct ether_multi	*enm;
    struct ether_multistep	step;
    struct ethercom		*ec;
    struct ifnet		*ifp;
    uint16_t		af[4];
    int			i;

    ec = &sc->sc_ethercom;
    ifp = &ec->ec_if;

    if (ifp->if_flags & IFF_PROMISC) {
        dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN  |
                  DM9000_RCR_WTDIS |
                  DM9000_RCR_PRMSC);
        ifp->if_flags |= IFF_ALLMULTI;
        return;
    }

    af[0] = af[1] = af[2] = af[3] = 0x0000;
    ifp->if_flags &= ~IFF_ALLMULTI;

    ETHER_FIRST_MULTI(step, ec, enm);
    while (enm != NULL) {
        uint16_t hash;
        if (memcpy(enm->enm_addrlo, enm->enm_addrhi,
                   sizeof(enm->enm_addrlo))) {
            /*
                     * 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.)
                     */
            ifp->if_flags |= IFF_ALLMULTI;
            af[0] = af[1] = af[2] = af[3] = 0xffff;
            break;
        } else {
            hash = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3F;
            af[(uint16_t)(hash>>4)] |= (uint16_t)(1 << (hash % 16));
            ETHER_NEXT_MULTI(step, enm);
        }
    }

    /* Write the multicast address filter */
    for(i=0; i<4; i++) {
        dme_write(sc, DM9000_MAB0+i*2, af[i] & 0xFF);
        dme_write(sc, DM9000_MAB0+i*2+1, (af[i] >> 8) & 0xFF);
    }

    /* Setup RX controls */
    dme_write(sc, DM9000_RCR, DM9000_RCR_RXEN | DM9000_RCR_WTDIS);
}
示例#6
0
/*
 * Set the EPIC multicast hash table.
 *
 * NOTE: We rely on a recently-updated mii_media_active here!
 */
void
epic_set_mchash(struct epic_softc *sc)
{
	struct arpcom *ac = &sc->sc_arpcom;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	u_int32_t hash, mchash[4];

	/*
	 * Set up the multicast address filter by passing all multicast
	 * addresses through a CRC generator, and then using the low-order
	 * 6 bits as an index into the 64 bit multicast hash table (only
	 * the lower 16 bits of each 32 bit multicast hash register are
	 * valid).  The high order bits select the register, while the
	 * rest of the bits select the bit within the register.
	 */

	if (ifp->if_flags & IFF_PROMISC)
		goto allmulti;

	if (IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_10_T) {
		/* XXX hardware bug in 10Mbps mode. */
		goto allmulti;
	}

	if (ac->ac_multirangecnt > 0)
		goto allmulti;

	mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0;

	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
		hash >>= 26;

		/* Set the corresponding bit in the hash table. */
		mchash[hash >> 4] |= 1 << (hash & 0xf);

		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;
	goto sethash;

 allmulti:
	ifp->if_flags |= IFF_ALLMULTI;
	mchash[0] = mchash[1] = mchash[2] = mchash[3] = 0xffff;

 sethash:
	bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC0, mchash[0]);
	bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC1, mchash[1]);
	bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC2, mchash[2]);
	bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MC3, mchash[3]);
}
示例#7
0
void
ste_iff(struct ste_softc *sc)
{
	struct ifnet		*ifp = &sc->arpcom.ac_if;
	struct arpcom		*ac = &sc->arpcom;
	struct ether_multi	*enm;
	struct ether_multistep	step;
	u_int32_t		rxmode, hashes[2];
	int			h = 0;

	rxmode = CSR_READ_1(sc, STE_RX_MODE);
	rxmode &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_BROADCAST |
	    STE_RXMODE_MULTIHASH | STE_RXMODE_PROMISC |
	    STE_RXMODE_UNICAST);
	bzero(hashes, sizeof(hashes));
	ifp->if_flags &= ~IFF_ALLMULTI;

	/*
	 * Always accept broadcast frames.
	 * Always accept frames destined to our station address.
	 */
	rxmode |= STE_RXMODE_BROADCAST | STE_RXMODE_UNICAST;

	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		rxmode |= STE_RXMODE_ALLMULTI;
		if (ifp->if_flags & IFF_PROMISC)
			rxmode |= STE_RXMODE_PROMISC;
	} else {
		rxmode |= STE_RXMODE_MULTIHASH;

		/* now program new ones */
		ETHER_FIRST_MULTI(step, ac, enm);
		while (enm != NULL) {
			h = ether_crc32_be(enm->enm_addrlo,
			    ETHER_ADDR_LEN) & 0x3F;

			if (h < 32)
				hashes[0] |= (1 << h);
			else
				hashes[1] |= (1 << (h - 32));

			ETHER_NEXT_MULTI(step, enm);
		}
	}

	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);
	CSR_WRITE_1(sc, STE_RX_MODE, rxmode);
}
示例#8
0
void
mec_setfilter(struct mec_softc *sc)
{
	struct arpcom *ec = &sc->sc_ac;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	bus_space_tag_t st = sc->sc_st;
	bus_space_handle_t sh = sc->sc_sh;
	uint64_t mchash;
	uint32_t control, hash;
	int mcnt;

	control = bus_space_read_8(st, sh, MEC_MAC_CONTROL);
	control &= ~MEC_MAC_FILTER_MASK;

	if (ifp->if_flags & IFF_PROMISC) {
		control |= MEC_MAC_FILTER_PROMISC;
		bus_space_write_8(st, sh, MEC_MULTICAST, 0xffffffffffffffffULL);
		bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
		return;
	}

	mcnt = 0;
	mchash = 0;
	ETHER_FIRST_MULTI(step, ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			/* Set allmulti for a range of multicast addresses. */
			control |= MEC_MAC_FILTER_ALLMULTI;
			bus_space_write_8(st, sh, MEC_MULTICAST,
			    0xffffffffffffffffULL);
			bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
			return;
		}

#define mec_calchash(addr)	(ether_crc32_be((addr), ETHER_ADDR_LEN) >> 26)

		hash = mec_calchash(enm->enm_addrlo);
		mchash |= 1 << hash;
		mcnt++;
		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	if (mcnt > 0)
		control |= MEC_MAC_FILTER_MATCHMULTI;

	bus_space_write_8(st, sh, MEC_MULTICAST, mchash);
	bus_space_write_8(st, sh, MEC_MAC_CONTROL, control);
}
示例#9
0
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);
}
示例#10
0
void
ste_setmulti(struct ste_softc *sc)
{
	struct ifnet		*ifp;
	struct arpcom		*ac = &sc->arpcom;
	struct ether_multi	*enm;
	struct ether_multistep	step;
	int			h = 0;
	u_int32_t		hashes[2] = { 0, 0 };

	ifp = &sc->arpcom.ac_if;
allmulti:
	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);

	/* now program new ones */
	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			ifp->if_flags |= IFF_ALLMULTI;
			goto allmulti;
		}
		h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) & 0x3F;
		if (h < 32)
			hashes[0] |= (1 << h);
		else
			hashes[1] |= (1 << (h - 32));
		ETHER_NEXT_MULTI(step, enm);
	}

	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);

	return;
}
示例#11
0
Static void
kue_setmulti(struct kue_softc *sc)
{
	struct ifnet		*ifp = GET_IFP(sc);
	struct ether_multi	*enm;
	struct ether_multistep	step;
	int			i;

	DPRINTFN(5,("%s: %s: enter\n", USBDEVNAME(sc->kue_dev), __func__));

	if (ifp->if_flags & IFF_PROMISC) {
allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI;
		sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
		kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
		return;
	}

	sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI;

	i = 0;
#if defined (__NetBSD__)
	ETHER_FIRST_MULTI(step, &sc->kue_ec, enm);
#else
	ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
#endif
	while (enm != NULL) {
		if (i == KUE_MCFILTCNT(sc) ||
		    memcmp(enm->enm_addrlo, enm->enm_addrhi,
			ETHER_ADDR_LEN) != 0)
			goto allmulti;

		memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN);
		ETHER_NEXT_MULTI(step, enm);
		i++;
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
	kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
	    i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);

	kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
}
示例#12
0
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);
}
示例#13
0
void
pdq_os_addr_fill(
    pdq_t *pdq,
    pdq_lanaddr_t *addr,
    size_t num_addrs)
{
    pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
    struct ether_multistep step;
    struct ether_multi *enm;

    ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
    while (enm != NULL && num_addrs > 0) {
        ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) enm->enm_addrlo)[0];
        ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) enm->enm_addrlo)[1];
        ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) enm->enm_addrlo)[2];
        ETHER_NEXT_MULTI(step, enm);
        addr++;
        num_addrs--;
    }
}
示例#14
0
void
kue_setmulti(struct kue_softc *sc)
{
	struct arpcom		*ac = &sc->arpcom;
	struct ifnet		*ifp = GET_IFP(sc);
	struct ether_multi	*enm;
	struct ether_multistep	step;
	int			i;

	DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));

	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI;
		sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
		kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
		return;
	}

	sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI;

	i = 0;
	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		if (i == KUE_MCFILTCNT(sc))
			goto allmulti;

		memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN);
		ETHER_NEXT_MULTI(step, enm);
		i++;
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
	kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
	    i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);

	kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
}
示例#15
0
void
vnet_setmulti(struct vnet_softc *sc, int set)
{
	struct arpcom *ac = &sc->sc_ac;
	struct ether_multi *enm;
	struct ether_multistep step;
	struct vnet_mcast_info mi;
	int count = 0;

	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX) ||
	    !ISSET(sc->sc_vio_state, VIO_ACK_RDX))
		return;

	bzero(&mi, sizeof(mi));
	mi.tag.type = VIO_TYPE_CTRL;
	mi.tag.stype = VIO_SUBTYPE_INFO;
	mi.tag.stype_env = VNET_MCAST_INFO;
	mi.tag.sid = sc->sc_local_sid;
	mi.set = set ? 1 : 0;
	KERNEL_LOCK();
	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		/* XXX What about multicast ranges? */
		bcopy(enm->enm_addrlo, mi.mcast_addr[count], ETHER_ADDR_LEN);
		ETHER_NEXT_MULTI(step, enm);

		count++;
		if (count < VNET_NUM_MCAST)
			continue;

		mi.count = VNET_NUM_MCAST;
		vnet_sendmsg(sc, &mi, sizeof(mi));
		count = 0;
	}

	if (count > 0) {
		mi.count = count;
		vnet_sendmsg(sc, &mi, sizeof(mi));
	}
	KERNEL_UNLOCK();
}
示例#16
0
/*
 * Go through the list of multicast addresses and calculate the logical
 * address filter.
 */
void
mace_calcladrf(struct mc_softc *sc, u_int8_t *af)
{
	struct ether_multi *enm;
	u_int32_t crc;
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct arpcom *ac = &sc->sc_arpcom;
	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 (ac->ac_multirangecnt > 0)
		goto allmulti;

	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0;
	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		crc = ether_crc32_le(enm->enm_addrlo, sizeof(enm->enm_addrlo));

		/* Just want the 6 most significant bits. */
		crc >>= 26;

		/* Set the corresponding bit in the filter. */
		af[crc >> 3] |= 1 << (crc & 7);

		ETHER_NEXT_MULTI(step, enm);
	}
	ifp->if_flags &= ~IFF_ALLMULTI;
	return;

allmulti:
	ifp->if_flags |= IFF_ALLMULTI;
	*((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff;
}
示例#17
0
void
tsec_iff(struct tsec_softc *sc)
{
	struct arpcom *ac = &sc->sc_ac;
	struct ifnet *ifp = &sc->sc_ac.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	uint32_t crc, hash[8];
	uint32_t rctrl;
	int i;

	rctrl = tsec_read(sc, TSEC_RCTRL);
	rctrl &= ~TSEC_RCTRL_PROM;
	ifp->if_flags &= ~IFF_ALLMULTI;

	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		rctrl |= TSEC_RCTRL_PROM;
		bzero(hash, sizeof(hash));
	} else {
		ETHER_FIRST_MULTI(step, ac, enm);
		while (enm != NULL) {
			crc = ether_crc32_be(enm->enm_addrlo,
			    ETHER_ADDR_LEN);

			crc >>= 24;
			hash[crc / 32] |= 1 << (31 - (crc % 32));

			ETHER_NEXT_MULTI(step, enm);
		}
	}

	for (i = 0; i < nitems(hash); i++)
		tsec_write(sc, TSEC_GADDR0 + i * 4, hash[i]);

	tsec_write(sc, TSEC_RCTRL, rctrl);
}
示例#18
0
文件: qe.c 项目: ryo/netbsd-src
/*
 * Reset multicast filter.
 */
void
qe_mcreset(struct qe_softc *sc)
{
	struct ethercom *ec = &sc->sc_ethercom;
	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
	bus_space_tag_t t = sc->sc_bustag;
	bus_space_handle_t mr = sc->sc_mr;
	struct ether_multi *enm;
	struct ether_multistep step;
	uint32_t crc;
	uint16_t hash[4];
	uint8_t octet, maccc, *ladrp = (uint8_t *)&hash[0];
	int i;

#if defined(SUN4U) || defined(__GNUC__)
	(void)&t;
#endif

	/* We also enable transmitter & receiver here */
	maccc = QE_MR_MACCC_ENXMT | QE_MR_MACCC_ENRCV;

	if (ifp->if_flags & IFF_PROMISC) {
		maccc |= QE_MR_MACCC_PROM;
		bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
		return;
	}

	if (ifp->if_flags & IFF_ALLMULTI) {
		bus_space_write_1(t, mr, QE_MRI_IAC,
				  QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
		bus_space_set_multi_1(t, mr, QE_MRI_LADRF, 0xff, 8);
		bus_space_write_1(t, mr, QE_MRI_IAC, 0);
		bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
		return;
	}

	hash[3] = hash[2] = hash[1] = hash[0] = 0;

	ETHER_FIRST_MULTI(step, ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
			 ETHER_ADDR_LEN) != 0) {
			/*
			 * 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.)
			 */
			bus_space_write_1(t, mr, QE_MRI_IAC,
				 QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
			bus_space_set_multi_1(t, mr, QE_MRI_LADRF, 0xff, 8);
			bus_space_write_1(t, mr, QE_MRI_IAC, 0);
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}

		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
		crc >>= 26;
		hash[crc >> 4] |= 1 << (crc & 0xf);
		ETHER_NEXT_MULTI(step, enm);
	}

	/* We need to byte-swap the hash before writing to the chip. */
	for (i = 0; i < 7; i += 2) {
		octet = ladrp[i];
		ladrp[i] = ladrp[i + 1];
		ladrp[i + 1] = octet;
	}
	bus_space_write_1(t, mr, QE_MRI_IAC,
			  QE_MR_IAC_ADDRCHG | QE_MR_IAC_LOGADDR);
	bus_space_write_multi_1(t, mr, QE_MRI_LADRF, ladrp, 8);
	bus_space_write_1(t, mr, QE_MRI_IAC, 0);
	bus_space_write_1(t, mr, QE_MRI_MACCC, maccc);
}
示例#19
0
/*
 * Set up the logical address filter.
 */
void
cas_setladrf(struct cas_softc *sc)
{
	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	struct arpcom *ac = &sc->sc_arpcom;
	bus_space_tag_t t = sc->sc_memt;
	bus_space_handle_t h = sc->sc_memh;
	u_int32_t crc, hash[16], v;
	int i;

	/* Get current RX configuration */
	v = bus_space_read_4(t, h, CAS_MAC_RX_CONFIG);


	/*
	 * Turn off promiscuous mode, promiscuous group mode (all multicast),
	 * and hash filter.  Depending on the case, the right bit will be
	 * enabled.
	 */
	v &= ~(CAS_MAC_RX_PROMISCUOUS|CAS_MAC_RX_HASH_FILTER|
	    CAS_MAC_RX_PROMISC_GRP);

	if ((ifp->if_flags & IFF_PROMISC) != 0) {
		/* Turn on promiscuous mode */
		v |= CAS_MAC_RX_PROMISCUOUS;
		ifp->if_flags |= IFF_ALLMULTI;
		goto chipit;
	}

	/*
	 * Set up multicast address filter by passing all multicast addresses
	 * through a crc generator, and then using the high order 8 bits as an
	 * index into the 256 bit logical address filter.  The high order 4
	 * bits selects the word, while the other 4 bits select the bit within
	 * the word (where bit 0 is the MSB).
	 */

	/* Clear hash table */
	for (i = 0; i < 16; i++)
		hash[i] = 0;


	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			/*
			 * 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.)
			 * XXX use the addr filter for this
			 */
			ifp->if_flags |= IFF_ALLMULTI;
			v |= CAS_MAC_RX_PROMISC_GRP;
			goto chipit;
		}

		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);

		/* Just want the 8 most significant bits. */
		crc >>= 24;

		/* Set the corresponding bit in the filter. */
		hash[crc >> 4] |= 1 << (15 - (crc & 15));

		ETHER_NEXT_MULTI(step, enm);
	}

	v |= CAS_MAC_RX_HASH_FILTER;
	ifp->if_flags &= ~IFF_ALLMULTI;

	/* Now load the hash table into the chip (if we are using it) */
	for (i = 0; i < 16; i++) {
		bus_space_write_4(t, h,
		    CAS_MAC_HASH0 + i * (CAS_MAC_HASH1-CAS_MAC_HASH0),
		    hash[i]);
	}

chipit:
	bus_space_write_4(t, h, CAS_MAC_RX_CONFIG, v);
}
示例#20
0
/*
 * How Command Block List Processing is done.
 * 
 * A running CBL is never manipulated. If there is a CBL already running,
 * further CMDs are deferred until the current list is done. A new list is
 * setup when the old one has finished.
 * This eases programming. To manipulate a running CBL it is necessary to
 * suspend the Command Unit to avoid race conditions. After a suspend
 * is sent we have to wait for an interrupt that ACKs the suspend. Then
 * we can manipulate the CBL and resume operation. I am not sure that this
 * is more effective than the current, much simpler approach. => KISS
 * See i82596CA data sheet page 26.
 * 
 * A CBL is running or on the way to be set up when (sc->sc_next_cb != 0).
 * 
 * A CBL may consist of TX CMDs, and _only_ TX CMDs.
 * A TX CBL is running or on the way to be set up when
 * ((sc->sc_next_cb != 0) && (sc->sc_next_tbd != 0)).
 * 
 * A CBL may consist of other non-TX CMDs like IAS or CONF, and _only_
 * non-TX CMDs.
 * 
 * This comes mostly through the way how an Ethernet driver works and
 * because running CBLs are not manipulated when they are on the way. If
 * if_start() is called there will be TX CMDs enqueued so we have a running
 * CBL and other CMDs from e.g. if_ioctl() will be deferred and vice versa.
 * 
 * The Multicast Setup Command is special. A MCS needs more space than
 * a single CB has. Actual space requirement depends on the length of the
 * multicast list. So we always defer MCS until other CBLs are finished,
 * then we setup a CONF CMD in the first CB. The CONF CMD is needed to
 * turn ALLMULTI on the hardware on or off. The MCS is the 2nd CB and may
 * use all the remaining space in the CBL and the Transmit Buffer Descriptor
 * List. (Therefore CBL and TBDL must be continuous in physical and virtual
 * memory. This is guaranteed through the definitions of the list offsets
 * in i82596reg.h and because it is only a single DMA segment used for all
 * lists.) When ALLMULTI is enabled via the CONF CMD, the MCS is run with
 * a multicast list length of 0, thus disabling the multicast filter.
 * A deferred MCS is signaled via ((sc->sc_flags & IEE_WANT_MCAST) != 0)
 */
void
iee_cb_setup(struct iee_softc *sc, uint32_t cmd)
{
	struct iee_cb *cb = SC_CB(sc, sc->sc_next_cb);
	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
	struct ether_multistep step;
	struct ether_multi *enm;

	memset(cb, 0, sc->sc_cb_sz);
	cb->cb_cmd = cmd;
	switch (cmd & IEE_CB_CMD) {
	case IEE_CB_CMD_NOP:	/* NOP CMD */
		break;
	case IEE_CB_CMD_IAS:	/* Individual Address Setup */
		memcpy(__UNVOLATILE(cb->cb_ind_addr), CLLADDR(ifp->if_sadl),
		    ETHER_ADDR_LEN);
		break;
	case IEE_CB_CMD_CONF:	/* Configure */
		memcpy(__UNVOLATILE(cb->cb_cf), sc->sc_cf, sc->sc_cf[0]
		    & IEE_CF_0_CNT_M);
		break;
	case IEE_CB_CMD_MCS:	/* Multicast Setup */
		if (sc->sc_next_cb != 0) {
			sc->sc_flags |= IEE_WANT_MCAST;
			return;
		}
		sc->sc_flags &= ~IEE_WANT_MCAST;
		if ((sc->sc_cf[8] & IEE_CF_8_PRM) != 0) {
			/* Need no multicast filter in promisc mode. */
			iee_cb_setup(sc, IEE_CB_CMD_CONF | IEE_CB_S | IEE_CB_EL
			    | IEE_CB_I);
			return;
		}
		/* Leave room for a CONF CMD to en/dis-able ALLMULTI mode */
		cb = SC_CB(sc, sc->sc_next_cb + 1);
		cb->cb_cmd = cmd;
		cb->cb_mcast.mc_size = 0;
		ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
		while (enm != NULL) {
			if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
			    ETHER_ADDR_LEN) != 0 || cb->cb_mcast.mc_size
			    * ETHER_ADDR_LEN + 2 * sc->sc_cb_sz >
			    sc->sc_cb_sz * IEE_NCB +
			    sc->sc_tbd_sz * IEE_NTBD * IEE_NCB) {
				cb->cb_mcast.mc_size = 0;
				break;
			}
			memcpy(__UNVOLATILE(&cb->cb_mcast.mc_addrs[
			    cb->cb_mcast.mc_size * ETHER_ADDR_LEN]),
			    enm->enm_addrlo, ETHER_ADDR_LEN);
			ETHER_NEXT_MULTI(step, enm);
			cb->cb_mcast.mc_size++;
		}
		if (cb->cb_mcast.mc_size == 0) {
			/* Can't do exact mcast filtering, do ALLMULTI mode. */
			ifp->if_flags |= IFF_ALLMULTI;
			sc->sc_cf[11] &= ~IEE_CF_11_MCALL;
		} else {
			/* disable ALLMULTI and load mcast list */
			ifp->if_flags &= ~IFF_ALLMULTI;
			sc->sc_cf[11] |= IEE_CF_11_MCALL;
			/* Mcast setup may need more than sc->sc_cb_sz bytes. */
			bus_dmamap_sync(sc->sc_dmat, sc->sc_shmem_map,
			    sc->sc_cb_off,
			    sc->sc_cb_sz * IEE_NCB +
			    sc->sc_tbd_sz * IEE_NTBD * IEE_NCB,
			    BUS_DMASYNC_PREWRITE);
		}
		iee_cb_setup(sc, IEE_CB_CMD_CONF);
		break;
	case IEE_CB_CMD_TR:	/* Transmit */
		cb->cb_transmit.tx_tbd_addr =
		    IEE_SWAPA32(IEE_PHYS_SHMEM(sc->sc_tbd_off
		    + sc->sc_tbd_sz * sc->sc_next_tbd));
		cb->cb_cmd |= IEE_CB_SF; /* Always use Flexible Mode. */
		break;
	case IEE_CB_CMD_TDR:	/* Time Domain Reflectometry */
		break;
	case IEE_CB_CMD_DUMP:	/* Dump */
		break;
	case IEE_CB_CMD_DIAG:	/* Diagnose */
		break;
	default:
		/* can't happen */
		break;
	}
	cb->cb_link_addr = IEE_SWAPA32(IEE_PHYS_SHMEM(sc->sc_cb_off +
	    sc->sc_cb_sz * (sc->sc_next_cb + 1)));
	IEE_CBSYNC(sc, sc->sc_next_cb,
	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
	sc->sc_next_cb++;
	ifp->if_timer = 5;
}
示例#21
0
/*
 * Program the 64-bit multicast hash filter.
 */
void
rtk_setmulti(struct rtk_softc *sc)
{
	struct ifnet *ifp;
	uint32_t hashes[2] = { 0, 0 };
	uint32_t rxfilt;
	struct ether_multi *enm;
	struct ether_multistep step;
	int h, mcnt;

	ifp = &sc->ethercom.ec_if;

	rxfilt = CSR_READ_4(sc, RTK_RXCFG);

	if (ifp->if_flags & IFF_PROMISC) {
 allmulti:
		ifp->if_flags |= IFF_ALLMULTI;
		rxfilt |= RTK_RXCFG_RX_MULTI;
		CSR_WRITE_4(sc, RTK_RXCFG, rxfilt);
		CSR_WRITE_4(sc, RTK_MAR0, 0xFFFFFFFF);
		CSR_WRITE_4(sc, RTK_MAR4, 0xFFFFFFFF);
		return;
	}

	/* first, zot all the existing hash bits */
	CSR_WRITE_4(sc, RTK_MAR0, 0);
	CSR_WRITE_4(sc, RTK_MAR4, 0);

	/* now program new ones */
	ETHER_FIRST_MULTI(step, &sc->ethercom, enm);
	mcnt = 0;
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
		    ETHER_ADDR_LEN) != 0)
			goto allmulti;

		h = rtk_calchash(enm->enm_addrlo);
		if (h < 32)
			hashes[0] |= (1 << h);
		else
			hashes[1] |= (1 << (h - 32));
		mcnt++;
		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

	if (mcnt)
		rxfilt |= RTK_RXCFG_RX_MULTI;
	else
		rxfilt &= ~RTK_RXCFG_RX_MULTI;

	CSR_WRITE_4(sc, RTK_RXCFG, rxfilt);

	/*
	 * For some unfathomable reason, RealTek decided to reverse
	 * the order of the multicast hash registers in the PCI Express
	 * parts. This means we have to write the hash pattern in reverse
	 * order for those devices.
	 */
	if ((sc->sc_quirk & RTKQ_PCIE) != 0) {
		CSR_WRITE_4(sc, RTK_MAR0, bswap32(hashes[1]));
		CSR_WRITE_4(sc, RTK_MAR4, bswap32(hashes[0]));
	} else {
		CSR_WRITE_4(sc, RTK_MAR0, hashes[0]);
		CSR_WRITE_4(sc, RTK_MAR4, hashes[1]);
	}
}
示例#22
0
/*
 * Set up the logical address filter.
 */
void
bmac_setladrf(struct bmac_softc *sc)
{
	struct ifnet *ifp = &sc->arpcom.ac_if;
	struct ether_multi *enm;
	struct ether_multistep step;
	u_int32_t crc;
	u_int16_t hash[4];
	int x;

	/*
	 * 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) {
		bmac_set_bits(sc, RXCFG, RxPromiscEnable);
		return;
	}

	if (ifp->if_flags & IFF_ALLMULTI) {
		hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
		goto chipit;
	}

	hash[3] = hash[2] = hash[1] = hash[0] = 0;
	ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
	while (enm != NULL) {
		if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			/*
			 * 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.)
			 */
			hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
			ifp->if_flags |= IFF_ALLMULTI;
			goto chipit;
		}

		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. */
		hash[crc >> 4] |= 1 << (crc & 0xf);

		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

chipit:
	bmac_write_reg(sc, HASH0, hash[0]);
	bmac_write_reg(sc, HASH1, hash[1]);
	bmac_write_reg(sc, HASH2, hash[2]);
	bmac_write_reg(sc, HASH3, hash[3]);
	x = bmac_read_reg(sc, RXCFG);
	x &= ~RxPromiscEnable;
	x |= RxHashFilterEnable;
	bmac_write_reg(sc, RXCFG, x);
}
示例#23
0
/*
 * Create a setup packet and put in queue for sending.
 */
void
qe_setup(struct qe_softc *sc)
{
	struct ether_multi *enm;
	struct ether_multistep step;
	struct qe_cdata *qc = sc->sc_qedata;
	struct ifnet *ifp = &sc->sc_if;
	u_int8_t *enaddr = sc->sc_ac.ac_enaddr;
	int i, j, k, idx, s;

	s = splnet();
	if (sc->sc_inq == (TXDESCS - 1)) {
		sc->sc_setup = 1;
		splx(s);
		return;
	}
	sc->sc_setup = 0;
	/*
	 * Init the setup packet with valid info.
	 */
	memset(qc->qc_setup, 0xff, sizeof(qc->qc_setup)); /* Broadcast */
	for (i = 0; i < ETHER_ADDR_LEN; i++)
		qc->qc_setup[i * 8 + 1] = enaddr[i]; /* Own address */

	/*
	 * Multicast handling. The DEQNA can handle up to 12 direct 
	 * ethernet addresses.
	 */
	j = 3; k = 0;
	ifp->if_flags &= ~IFF_ALLMULTI;
	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
		for (i = 0; i < ETHER_ADDR_LEN; i++)
			qc->qc_setup[i * 8 + j + k] = enm->enm_addrlo[i];
		j++;
		if (j == 8) {
			j = 1; k += 64;
		}
		if (k > 64) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
		ETHER_NEXT_MULTI(step, enm);
	}
	idx = sc->sc_nexttx;
	qc->qc_xmit[idx].qe_buf_len = -64;

	/*
	 * How is the DEQNA turned in ALLMULTI mode???
	 * Until someone tells me, fall back to PROMISC when more than
	 * 12 ethernet addresses.
	 */
	if (ifp->if_flags & IFF_ALLMULTI)
		ifp->if_flags |= IFF_PROMISC;
	else if (ifp->if_pcount == 0)
		ifp->if_flags &= ~IFF_PROMISC;
	if (ifp->if_flags & IFF_PROMISC)
		qc->qc_xmit[idx].qe_buf_len = -65;

	qc->qc_xmit[idx].qe_addr_lo = LOWORD(sc->sc_pqedata->qc_setup);
	qc->qc_xmit[idx].qe_addr_hi =
	    HIWORD(sc->sc_pqedata->qc_setup) | QE_SETUP | QE_EOMSG;
	qc->qc_xmit[idx].qe_status1 = qc->qc_xmit[idx].qe_flag = QE_NOTYET;
	qc->qc_xmit[idx].qe_addr_hi |= QE_VALID;

	if (QE_RCSR(QE_CSR_CSR) & QE_XL_INVALID) {
		QE_WCSR(QE_CSR_XMTL,
		    LOWORD(&sc->sc_pqedata->qc_xmit[idx]));
		QE_WCSR(QE_CSR_XMTH,
		    HIWORD(&sc->sc_pqedata->qc_xmit[idx]));
	}

	sc->sc_inq++;
	if (++sc->sc_nexttx == TXDESCS)
		sc->sc_nexttx = 0;
	splx(s);
}
示例#24
0
static void 
camprogram(struct sn_softc *sc)
{
	struct ether_multistep step;
	struct ether_multi *enm;
	struct ifnet *ifp;
	int	timeout;
	int	mcount = 0;

	caminitialise(sc);

	ifp = &sc->sc_if;

	/* Always load our own address first. */
	camentry(sc, mcount, CLLADDR(ifp->if_sadl));
	mcount++;

	/* Assume we won't need allmulti bit. */
	ifp->if_flags &= ~IFF_ALLMULTI;

	/* Loop through multicast addresses */
	ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
	while (enm != NULL) {
		if (mcount == MAXCAM) {
			 ifp->if_flags |= IFF_ALLMULTI;
			 break;
		}

		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
		    sizeof(enm->enm_addrlo)) != 0) {
			/*
			 * SONIC's CAM is programmed with specific
			 * addresses. It has no way to specify a range.
			 * (Well, thats not exactly true. If the
			 * range is small one could program each addr
			 * within the range as a separate CAM entry)
			 */
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}

		/* program the CAM with the specified entry */
		camentry(sc, mcount, enm->enm_addrlo);
		mcount++;

		ETHER_NEXT_MULTI(step, enm);
	}

	NIC_PUT(sc, SNR_CDP, LOWER(sc->v_cda));
	NIC_PUT(sc, SNR_CDC, MAXCAM);
	NIC_PUT(sc, SNR_CR, CR_LCAM);
	wbflush();

	timeout = 10000;
	while ((NIC_GET(sc, SNR_CR) & CR_LCAM) && timeout--)
		delay(10);
	if (timeout == 0) {
		/* XXX */
		panic("%s: CAM initialisation failed",
		    device_xname(sc->sc_dev));
	}
	timeout = 10000;
	while (((NIC_GET(sc, SNR_ISR) & ISR_LCD) == 0) && timeout--)
		delay(10);

	if (NIC_GET(sc, SNR_ISR) & ISR_LCD)
		NIC_PUT(sc, SNR_ISR, ISR_LCD);
	else
		printf("%s: CAM initialisation without interrupt\n",
		    device_xname(sc->sc_dev));
}
示例#25
0
/*
 * Create a setup packet and put in queue for sending.
 */
void
ze_setup(struct ze_softc *sc)
{
	struct ether_multi *enm;
	struct ether_multistep step;
	struct ze_cdata *zc = sc->sc_zedata;
	struct ifnet *ifp = &sc->sc_if;
	const u_int8_t *enaddr = CLLADDR(ifp->if_sadl);
	int j, idx, reg;

	if (sc->sc_inq == (TXDESCS - 1)) {
		sc->sc_setup = 1;
		return;
	}
	sc->sc_setup = 0;
	/*
	 * Init the setup packet with valid info.
	 */
	memset(zc->zc_setup, 0xff, sizeof(zc->zc_setup)); /* Broadcast */
	memcpy(zc->zc_setup, enaddr, ETHER_ADDR_LEN);

	/*
	 * Multicast handling. The SGEC can handle up to 16 direct
	 * ethernet addresses.
	 */
	j = 16;
	ifp->if_flags &= ~IFF_ALLMULTI;
	ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
		memcpy(&zc->zc_setup[j], enm->enm_addrlo, ETHER_ADDR_LEN);
		j += 8;
		ETHER_NEXT_MULTI(step, enm);
		if ((enm != NULL)&& (j == 128)) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
	}

	/*
	 * ALLMULTI implies PROMISC in this driver.
	 */
	if (ifp->if_flags & IFF_ALLMULTI)
		ifp->if_flags |= IFF_PROMISC;
	else if (ifp->if_pcount == 0)
		ifp->if_flags &= ~IFF_PROMISC;

	/*
	 * Fiddle with the receive logic.
	 */
	reg = ZE_RCSR(ZE_CSR6);
	DELAY(10);
	ZE_WCSR(ZE_CSR6, reg & ~ZE_NICSR6_SR); /* Stop rx */
	reg &= ~ZE_NICSR6_AF;
	if (ifp->if_flags & IFF_PROMISC)
		reg |= ZE_NICSR6_AF_PROM;
	else if (ifp->if_flags & IFF_ALLMULTI)
		reg |= ZE_NICSR6_AF_ALLM;
	DELAY(10);
	ZE_WCSR(ZE_CSR6, reg);
	/*
	 * Only send a setup packet if needed.
	 */
	if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) == 0) {
		idx = sc->sc_nexttx;
		zc->zc_xmit[idx].ze_tdes1 = ZE_TDES1_DT_SETUP;
		zc->zc_xmit[idx].ze_bufsize = 128;
		zc->zc_xmit[idx].ze_bufaddr = sc->sc_pzedata->zc_setup;
		zc->zc_xmit[idx].ze_tdr = ZE_TDR_OW;

		if ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_TS) != ZE_NICSR5_TS_RUN)
			ZE_WCSR(ZE_CSR1, -1);

		sc->sc_inq++;
		if (++sc->sc_nexttx == TXDESCS)
			sc->sc_nexttx = 0;
	}
}
示例#26
0
void
be_mcreset(struct be_softc *sc)
{
	struct ethercom *ec = &sc->sc_ethercom;
	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
	bus_space_tag_t t = sc->sc_bustag;
	bus_space_handle_t br = sc->sc_br;
	uint32_t v;
	uint32_t crc;
	uint16_t hash[4];
	struct ether_multi *enm;
	struct ether_multistep step;

	if (ifp->if_flags & IFF_PROMISC) {
		v = bus_space_read_4(t, br, BE_BRI_RXCFG);
		v |= BE_BR_RXCFG_PMISC;
		bus_space_write_4(t, br, BE_BRI_RXCFG, v);
		return;
	}

	if (ifp->if_flags & IFF_ALLMULTI) {
		hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
		goto chipit;
	}

	hash[3] = hash[2] = hash[1] = hash[0] = 0;

	ETHER_FIRST_MULTI(step, ec, enm);
	while (enm != NULL) {
		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
			/*
			 * 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.)
			 */
			hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
			ifp->if_flags |= IFF_ALLMULTI;
			goto chipit;
		}

		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
		/* Just want the 6 most significant bits. */
		crc >>= 26;

		hash[crc >> 4] |= 1 << (crc & 0xf);
		ETHER_NEXT_MULTI(step, enm);
	}

	ifp->if_flags &= ~IFF_ALLMULTI;

chipit:
	/* Enable the hash filter */
	bus_space_write_4(t, br, BE_BRI_HASHTAB0, hash[0]);
	bus_space_write_4(t, br, BE_BRI_HASHTAB1, hash[1]);
	bus_space_write_4(t, br, BE_BRI_HASHTAB2, hash[2]);
	bus_space_write_4(t, br, BE_BRI_HASHTAB3, hash[3]);

	v = bus_space_read_4(t, br, BE_BRI_RXCFG);
	v &= ~BE_BR_RXCFG_PMISC;
	v |= BE_BR_RXCFG_HENABLE;
	bus_space_write_4(t, br, BE_BRI_RXCFG, v);
}