len = MHLEN - pad;
len -= pad;
static struct mbuf *	hme_get __P((struct hme_softc *, int, int));static void		hme_read __P((struct hme_softc *, int, int));static int		hme_put __P((struct hme_softc *, int, struct mbuf *));/* * ifmedia glue */static int	hme_mediachange __P((struct ifnet *));static void	hme_mediastatus __P((struct ifnet *, struct ifmediareq *));/* * mii glue */static int	hme_mii_read __P((struct device *, int, int));static void	hme_mii_write __P((struct device *, int, int, int));static void	hme_mii_statchg __P((struct device *));static void	hme_mcreset __P((struct hme_softc *));struct cfattach hme_ca = {	sizeof (struct hme_softc), hmematch, hmeattach};struct cfdriver hme_cd = {	NULL, "hme", DV_IFNET};inthmematch(parent, vcf, aux)	struct device *parent;	void *vcf, *aux;{	struct cfdata *cf = vcf;	struct confargs *ca = aux;	register struct romaux *ra = &ca->ca_ra;	if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&	    strcmp("SUNW,hme", ra->ra_name) &&	    strcmp("SUNW,qfe", ra->ra_name)) {		return (0);	}	if (!sbus_testdma((struct sbus_softc *)parent, ca))		return(0);	return (1);}void    hmeattach(parent, self, aux)	struct device *parent, *self;	void *aux;{	struct confargs *ca = aux;	struct hme_softc *sc = (struct hme_softc *)self;	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	int pri;	/* XXX the following declaration should be elsewhere */	extern void myetheraddr __P((u_char *));	if (ca->ca_ra.ra_nintr != 1) {		printf(": expected 1 interrupt, got %d\n",			ca->ca_ra.ra_nintr);		return;	}	pri = ca->ca_ra.ra_intr[0].int_pri;	/* map registers */	if (ca->ca_ra.ra_nreg != 5) {		printf(": expected 5 registers, got %d\n", ca->ca_ra.ra_nreg);		return;	}	sc->sc_gr = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,			ca->ca_ra.ra_reg[0].rr_len);	sc->sc_txr = mapiodev(&(ca->ca_ra.ra_reg[1]), 0,			ca->ca_ra.ra_reg[1].rr_len);	sc->sc_rxr = mapiodev(&(ca->ca_ra.ra_reg[2]), 0,			ca->ca_ra.ra_reg[2].rr_len);	sc->sc_cr = mapiodev(&(ca->ca_ra.ra_reg[3]), 0,			ca->ca_ra.ra_reg[3].rr_len);	sc->sc_tcvr = mapiodev(&(ca->ca_ra.ra_reg[4]), 0,			ca->ca_ra.ra_reg[4].rr_len);	sc->sc_node = ca->ca_ra.ra_node;	sc->sc_rev = getpropint(ca->ca_ra.ra_node, "hm-rev", -1);	if (sc->sc_rev == 0xff)		sc->sc_rev = 0xa0;	if (sc->sc_rev == 0x20 || sc->sc_rev == 0x21)		sc->sc_flags = HME_FLAG_20_21;	else if (sc->sc_rev != 0xa0)		sc->sc_flags = HME_FLAG_NOT_A0;	sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);	if (sc->sc_burst == -1)		sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;        /* Clamp at parent's burst sizes */	sc->sc_burst &= ((struct sbus_softc *)parent)->sc_burst;	hme_meminit(sc);	sbus_establish(&sc->sc_sd, &sc->sc_dev);	sc->sc_ih.ih_fun = hmeintr;	sc->sc_ih.ih_arg = sc;	intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih);	/*	 * Get MAC address from card if 'local-mac-address' property exists.	 * Otherwise, use the machine's builtin MAC.	 */	if (getprop(ca->ca_ra.ra_node, "local-mac-address",	    sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0) {		myetheraddr(sc->sc_arpcom.ac_enaddr);	}	printf(" pri %d: address %s rev %d\n", pri,	    ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_rev);	sc->sc_mii.mii_ifp = ifp;	sc->sc_mii.mii_readreg = hme_mii_read;	sc->sc_mii.mii_writereg = hme_mii_write;	sc->sc_mii.mii_statchg = hme_mii_statchg;	ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, hme_mediachange,	    hme_mediastatus);	mii_phy_probe(self, &sc->sc_mii, 0xffffffff);	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE,		    0, NULL);		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);	}	else		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);	ifp->if_softc = sc;	ifp->if_start = hmestart;	ifp->if_ioctl = hmeioctl;	ifp->if_watchdog = hmewatchdog;	ifp->if_flags =		IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;	/* Attach the interface. */	if_attach(ifp);	ether_ifattach(ifp);#if NBPFILTER > 0	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif}/* * Start output on interface. * We make two assumptions here: *  1) that the current priority is set to splnet _before_ this code *     is called *and* is returned to the appropriate priority after *     return *  2) that the IFF_OACTIVE flag is checked before this code is called *     (i.e. that the output part of the interface is idle) */voidhmestart(ifp)	struct ifnet *ifp;{	struct hme_softc *sc = ifp->if_softc;	struct mbuf *m;	int bix, len;	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)		return;	bix = sc->sc_last_td;	for (;;) {		IF_DEQUEUE(&ifp->if_snd, m);		if (m == 0)			break;#if NBPFILTER > 0		/*		 * If BPF is listening on this interface, let it see the		 * packet before we commit it to the wire.		 */		if (ifp->if_bpf)			bpf_mtap(ifp->if_bpf, m);#endif		/*		 * Copy the mbuf chain into the transmit buffer.		 */		len = hme_put(sc, bix, m);		/*		 * Initialize transmit registers and start transmission.		 */		sc->sc_desc->hme_txd[bix].tx_flags =		    HME_TXD_OWN | HME_TXD_SOP | HME_TXD_EOP |		    (len & HME_TXD_SIZE);		sc->sc_txr->tx_pnding = TXR_TP_DMAWAKEUP;		if (++bix == HME_TX_RING_SIZE)			bix = 0;		if (++sc->sc_no_td == HME_TX_RING_SIZE) {			ifp->if_flags |= IFF_OACTIVE;			break;		}	}	sc->sc_last_td = bix;}#define MAX_STOP_TRIES	16voidhmestop(sc)	struct hme_softc *sc;{	int tries = 0;	sc->sc_gr->reset = GR_RESET_ALL;	while (sc->sc_gr->reset && (tries != MAX_STOP_TRIES))		DELAY(20);	if (tries == MAX_STOP_TRIES)		printf("%s: stop failed\n", sc->sc_dev.dv_xname);	sc->sc_mii.mii_media_status &= ~IFM_ACTIVE;}/* * Reset interface. */voidhmereset(sc)	struct hme_softc *sc;{	int s;	s = splnet();	hmestop(sc);	hmeinit(sc);	splx(s);}/* * Device timeout/watchdog routine. Entered if the device neglects to generate * an interrupt after a transmit has been started on it. */voidhmewatchdog(ifp)	struct ifnet *ifp;{	struct hme_softc *sc = ifp->if_softc;	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);	++sc->sc_arpcom.ac_if.if_oerrors;	hmereset(sc);}inthmeioctl(ifp, cmd, data)	struct ifnet *ifp;	u_long cmd;	caddr_t data;{	struct hme_softc *sc = ifp->if_softc;	struct ifaddr *ifa = (struct ifaddr *)data;	struct ifreq *ifr = (struct ifreq *)data;	int s, error = 0;	s = splimp();	if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {		splx(s);		return error;	}	switch (cmd) {	case SIOCSIFADDR:		ifp->if_flags |= IFF_UP;		switch (ifa->ifa_addr->sa_family) {#ifdef INET		case AF_INET:			hmeinit(sc);			arp_ifinit(&sc->sc_arpcom, ifa);			break;#endif /* INET */#ifdef NS		/* XXX - This code is probably wrong. */		case AF_NS:		    {			struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;			if (ns_nullhost(*ina))				ina->x_host = 				    *(union ns_host *)(sc->sc_arpcom.ac_enaddr);			else				bcopy(ina->x_host.c_host,				    sc->sc_arpcom.ac_enaddr,				    sizeof(sc->sc_arpcom.ac_enaddr));			/* Set new address. */			hmeinit(sc);			break;		    }#endif /* NS */		default:			hmeinit(sc);			break;		}		break;	case SIOCSIFFLAGS:		if ((ifp->if_flags & IFF_UP) == 0 &&		    (ifp->if_flags & IFF_RUNNING) != 0) {			/*			 * If interface is marked down and it is running, then			 * stop it.			 */			hmestop(sc);			ifp->if_flags &= ~IFF_RUNNING;		} else if ((ifp->if_flags & IFF_UP) != 0 &&			   (ifp->if_flags & IFF_RUNNING) == 0) {			/*			 * If interface is marked up and it is stopped, then			 * start it.			 */			hmeinit(sc);		} else {			/*			 * Reset the interface to pick up changes in any other			 * flags that affect hardware registers.			 */			hmestop(sc);			hmeinit(sc);		}#ifdef IEDEBUG   		if (ifp->if_flags & IFF_DEBUG)			sc->sc_debug = IED_ALL;		else			sc->sc_debug = 0;#endif		break;	case SIOCADDMULTI:	case SIOCDELMULTI:		error = (cmd == SIOCADDMULTI) ?			ether_addmulti(ifr, &sc->sc_arpcom):			ether_delmulti(ifr, &sc->sc_arpcom);		if (error == ENETRESET) {			/*			 * Multicast list has changed; set the hardware filter			 * accordingly.			 */			hme_mcreset(sc);			error = 0;		}		break;	case SIOCGIFMEDIA:	case SIOCSIFMEDIA:		error = ifmedia_ioctl(ifp, ifr,  &sc->sc_mii.mii_media, cmd);		break;	default:		error = EINVAL;	}	splx(s);	return error;}voidhme_meminit(sc)	struct hme_softc *sc;{	struct hme_desc *desc;	int i;	if (sc->sc_desc_dva == NULL)		sc->sc_desc_dva = (struct hme_desc *) dvma_malloc(		    sizeof(struct hme_desc), &sc->sc_desc, M_NOWAIT);	if (sc->sc_bufs_dva == NULL)		sc->sc_bufs_dva = (struct hme_bufs *) dvma_malloc(		    sizeof(struct hme_bufs), &sc->sc_bufs, M_NOWAIT);	desc = sc->sc_desc;	/*	 * Setup TX descriptors	 */	sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;	for (i = 0; i < HME_TX_RING_SIZE; i++) {		desc->hme_txd[i].tx_addr =		    (u_int32_t) &sc->sc_bufs_dva->tx_buf[i][0];		desc->hme_txd[i].tx_flags = 0;	}	/*	 * Setup RX descriptors	 */	sc->sc_last_rd = 0;	for (i = 0; i < HME_RX_RING_SIZE; i++) {		desc->hme_rxd[i].rx_addr =		    (u_int32_t) &sc->sc_bufs_dva->rx_buf[i][0];		desc->hme_rxd[i].rx_flags = HME_RXD_OWN |		    ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);	}}voidhmeinit(sc)	struct hme_softc *sc;{	u_int32_t c;	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	struct hme_tcvr *tcvr = sc->sc_tcvr;	struct hme_cr *cr = sc->sc_cr;	struct hme_gr *gr = sc->sc_gr;	struct hme_txr *txr = sc->sc_txr;	struct hme_rxr *rxr = sc->sc_rxr;	hme_poll_stop(sc);	hmestop(sc);	hme_meminit(sc);	tcvr->int_mask = 0xffff;	c = tcvr->cfg;	if (sc->sc_flags & HME_FLAG_FENABLE)		tcvr->cfg = c & ~(TCVR_CFG_BENABLE);	else		tcvr->cfg = c | TCVR_CFG_BENABLE;	hme_reset_tx(sc);	hme_reset_rx(sc);	cr->rand_seed = sc->sc_arpcom.ac_enaddr[5] |	    ((sc->sc_arpcom.ac_enaddr[4] << 8) & 0x3f00);	cr->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |			   sc->sc_arpcom.ac_enaddr[1];	cr->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |			   sc->sc_arpcom.ac_enaddr[3];	cr->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |			   sc->sc_arpcom.ac_enaddr[5];	cr->jsize = HME_DEFAULT_JSIZE;	cr->ipkt_gap1 = HME_DEFAULT_IPKT_GAP1;	cr->ipkt_gap2 = HME_DEFAULT_IPKT_GAP2;	rxr->rx_ring = (u_int32_t)&sc->sc_desc_dva->hme_rxd[0];	txr->tx_ring = (u_int32_t)&sc->sc_desc_dva->hme_txd[0];	if (sc->sc_burst & SBUS_BURST_64)		gr->cfg = GR_CFG_BURST64;	else if (sc->sc_burst & SBUS_BURST_32)		gr->cfg = GR_CFG_BURST32;	else if (sc->sc_burst & SBUS_BURST_16)		gr->cfg = GR_CFG_BURST16;	else {		printf("%s: burst size unknown\n", sc->sc_dev.dv_xname);		gr->cfg = 0;	}	gr->imask = GR_IMASK_SENTFRAME | GR_IMASK_TXPERR |	              GR_IMASK_GOTFRAME | GR_IMASK_RCNTEXP;	txr->tx_rsize = (HME_TX_RING_SIZE >> TXR_RSIZE_SHIFT) - 1;	txr->cfg |= TXR_CFG_DMAENABLE;	c = RXR_CFG_DMAENABLE | (HME_RX_OFFSET << 3) | (HME_RX_CSUMLOC << 16);#if HME_RX_RING_SIZE == 32	c |= RXR_CFG_RINGSIZE32;#elif HME_RX_RING_SIZE == 64	c |= RXR_CFG_RINGSIZE64;#elif HME_RX_RING_SIZE == 128	c |= RXR_CFG_RINGSIZE128;#elif HME_RX_RING_SIZE == 256	c |= RXR_CFG_RINGSIZE256;#else#error "HME_RX_RING_SIZE must be 32, 64, 128, or 256."#endif	rxr->cfg = c;	DELAY(20);	if (c != rxr->cfg)	/* the receiver sometimes misses bits */	    printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);	cr->rx_cfg = 0;	hme_mcreset(sc);	DELAY(10);	cr->tx_cfg |= CR_TXCFG_DGIVEUP;	c = CR_XCFG_ODENABLE;	if (sc->sc_flags & HME_FLAG_LANCE)		c |= (HME_DEFAULT_IPKT_GAP0 << 5) | CR_XCFG_LANCE;	cr->xif_cfg = c;	cr->tx_cfg |= CR_TXCFG_ENABLE;	/* enable tx */	cr->rx_cfg |= CR_RXCFG_ENABLE;	/* enable rx */	mii_mediachg(&sc->sc_mii);	ifp->if_flags |= IFF_RUNNING;	ifp->if_flags &= ~IFF_OACTIVE;	ifp->if_timer = 0;}static voidhme_poll_stop(sc)	struct hme_softc *sc;{	struct hme_tcvr *tcvr = sc->sc_tcvr;	/* if not polling, or polling not enabled, we're done. */	if ((sc->sc_flags & (HME_FLAG_POLLENABLE | HME_FLAG_POLL)) != 	    (HME_FLAG_POLLENABLE | HME_FLAG_POLL))		return;	/* Turn off MIF interrupts, and diable polling */	tcvr->int_mask = 0xffff;        tcvr->cfg &= ~(TCVR_CFG_PENABLE);	sc->sc_flags &= ~(HME_FLAG_POLL);	DELAY(200);}#define RESET_TRIES	32static voidhme_reset_tx(sc)	struct hme_softc *sc;{	int tries = RESET_TRIES;	struct hme_cr *cr = sc->sc_cr;	cr->tx_swreset = 0;	while (tries-- && (cr->tx_swreset & 1))		DELAY(20);	if (!tries)		printf("%s: reset tx failed\n", sc->sc_dev.dv_xname);}static voidhme_reset_rx(sc)	struct hme_softc *sc;{	int tries = RESET_TRIES;	struct hme_cr *cr = sc->sc_cr;	cr->rx_swreset = 0;	while (tries-- && (cr->rx_swreset & 1))		DELAY(20);	if (!tries)		printf("%s: reset rx failed\n", sc->sc_dev.dv_xname);}/* * mif interrupt */static inthme_mint(sc, why)	struct hme_softc *sc;	u_int32_t why;{	printf("%s: link status changed\n", sc->sc_dev.dv_xname);	hme_poll_stop(sc);	return 1;}/* * transmit interrupt */static inthme_tint(sc)	struct hme_softc *sc;{	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	struct hme_cr *cr = sc->sc_cr;	int bix;	struct hme_txd txd;	/*	 * Get collision counters	 */	ifp->if_collisions += cr->ex_ctr + cr->lt_ctr + cr->fc_ctr + cr->nc_ctr;	cr->ex_ctr = 0;	cr->lt_ctr = 0;	cr->fc_ctr = 0;	cr->nc_ctr = 0;	bix = sc->sc_first_td;	for (;;) {		if (sc->sc_no_td <= 0)			break;		bcopy(&sc->sc_desc->hme_txd[bix], &txd, sizeof(txd));		if (txd.tx_flags & HME_TXD_OWN)			break;		ifp->if_flags &= ~IFF_OACTIVE;		ifp->if_opackets++;		if (++bix == HME_TX_RING_SIZE)			bix = 0;		--sc->sc_no_td;	}	sc->sc_first_td = bix;	hmestart(ifp);	if (sc->sc_no_td == 0)		ifp->if_timer = 0;	return 1;}static inthme_rint(sc)	struct hme_softc *sc;{	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	int bix, len;	struct hme_rxd rxd;	bix = sc->sc_last_rd;	for (;;) {		bcopy(&sc->sc_desc->hme_rxd[bix], &rxd, sizeof(rxd));		len = rxd.rx_flags >> 16;		if (rxd.rx_flags & HME_RXD_OWN)			break;		if (rxd.rx_flags & HME_RXD_OVERFLOW)			ifp->if_ierrors++;		else			hme_read(sc, bix, len);		rxd.rx_flags = HME_RXD_OWN |		    ((HME_RX_PKT_BUF_SZ - HME_RX_OFFSET) << 16);		bcopy(&rxd, &sc->sc_desc->hme_rxd[bix], sizeof(rxd));		if (++bix == HME_RX_RING_SIZE)			bix = 0;	}	sc->sc_last_rd = bix;	return 1;}/* * error interrupt */static inthme_eint(sc, why)	struct hme_softc *sc;	u_int32_t why;{	if (why & GR_STAT_ALL_ERRORS) {		printf("%s: stat=%b, resetting.\n", sc->sc_dev.dv_xname,		    why, GR_STAT_BITS);		hmereset(sc);	}	return 1;}/* * Interrupt handler */inthmeintr(v)	void *v;{	struct hme_softc *sc = (struct hme_softc *)v;	struct hme_gr *gr = sc->sc_gr;	u_int32_t why;	int r = 0;	why = gr->stat;	if (why & GR_STAT_ALL_ERRORS)		r |= hme_eint(sc, why);	if (why & GR_STAT_MIFIRQ)		r |= hme_mint(sc, why);	if (why & (GR_STAT_TXALL | GR_STAT_HOSTTOTX))		r |= hme_tint(sc);	if (why & GR_STAT_RXTOHOST)		r |= hme_rint(sc);	return (r);}static struct mbuf *hme_get(sc, idx, totlen)	struct hme_softc *sc;	int idx, totlen;{	struct ifnet *ifp = &sc->sc_arpcom.ac_if;	struct mbuf *m;	struct mbuf *top, **mp;	int len, pad, boff = 0;	MGETHDR(m, M_DONTWAIT, MT_DATA);	if (m == NULL)		return NULL;	m->m_pkthdr.rcvif = ifp;	m->m_pkthdr.len = totlen;	pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);	m->m_data += pad;	len = MHLEN - pad;	top = NULL;	mp = &top;	while (totlen > 0) {		if (top) {			MGET(m, M_DONTWAIT, MT_DATA);			if (m == NULL) {				m_freem(top);				return NULL;			}			len = MLEN;		}		if (top && totlen >= MINCLSIZE) {			MCLGET(m, M_DONTWAIT);			if (m->m_flags & M_EXT)				len = MCLBYTES;		}		m->m_len = len = min(totlen, len);		bcopy(&sc->sc_bufs->rx_buf[idx][boff + HME_RX_OFFSET],		    mtod(m, caddr_t), len);		boff += len;		totlen -= len;		*mp = m;		mp = &m->m_next;	}	return top;}