wbflush(); #else
struct mtd *mtd_alloc __P((void));int sngetaddr __P((struct sn_softc *sc));int sninit __P((int unit));int snstop __P((int unit));int sonicput __P((struct sn_softc *sc, struct mbuf *m0));intsnmatch(parent, match, aux)	struct device *parent;	void *match, *aux;{	struct cfdata *cf = match;	struct confargs *ca = aux;	/* XXX CHECK BUS */	/* make sure that we're looking for this type of device. */	if (!BUS_MATCHNAME(ca, "sonic"))		return (0);	return (1);}/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */voidsnattach(parent, self, aux)	struct device *parent, *self;	void   *aux;{	struct sn_softc *sc = (void *)self;	struct confargs *ca = aux;	struct ifnet *ifp = &sc->sc_if;	struct cfdata *cf = sc->sc_dev.dv_cfdata;	int p, pp;	sc->sc_csr = (struct sonic_reg *)BUS_CVTADDR(ca);	sc->dma = &sc->__dma;	sn_dma_init(sc->dma, FRAGMAX * NTDA			   + (NRBA * RBASIZE / PICA_DMA_PAGE_SIZE) + 1			   + (DESC_SIZE * 2 / PICA_DMA_PAGE_SIZE) + 1);/* * because the sonic is basicly 16bit device it 'concatenates' * a higher buffer address to a 16 bit offset this will cause wrap * around problems near the end of 64k !! */	p = SONICBUF;	pp = SONICBUF - (FRAGMAX * NTDA * PICA_DMA_PAGE_SIZE);	if ((p ^ (p + RRASIZE + CDASIZE)) & 0x10000)		p = (p + 0x10000) & ~0xffff;	p_rra = (struct RXrsrc *) p;	v_rra = (struct RXrsrc *)(p - pp + sc->dma->dma_va);	p += RRASIZE;	p_cda = (struct CDA *) p;	v_cda = (struct CDA *)(p - pp + sc->dma->dma_va);	p += CDASIZE;	if ((p ^ (p + RDASIZE)) & 0x10000)		p = (p + 0x10000) & ~0xffff;	p_rda = (struct RXpkt *) p;	v_rda = (struct RXpkt *)(p - pp + sc->dma->dma_va);	p += RDASIZE;	if ((p ^ (p + TDASIZE)) & 0x10000)		p = (p + 0x10000) & ~0xffff;	p_tda = (struct TXpkt *) p;	v_tda = (struct TXpkt *)(p - pp + sc->dma->dma_va);	p += TDASIZE;	p += PICA_DMA_PAGE_SIZE - (p & (PICA_DMA_PAGE_SIZE -1));	p_rba = (char *)p;	v_rba = (char *)(p - pp + sc->dma->dma_va);	p += NRBA * RBASIZE;	DMA_MAP(sc->dma, (caddr_t)SONICBUF, p - SONICBUF, SONICBUF - pp);	sngetaddr(sc);	printf(" address %s\n", ether_sprintf(sc->sc_enaddr));#if 0printf("\nsonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n",	p_rra, p_cda, p_rda, p_tda, p_rba);printf("sonic buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x rba=0x%x\n",	v_rra, v_cda, v_rda, v_tda, v_rba);printf("mapped to offset 0x%x size 0x%x\n", SONICBUF - pp, p - SONICBUF);#endif	BUS_INTR_ESTABLISH(ca, (intr_handler_t)snintr, (void *)sc);	ifp->if_name = "sn";	ifp->if_unit = sc->sc_dev.dv_unit;	ifp->if_ioctl = snioctl;	ifp->if_start = snstart;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;	ifp->if_watchdog = snwatchdog;#if NBPFILTER > 0	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif	if_attach(ifp);	ether_ifattach(ifp);}intsnioctl(ifp, cmd, data)	struct ifnet *ifp;	u_long cmd;	caddr_t data;{	struct ifaddr *ifa;	struct sn_softc *sc = sncd.cd_devs[ifp->if_unit];	int     s = splimp(), err = 0;	int	temp;	switch (cmd) {	case SIOCSIFADDR:		ifa = (struct ifaddr *)data;		ifp->if_flags |= IFF_UP;		switch (ifa->ifa_addr->sa_family) {#ifdef INET		case AF_INET:			(void)sninit(ifp->if_unit);			arp_ifinit(&sc->sc_ac, ifa);			break;#endif#ifdef NS		case AF_NS:			{				struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);				if (ns_nullhost(*ina)) {					ina->x_host = *(union ns_host *)(sc->sc_addr);				} else {					/* XXX					 * add an extra i/f address to					 * sonic filter					 */				}			}			(void)sninit(ifp->if_unit);			break;#endif	/* NS */		default:			(void)sninit(ifp->if_unit);			break;		}		break;	case SIOCSIFFLAGS:		if ((ifp->if_flags & IFF_UP) == 0 &&		    ifp->if_flags & IFF_RUNNING) {			snstop(ifp->if_unit);			ifp->if_flags &= ~IFF_RUNNING;		} else if (ifp->if_flags & IFF_UP &&		    (ifp->if_flags & IFF_RUNNING) == 0)			(void)sninit(ifp->if_unit);		/*		 * If the state of the promiscuous bit changes, the interface		 * must be reset to effect the change.		 */		if (((ifp->if_flags ^ sc->sc_iflags) & IFF_PROMISC) &&		    (ifp->if_flags & IFF_RUNNING)) {			sc->sc_iflags = ifp->if_flags;			printf("change in flags\n");			temp = sc->sc_if.if_flags & IFF_UP;			snreset(sc);			sc->sc_if.if_flags |= temp;			snstart(ifp);		}		break;	case SIOCADDMULTI:	case SIOCDELMULTI:		if(cmd == SIOCADDMULTI)			err = ether_addmulti((struct ifreq *)data, &sc->sc_ac);		else			err = ether_delmulti((struct ifreq *)data, &sc->sc_ac);		if (err == ENETRESET) {			/*			 * Multicast list has changed; set the hardware			 * filter accordingly. But remember UP flag!			 */			temp = sc->sc_if.if_flags & IFF_UP;			snreset(sc);			sc->sc_if.if_flags |= temp;			err = 0;		}		break;	default:		err = EINVAL;	}	splx(s);	return (err);}/* * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. */voidsnstart(ifp)	struct ifnet *ifp;{	struct sn_softc *sc = sncd.cd_devs[ifp->if_unit];	struct mbuf *m;	int	len;	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)		return;	IF_DEQUEUE(&sc->sc_if.if_snd, m);	if (m == 0)		return;	/*	 * If there is nothing in the o/p queue, and there is room in	 * the Tx ring, then send the packet directly.  Otherwise append	 * it to the o/p queue.	 */	len = sonicput(sc, m);#if NBPFILTER > 0	/*	 * If bpf is listening on this interface, let it	 * see the packet before we commit it to the wire.	 */	if (sc->sc_if.if_bpf)		bpf_mtap(sc->sc_if.if_bpf, m);#endif	sc->sc_if.if_opackets++;	/* # of pkts */	sc->sc_sum.ls_opacks++;		/* # of pkts */}/* * This is called from sonicioctl() when /etc/ifconfig is run to set * the address or switch the i/f on. */void caminitialise __P((void));void camentry __P((int, u_char *ea));void camprogram __P((struct sn_softc *));void initialise_tda __P((struct sn_softc *));void initialise_rda __P((struct sn_softc *));void initialise_rra __P((struct sn_softc *));/* * reset and restart the SONIC.  Called in case of fatal * hardware/software errors. */voidsnreset(sc)	struct sn_softc *sc;{	printf("snreset\n");	snstop(sc->sc_dev.dv_unit);	sninit(sc->sc_dev.dv_unit);}int sninit(unit)	int unit;{	struct sn_softc *sc = sncd.cd_devs[unit];	struct sonic_reg *csr = sc->sc_csr;	int s, error;	if (sc->sc_if.if_flags & IFF_RUNNING)		/* already running */		return (0);	s = splimp();	csr->s_cr = CR_RST;	/* s_dcr only accessable reset mode! */	/* config it */	csr->s_dcr = DCR_LBR | DCR_SYNC | DCR_WAIT0 | DCR_DW32 | DCR_DMABLOCK |	    DCR_RFT16 | DCR_TFT16;	csr->s_rcr = RCR_BRD | RCR_LBNONE;	csr->s_imr = IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_HBLEN | IMR_LCDEN;	/* clear pending interrupts */	csr->s_isr = 0x7fff;	/* clear tally counters */	csr->s_crct = -1;	csr->s_faet = -1;	csr->s_mpt = -1;	initialise_tda(sc);	initialise_rda(sc);	initialise_rra(sc);	/* enable the chip */	csr->s_cr = 0;	wbflush();	/* program the CAM with our address */	caminitialise();	camentry(0, sc->sc_enaddr);	camprogram(sc);	/* get it to read resource descriptors */	csr->s_cr = CR_RRRA;	wbflush();	while (csr->s_cr & CR_RRRA)		continue;	/* enable rx */	csr->s_cr = CR_RXEN;	wbflush();	/* flag interface as "running" */	sc->sc_if.if_flags |= IFF_RUNNING;	splx(s);	return (0);bad:	snstop(sc->sc_dev.dv_unit);	return (error);}/* * close down an interface and free its buffers * Called on final close of device, or if sninit() fails * part way through. */int snstop(unit)	int unit;{	struct sn_softc *sc = sncd.cd_devs[unit];	struct mtd *mtd;	int s = splimp();	/* stick chip in reset */	sc->sc_csr->s_cr = CR_RST;	wbflush();	/* free all receive buffers (currently static so nothing to do) */	/* free all pending transmit mbufs */	while (mtd = mtdhead) {		mtdhead = mtdhead->mtd_link;		if (mtd->mtd_mbuf)			m_freem(mtd->mtd_mbuf);		mtd->mtd_mbuf = 0;		mtd_free(mtd);	}	mtdnext = mtd_alloc();	sc->sc_if.if_timer = 0;	sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);	splx(s);	return (0);}/* * Called if any Tx packets remain unsent after 5 seconds, * In all cases we just reset the chip, and any retransmission * will be handled by higher level protocol timeouts. */voidsnwatchdog(unit)	int unit;{	struct sn_softc *sc = sncd.cd_devs[unit];	int temp;	if (mtdhead && mtdhead->mtd_mbuf) {		/* something still pending for transmit */		if (mtdhead->mtd_txp->status == 0)			log(LOG_ERR, "%s%d: Tx - timeout\n",			    sc->sc_if.if_name, sc->sc_if.if_unit);		else			log(LOG_ERR, "%s%d: Tx - lost interrupt\n",			    sc->sc_if.if_name, sc->sc_if.if_unit);		temp = sc->sc_if.if_flags & IFF_UP;		snreset(sc);		sc->sc_if.if_flags |= temp;	}}/* * stuff packet into sonic (at splimp)*/int sonicput(sc, m0)	struct sn_softc *sc;	struct mbuf *m0;{	struct sonic_reg *csr = sc->sc_csr;	struct TXpkt *txp;	struct mtd *mtdnew;	struct mbuf *m;	int len = 0, fr = 0;	int i;	int fragoffset;		/* Offset in viritual dma space for fragment */	/* grab the replacement mtd */	if ((mtdnew = mtd_alloc()) == 0)		return (0);	/* this packet goes to mdtnext fill in the TDA */	mtdnext->mtd_mbuf = m0;	txp = mtdnext->mtd_txp;	SWR(txp->config, 0);	fragoffset = (txp - p_tda) * FRAGMAX * PICA_DMA_PAGE_SIZE;	/*	 * Now fill in the fragments. Each fragment maps to it's	 * own dma page. Fragments crossing a dma page boundary	 * are split up in two fragments. This is somewhat stupid	 * because the dma mapper can do the work, but it helps	 * keeping the fragments in order. (read lazy programmer).	 */	for (m = m0; m; m = m->m_next) {		unsigned va = (unsigned) mtod(m, caddr_t);		int resid = m->m_len;		MachHitFlushDCache(va, resid);		len += resid;		DMA_MAP(sc->dma, (caddr_t)va, resid, fragoffset);		while (resid) {			unsigned pa;			unsigned n;			pa = sc->dma->dma_va + (va & PGOFSET) + fragoffset;			n = resid;			if (n > NBPG - (va & PGOFSET)) {				n = NBPG - (va & PGOFSET);			}			if (fr < FRAGMAX) {				SWR(txp->u[fr].frag_ptrlo, LOWER(pa));				SWR(txp->u[fr].frag_ptrhi, UPPER(pa));				SWR(txp->u[fr].frag_size, n);			}			fr++;			va += n;			resid -= n;			fragoffset += PICA_DMA_PAGE_SIZE;		}	}	if (fr > FRAGMAX) {		mtd_free(mtdnew);		m_freem(m0);		log(LOG_ERR, "%s%d: tx too many fragments %d\n",		    sc->sc_if.if_name, sc->sc_if.if_unit, fr);		sc->sc_if.if_oerrors++;		return (len);	}	/*	 * pad out last fragment for minimum size	 * 	 * XXX is this incorrectly done? does it cause random bytes of	 * mem to be sent? if so, it should instead point to a zero'd	 * zone of mem.	 */	if (len < ETHERMIN + sizeof(struct ether_header)) {		int pad = ETHERMIN + sizeof(struct ether_header) - len;		SWR(txp->u[fr - 1].frag_size, pad + SRD(txp->u[fr - 1].frag_size));		len = ETHERMIN + sizeof(struct ether_header);	}	SWR(txp->frag_count, fr);	SWR(txp->pkt_size, len);	/* link onto the next mtd that will be used */	SWR(txp->u[fr].tlink, LOWER(v_tda + (mtdnew->mtd_txp - p_tda)) | EOL);	if (mtdhead == 0) {		/* no current transmit list start with this one */		mtdtail = mtdhead = mtdnext;		csr->s_ctda = LOWER(v_tda + (txp - p_tda));	} else {		/*		 * have a transmit list append it to end note		 * mtdnext is already physicaly linked to mtdtail in		 * mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink		 */		SWR(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink,		    SRD(mtdtail->mtd_txp->u[mtdtail->mtd_txp->frag_count].tlink) & ~EOL);		mtdtail = mtdnext;	}	mtdnext->mtd_link = mtdnew;	mtdnext = mtdnew;	/* make sure chip is running */	wbflush();	csr->s_cr = CR_TXP;	wbflush();	sc->sc_if.if_timer = 5;	/* 5 seconds to watch for failing to transmit */	return (len);}/* *  Read out the ethernet address from the cam. It is stored *  there by the boot when doing a loopback test. Thus we don't *  have to fetch it from nv ram. */int sngetaddr(sc)	struct sn_softc *sc;{	unsigned i, x, y;	char   *cp, *ea;#if 0	sc->sc_csr->s_cr = CR_RST;	sc->sc_csr->s_cep = 0;	i = sc->sc_csr->s_cap2;	sc->sc_enaddr[5] = i >> 8;	sc->sc_enaddr[4] = i;	i = sc->sc_csr->s_cap1;	sc->sc_enaddr[3] = i >> 8;	sc->sc_enaddr[2] = i;	i = sc->sc_csr->s_cap0;	sc->sc_enaddr[1] = i >> 8;	sc->sc_enaddr[0] = i;	sc->sc_csr->s_cr = 0;#endif	sc->sc_enaddr[0] = 0x08;	sc->sc_enaddr[1] = 0x00;	sc->sc_enaddr[2] = 0x20;	sc->sc_enaddr[3] = 0xa0;	sc->sc_enaddr[4] = 0x66;	sc->sc_enaddr[5] = 0x54;		return (0);}void sonictxint __P((struct sn_softc *));void sonicrxint __P((struct sn_softc *));int sonic_read __P((struct sn_softc *, struct RXpkt *));struct mbuf *sonic_get __P((struct sn_softc *, struct ether_header *, int));void mtd_free(mtd)	struct mtd *mtd;{	mtd->mtd_link = mtdfree;	mtdfree = mtd;}struct mtd *mtd_alloc(){	struct mtd *mtd = mtdfree;	if (mtd) {		mtdfree = mtd->mtd_link;		mtd->mtd_link = 0;	}	return (mtd);}