xref: /openbsd-src/sys/dev/ic/aic6915.c (revision cf96265bb25b08cea5a0b5654925448396fd9df0)
1*cf96265bSbluhm /*	$OpenBSD: aic6915.c,v 1.25 2023/11/10 15:51:20 bluhm Exp $	*/
22f5860a2Smartin /*	$NetBSD: aic6915.c,v 1.15 2005/12/24 20:27:29 perry Exp $	*/
32f5860a2Smartin 
42f5860a2Smartin /*-
52f5860a2Smartin  * Copyright (c) 2001 The NetBSD Foundation, Inc.
62f5860a2Smartin  * All rights reserved.
72f5860a2Smartin  *
82f5860a2Smartin  * This code is derived from software contributed to The NetBSD Foundation
92f5860a2Smartin  * by Jason R. Thorpe.
102f5860a2Smartin  *
112f5860a2Smartin  * Redistribution and use in source and binary forms, with or without
122f5860a2Smartin  * modification, are permitted provided that the following conditions
132f5860a2Smartin  * are met:
142f5860a2Smartin  * 1. Redistributions of source code must retain the above copyright
152f5860a2Smartin  *    notice, this list of conditions and the following disclaimer.
162f5860a2Smartin  * 2. Redistributions in binary form must reproduce the above copyright
172f5860a2Smartin  *    notice, this list of conditions and the following disclaimer in the
182f5860a2Smartin  *    documentation and/or other materials provided with the distribution.
192f5860a2Smartin  *
202f5860a2Smartin  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
212f5860a2Smartin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
222f5860a2Smartin  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
232f5860a2Smartin  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
242f5860a2Smartin  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
252f5860a2Smartin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
262f5860a2Smartin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
272f5860a2Smartin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
282f5860a2Smartin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
292f5860a2Smartin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
302f5860a2Smartin  * POSSIBILITY OF SUCH DAMAGE.
312f5860a2Smartin  */
322f5860a2Smartin 
332f5860a2Smartin /*
342f5860a2Smartin  * Device driver for the Adaptec AIC-6915 (``Starfire'')
352f5860a2Smartin  * 10/100 Ethernet controller.
362f5860a2Smartin  */
372f5860a2Smartin 
382f5860a2Smartin #include "bpfilter.h"
392f5860a2Smartin 
402f5860a2Smartin #include <sys/param.h>
41a4adbbcbSmartin #include <sys/endian.h>
422f5860a2Smartin #include <sys/systm.h>
432f5860a2Smartin #include <sys/timeout.h>
442f5860a2Smartin #include <sys/mbuf.h>
452f5860a2Smartin #include <sys/malloc.h>
462f5860a2Smartin #include <sys/kernel.h>
472f5860a2Smartin #include <sys/socket.h>
482f5860a2Smartin #include <sys/ioctl.h>
492f5860a2Smartin #include <sys/errno.h>
502f5860a2Smartin #include <sys/device.h>
512f5860a2Smartin 
522f5860a2Smartin #include <net/if.h>
532f5860a2Smartin #include <net/if_dl.h>
542f5860a2Smartin 
552f5860a2Smartin #include <netinet/in.h>
562f5860a2Smartin #include <netinet/if_ether.h>
572f5860a2Smartin 
582f5860a2Smartin #include <net/if_media.h>
592f5860a2Smartin 
602f5860a2Smartin #if NBPFILTER > 0
612f5860a2Smartin #include <net/bpf.h>
622f5860a2Smartin #endif
632f5860a2Smartin 
642f5860a2Smartin #include <machine/bus.h>
652f5860a2Smartin #include <machine/intr.h>
662f5860a2Smartin 
672f5860a2Smartin #include <dev/mii/miivar.h>
682f5860a2Smartin 
692f5860a2Smartin #include <dev/ic/aic6915.h>
702f5860a2Smartin 
712f5860a2Smartin void	sf_start(struct ifnet *);
722f5860a2Smartin void	sf_watchdog(struct ifnet *);
732f5860a2Smartin int	sf_ioctl(struct ifnet *, u_long, caddr_t);
742f5860a2Smartin int	sf_init(struct ifnet *);
752f5860a2Smartin void	sf_stop(struct ifnet *, int);
762f5860a2Smartin 
772f5860a2Smartin void	sf_txintr(struct sf_softc *);
782f5860a2Smartin void	sf_rxintr(struct sf_softc *);
792f5860a2Smartin void	sf_stats_update(struct sf_softc *);
802f5860a2Smartin 
812f5860a2Smartin void	sf_reset(struct sf_softc *);
822f5860a2Smartin void	sf_macreset(struct sf_softc *);
832f5860a2Smartin void	sf_rxdrain(struct sf_softc *);
842f5860a2Smartin int	sf_add_rxbuf(struct sf_softc *, int);
852f5860a2Smartin uint8_t	sf_read_eeprom(struct sf_softc *, int);
862f5860a2Smartin void	sf_set_filter(struct sf_softc *);
872f5860a2Smartin 
882f5860a2Smartin int	sf_mii_read(struct device *, int, int);
892f5860a2Smartin void	sf_mii_write(struct device *, int, int, int);
902f5860a2Smartin void	sf_mii_statchg(struct device *);
912f5860a2Smartin 
922f5860a2Smartin void	sf_tick(void *);
932f5860a2Smartin 
942f5860a2Smartin int	sf_mediachange(struct ifnet *);
952f5860a2Smartin void	sf_mediastatus(struct ifnet *, struct ifmediareq *);
962f5860a2Smartin 
972f5860a2Smartin uint32_t sf_reg_read(struct sf_softc *, bus_addr_t);
982f5860a2Smartin void	sf_reg_write(struct sf_softc *, bus_addr_t , uint32_t);
992f5860a2Smartin 
1002f5860a2Smartin void	sf_set_filter_perfect(struct sf_softc *, int , uint8_t *);
1012f5860a2Smartin void	sf_set_filter_hash(struct sf_softc *, uint8_t *);
1022f5860a2Smartin 
1032f5860a2Smartin struct cfdriver sf_cd = {
1042f5860a2Smartin 	NULL, "sf", DV_IFNET
1052f5860a2Smartin };
1062f5860a2Smartin 
1072f5860a2Smartin #define	sf_funcreg_read(sc, reg)					\
1082f5860a2Smartin 	bus_space_read_4((sc)->sc_st, (sc)->sc_sh_func, (reg))
1092f5860a2Smartin #define	sf_funcreg_write(sc, reg, val)					\
1102f5860a2Smartin 	bus_space_write_4((sc)->sc_st, (sc)->sc_sh_func, (reg), (val))
1112f5860a2Smartin 
1122f5860a2Smartin uint32_t
sf_reg_read(struct sf_softc * sc,bus_addr_t reg)1132f5860a2Smartin sf_reg_read(struct sf_softc *sc, bus_addr_t reg)
1142f5860a2Smartin {
1152f5860a2Smartin 
1162f5860a2Smartin 	if (__predict_false(sc->sc_iomapped)) {
1172f5860a2Smartin 		bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoAccess,
1182f5860a2Smartin 		    reg);
1192f5860a2Smartin 		return (bus_space_read_4(sc->sc_st, sc->sc_sh,
1202f5860a2Smartin 		    SF_IndirectIoDataPort));
1212f5860a2Smartin 	}
1222f5860a2Smartin 
1232f5860a2Smartin 	return (bus_space_read_4(sc->sc_st, sc->sc_sh, reg));
1242f5860a2Smartin }
1252f5860a2Smartin 
1262f5860a2Smartin void
sf_reg_write(struct sf_softc * sc,bus_addr_t reg,uint32_t val)1272f5860a2Smartin sf_reg_write(struct sf_softc *sc, bus_addr_t reg, uint32_t val)
1282f5860a2Smartin {
1292f5860a2Smartin 
1302f5860a2Smartin 	if (__predict_false(sc->sc_iomapped)) {
1312f5860a2Smartin 		bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoAccess,
1322f5860a2Smartin 		    reg);
1332f5860a2Smartin 		bus_space_write_4(sc->sc_st, sc->sc_sh, SF_IndirectIoDataPort,
1342f5860a2Smartin 		    val);
1352f5860a2Smartin 		return;
1362f5860a2Smartin 	}
1372f5860a2Smartin 
1382f5860a2Smartin 	bus_space_write_4(sc->sc_st, sc->sc_sh, reg, val);
1392f5860a2Smartin }
1402f5860a2Smartin 
1412f5860a2Smartin #define	sf_genreg_read(sc, reg)						\
1422f5860a2Smartin 	sf_reg_read((sc), (reg) + SF_GENREG_OFFSET)
1432f5860a2Smartin #define	sf_genreg_write(sc, reg, val)					\
1442f5860a2Smartin 	sf_reg_write((sc), (reg) + SF_GENREG_OFFSET, (val))
1452f5860a2Smartin 
1462f5860a2Smartin /*
1472f5860a2Smartin  * sf_attach:
1482f5860a2Smartin  *
1492f5860a2Smartin  *	Attach a Starfire interface to the system.
1502f5860a2Smartin  */
1512f5860a2Smartin void
sf_attach(struct sf_softc * sc)1522f5860a2Smartin sf_attach(struct sf_softc *sc)
1532f5860a2Smartin {
1542f5860a2Smartin 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1552f5860a2Smartin 	int i, rseg, error;
1562f5860a2Smartin 	bus_dma_segment_t seg;
1572f5860a2Smartin 	u_int8_t enaddr[ETHER_ADDR_LEN];
1582f5860a2Smartin 
1592f5860a2Smartin 	timeout_set(&sc->sc_mii_timeout, sf_tick, sc);
1602f5860a2Smartin 
1612f5860a2Smartin 	/*
1622f5860a2Smartin 	 * If we're I/O mapped, the functional register handle is
1632f5860a2Smartin 	 * the same as the base handle.  If we're memory mapped,
1642f5860a2Smartin 	 * carve off a chunk of the register space for the functional
1652f5860a2Smartin 	 * registers, to save on arithmetic later.
1662f5860a2Smartin 	 */
1672f5860a2Smartin 	if (sc->sc_iomapped)
1682f5860a2Smartin 		sc->sc_sh_func = sc->sc_sh;
1692f5860a2Smartin 	else {
1702f5860a2Smartin 		if ((error = bus_space_subregion(sc->sc_st, sc->sc_sh,
1712f5860a2Smartin 		    SF_GENREG_OFFSET, SF_FUNCREG_SIZE, &sc->sc_sh_func)) != 0) {
1722f5860a2Smartin 			printf("%s: unable to sub-region functional "
1732f5860a2Smartin 			    "registers, error = %d\n", sc->sc_dev.dv_xname,
1742f5860a2Smartin 			    error);
1752f5860a2Smartin 			return;
1762f5860a2Smartin 		}
1772f5860a2Smartin 	}
1782f5860a2Smartin 
1792f5860a2Smartin 	/*
1802f5860a2Smartin 	 * Initialize the transmit threshold for this interface.  The
1812f5860a2Smartin 	 * manual describes the default as 4 * 16 bytes.  We start out
1822f5860a2Smartin 	 * at 10 * 16 bytes, to avoid a bunch of initial underruns on
1832f5860a2Smartin 	 * several platforms.
1842f5860a2Smartin 	 */
1852f5860a2Smartin 	sc->sc_txthresh = 10;
1862f5860a2Smartin 
1872f5860a2Smartin 	/*
1882f5860a2Smartin 	 * Allocate the control data structures, and create and load the
1892f5860a2Smartin 	 * DMA map for it.
1902f5860a2Smartin 	 */
1912f5860a2Smartin 	if ((error = bus_dmamem_alloc(sc->sc_dmat,
1922f5860a2Smartin 	    sizeof(struct sf_control_data), PAGE_SIZE, 0, &seg, 1, &rseg,
1932f5860a2Smartin 	    BUS_DMA_NOWAIT)) != 0) {
1942f5860a2Smartin 		printf("%s: unable to allocate control data, error = %d\n",
1952f5860a2Smartin 		    sc->sc_dev.dv_xname, error);
1962f5860a2Smartin 		goto fail_0;
1972f5860a2Smartin 	}
1982f5860a2Smartin 
1992f5860a2Smartin 	if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
2002f5860a2Smartin 	    sizeof(struct sf_control_data), (caddr_t *)&sc->sc_control_data,
2012f5860a2Smartin 	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
2022f5860a2Smartin 		printf("%s: unable to map control data, error = %d\n",
2032f5860a2Smartin 		    sc->sc_dev.dv_xname, error);
2042f5860a2Smartin 		goto fail_1;
2052f5860a2Smartin 	}
2062f5860a2Smartin 
2072f5860a2Smartin 	if ((error = bus_dmamap_create(sc->sc_dmat,
2082f5860a2Smartin 	    sizeof(struct sf_control_data), 1,
2092f5860a2Smartin 	    sizeof(struct sf_control_data), 0, BUS_DMA_NOWAIT,
2102f5860a2Smartin 	    &sc->sc_cddmamap)) != 0) {
2112f5860a2Smartin 		printf("%s: unable to create control data DMA map, "
2122f5860a2Smartin 		    "error = %d\n", sc->sc_dev.dv_xname, error);
2132f5860a2Smartin 		goto fail_2;
2142f5860a2Smartin 	}
2152f5860a2Smartin 
2162f5860a2Smartin 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cddmamap,
2172f5860a2Smartin 	    sc->sc_control_data, sizeof(struct sf_control_data), NULL,
2182f5860a2Smartin 	    BUS_DMA_NOWAIT)) != 0) {
2192f5860a2Smartin 		printf("%s: unable to load control data DMA map, error = %d\n",
2202f5860a2Smartin 		    sc->sc_dev.dv_xname, error);
2212f5860a2Smartin 		goto fail_3;
2222f5860a2Smartin 	}
2232f5860a2Smartin 
2242f5860a2Smartin 	/*
2252f5860a2Smartin 	 * Create the transmit buffer DMA maps.
2262f5860a2Smartin 	 */
2272f5860a2Smartin 	for (i = 0; i < SF_NTXDESC; i++) {
2282f5860a2Smartin 		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
2292f5860a2Smartin 		    SF_NTXFRAGS, MCLBYTES, 0, BUS_DMA_NOWAIT,
2302f5860a2Smartin 		    &sc->sc_txsoft[i].ds_dmamap)) != 0) {
2312f5860a2Smartin 			printf("%s: unable to create tx DMA map %d, "
2322f5860a2Smartin 			    "error = %d\n", sc->sc_dev.dv_xname, i, error);
2332f5860a2Smartin 			goto fail_4;
2342f5860a2Smartin 		}
2352f5860a2Smartin 	}
2362f5860a2Smartin 
2372f5860a2Smartin 	/*
2382f5860a2Smartin 	 * Create the receive buffer DMA maps.
2392f5860a2Smartin 	 */
2402f5860a2Smartin 	for (i = 0; i < SF_NRXDESC; i++) {
2412f5860a2Smartin 		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
2422f5860a2Smartin 		    MCLBYTES, 0, BUS_DMA_NOWAIT,
2432f5860a2Smartin 		    &sc->sc_rxsoft[i].ds_dmamap)) != 0) {
2442f5860a2Smartin 			printf("%s: unable to create rx DMA map %d, "
2452f5860a2Smartin 			    "error = %d\n", sc->sc_dev.dv_xname, i, error);
2462f5860a2Smartin 			goto fail_5;
2472f5860a2Smartin 		}
2482f5860a2Smartin 	}
2492f5860a2Smartin 
2502f5860a2Smartin 	/*
2512f5860a2Smartin 	 * Reset the chip to a known state.
2522f5860a2Smartin 	 */
2532f5860a2Smartin 	sf_reset(sc);
2542f5860a2Smartin 
2552f5860a2Smartin 	/*
2562f5860a2Smartin 	 * Read the Ethernet address from the EEPROM.
2572f5860a2Smartin 	 */
2582f5860a2Smartin 	for (i = 0; i < ETHER_ADDR_LEN; i++)
2592f5860a2Smartin 		enaddr[i] = sf_read_eeprom(sc, (15 + (ETHER_ADDR_LEN - 1)) - i);
2602f5860a2Smartin 
2612f5860a2Smartin 	printf(", address %s\n", ether_sprintf(enaddr));
2622f5860a2Smartin 
2632f5860a2Smartin #ifdef DEBUG
2642f5860a2Smartin 	if (sf_funcreg_read(sc, SF_PciDeviceConfig) & PDC_System64)
2652f5860a2Smartin 		printf("%s: 64-bit PCI slot detected\n", sc->sc_dev.dv_xname);
2662f5860a2Smartin #endif
2672f5860a2Smartin 
2682f5860a2Smartin 	/*
2692f5860a2Smartin 	 * Initialize our media structures and probe the MII.
2702f5860a2Smartin 	 */
2712f5860a2Smartin 	sc->sc_mii.mii_ifp = ifp;
2722f5860a2Smartin 	sc->sc_mii.mii_readreg = sf_mii_read;
2732f5860a2Smartin 	sc->sc_mii.mii_writereg = sf_mii_write;
2742f5860a2Smartin 	sc->sc_mii.mii_statchg = sf_mii_statchg;
2752f5860a2Smartin 	ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, sf_mediachange,
2762f5860a2Smartin 	    sf_mediastatus);
2772f5860a2Smartin 	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
2782f5860a2Smartin 	    MII_OFFSET_ANY, 0);
2792f5860a2Smartin 	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
2802f5860a2Smartin 		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
2812f5860a2Smartin 		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
2822f5860a2Smartin 	} else
2832f5860a2Smartin 		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
2842f5860a2Smartin 	bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
2852f5860a2Smartin 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
2862f5860a2Smartin 	ifp = &sc->sc_arpcom.ac_if;
2872f5860a2Smartin 	ifp->if_softc = sc;
2882f5860a2Smartin 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
2892f5860a2Smartin 	ifp->if_ioctl = sf_ioctl;
2902f5860a2Smartin 	ifp->if_start = sf_start;
2912f5860a2Smartin 	ifp->if_watchdog = sf_watchdog;
292*cf96265bSbluhm 	ifq_init_maxlen(&ifp->if_snd, SF_NTXDESC_MASK);
2932f5860a2Smartin 
2942f5860a2Smartin 	/*
2952f5860a2Smartin 	 * Attach the interface.
2962f5860a2Smartin 	 */
2972f5860a2Smartin 	if_attach(ifp);
2982f5860a2Smartin 	ether_ifattach(ifp);
2992f5860a2Smartin 	return;
3002f5860a2Smartin 
3012f5860a2Smartin 	/*
3022f5860a2Smartin 	 * Free any resources we've allocated during the failed attach
3032f5860a2Smartin 	 * attempt.  Do this in reverse order an fall through.
3042f5860a2Smartin 	 */
3052f5860a2Smartin  fail_5:
3062f5860a2Smartin 	for (i = 0; i < SF_NRXDESC; i++) {
3072f5860a2Smartin 		if (sc->sc_rxsoft[i].ds_dmamap != NULL)
3082f5860a2Smartin 			bus_dmamap_destroy(sc->sc_dmat,
3092f5860a2Smartin 			    sc->sc_rxsoft[i].ds_dmamap);
3102f5860a2Smartin 	}
3112f5860a2Smartin  fail_4:
3122f5860a2Smartin 	for (i = 0; i < SF_NTXDESC; i++) {
3132f5860a2Smartin 		if (sc->sc_txsoft[i].ds_dmamap != NULL)
3142f5860a2Smartin 			bus_dmamap_destroy(sc->sc_dmat,
3152f5860a2Smartin 			    sc->sc_txsoft[i].ds_dmamap);
3162f5860a2Smartin 	}
3172f5860a2Smartin 	bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
3182f5860a2Smartin  fail_3:
3192f5860a2Smartin 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
3202f5860a2Smartin  fail_2:
3212f5860a2Smartin 	bus_dmamem_unmap(sc->sc_dmat, (caddr_t) sc->sc_control_data,
3222f5860a2Smartin 	    sizeof(struct sf_control_data));
3232f5860a2Smartin  fail_1:
3242f5860a2Smartin 	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
3252f5860a2Smartin  fail_0:
3262f5860a2Smartin 	return;
3272f5860a2Smartin }
3282f5860a2Smartin 
3292f5860a2Smartin /*
3302f5860a2Smartin  * sf_start:		[ifnet interface function]
3312f5860a2Smartin  *
3322f5860a2Smartin  *	Start packet transmission on the interface.
3332f5860a2Smartin  */
3342f5860a2Smartin void
sf_start(struct ifnet * ifp)3352f5860a2Smartin sf_start(struct ifnet *ifp)
3362f5860a2Smartin {
3372f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
3382f5860a2Smartin 	struct mbuf *m0, *m;
3392f5860a2Smartin 	struct sf_txdesc0 *txd;
3402f5860a2Smartin 	struct sf_descsoft *ds;
3412f5860a2Smartin 	bus_dmamap_t dmamap;
3422f5860a2Smartin 	int error, producer, last = -1, opending, seg;
3432f5860a2Smartin 
3442f5860a2Smartin 	/*
3452f5860a2Smartin 	 * Remember the previous number of pending transmits.
3462f5860a2Smartin 	 */
3472f5860a2Smartin 	opending = sc->sc_txpending;
3482f5860a2Smartin 
3492f5860a2Smartin 	/*
3502f5860a2Smartin 	 * Find out where we're sitting.
3512f5860a2Smartin 	 */
3522f5860a2Smartin 	producer = SF_TXDINDEX_TO_HOST(
3532f5860a2Smartin 	    TDQPI_HiPrTxProducerIndex_get(
3542f5860a2Smartin 	    sf_funcreg_read(sc, SF_TxDescQueueProducerIndex)));
3552f5860a2Smartin 
3562f5860a2Smartin 	/*
3572f5860a2Smartin 	 * Loop through the send queue, setting up transmit descriptors
3582f5860a2Smartin 	 * until we drain the queue, or use up all available transmit
3592f5860a2Smartin 	 * descriptors.  Leave a blank one at the end for sanity's sake.
3602f5860a2Smartin 	 */
3612f5860a2Smartin 	while (sc->sc_txpending < (SF_NTXDESC - 1)) {
3622f5860a2Smartin 		/*
3632f5860a2Smartin 		 * Grab a packet off the queue.
3642f5860a2Smartin 		 */
365b5d83b91Sdlg 		m0 = ifq_deq_begin(&ifp->if_snd);
3662f5860a2Smartin 		if (m0 == NULL)
3672f5860a2Smartin 			break;
3682f5860a2Smartin 		m = NULL;
3692f5860a2Smartin 
3702f5860a2Smartin 		/*
3712f5860a2Smartin 		 * Get the transmit descriptor.
3722f5860a2Smartin 		 */
3732f5860a2Smartin 		txd = &sc->sc_txdescs[producer];
3742f5860a2Smartin 		ds = &sc->sc_txsoft[producer];
3752f5860a2Smartin 		dmamap = ds->ds_dmamap;
3762f5860a2Smartin 
3772f5860a2Smartin 		/*
3782f5860a2Smartin 		 * Load the DMA map.  If this fails, the packet either
3792f5860a2Smartin 		 * didn't fit in the allotted number of frags, or we were
3802f5860a2Smartin 		 * short on resources.  In this case, we'll copy and try
3812f5860a2Smartin 		 * again.
3822f5860a2Smartin 		 */
3832f5860a2Smartin 		if (bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
3842f5860a2Smartin 		    BUS_DMA_WRITE|BUS_DMA_NOWAIT) != 0) {
3852f5860a2Smartin 			MGETHDR(m, M_DONTWAIT, MT_DATA);
3862f5860a2Smartin 			if (m == NULL) {
387b5d83b91Sdlg 				ifq_deq_rollback(&ifp->if_snd, m0);
3882f5860a2Smartin 				printf("%s: unable to allocate Tx mbuf\n",
3892f5860a2Smartin 				    sc->sc_dev.dv_xname);
3902f5860a2Smartin 				break;
3912f5860a2Smartin 			}
3922f5860a2Smartin 			if (m0->m_pkthdr.len > MHLEN) {
3932f5860a2Smartin 				MCLGET(m, M_DONTWAIT);
3942f5860a2Smartin 				if ((m->m_flags & M_EXT) == 0) {
395b5d83b91Sdlg 					ifq_deq_rollback(&ifp->if_snd, m0);
3962f5860a2Smartin 					printf("%s: unable to allocate Tx "
3972f5860a2Smartin 					    "cluster\n", sc->sc_dev.dv_xname);
3982f5860a2Smartin 					m_freem(m);
3992f5860a2Smartin 					break;
4002f5860a2Smartin 				}
4012f5860a2Smartin 			}
4022f5860a2Smartin 			m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));
4032f5860a2Smartin 			m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
4042f5860a2Smartin 			error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
4052f5860a2Smartin 			    m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
4062f5860a2Smartin 			if (error) {
407b5d83b91Sdlg 				ifq_deq_rollback(&ifp->if_snd, m0);
4082f5860a2Smartin 				printf("%s: unable to load Tx buffer, "
4092f5860a2Smartin 				    "error = %d\n", sc->sc_dev.dv_xname, error);
410657454b1Sjsg 				m_freem(m);
4112f5860a2Smartin 				break;
4122f5860a2Smartin 			}
4132f5860a2Smartin 		}
4142f5860a2Smartin 
4152f5860a2Smartin 		/*
4162f5860a2Smartin 		 * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
4172f5860a2Smartin 		 */
418b5d83b91Sdlg 		ifq_deq_commit(&ifp->if_snd, m0);
4192f5860a2Smartin 		if (m != NULL) {
4202f5860a2Smartin 			m_freem(m0);
4212f5860a2Smartin 			m0 = m;
4222f5860a2Smartin 		}
4232f5860a2Smartin 
4242f5860a2Smartin 		/* Initialize the descriptor. */
4252f5860a2Smartin 		txd->td_word0 =
4262f5860a2Smartin 		    htole32(TD_W0_ID | TD_W0_CRCEN | m0->m_pkthdr.len);
4272f5860a2Smartin 		if (producer == (SF_NTXDESC - 1))
4282f5860a2Smartin 			txd->td_word0 |= TD_W0_END;
4292f5860a2Smartin 		txd->td_word1 = htole32(dmamap->dm_nsegs);
4302f5860a2Smartin 		for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
4312f5860a2Smartin 			txd->td_frags[seg].fr_addr =
4322f5860a2Smartin 			    htole32(dmamap->dm_segs[seg].ds_addr);
4332f5860a2Smartin 			txd->td_frags[seg].fr_len =
4342f5860a2Smartin 			    htole32(dmamap->dm_segs[seg].ds_len);
4352f5860a2Smartin 		}
4362f5860a2Smartin 
4372f5860a2Smartin 		/* Sync the descriptor and the DMA map. */
4382f5860a2Smartin 		SF_CDTXDSYNC(sc, producer, BUS_DMASYNC_PREWRITE);
4392f5860a2Smartin 		bus_dmamap_sync(sc->sc_dmat, dmamap, 0, dmamap->dm_mapsize,
4402f5860a2Smartin 		    BUS_DMASYNC_PREWRITE);
4412f5860a2Smartin 
4422f5860a2Smartin 		/*
4432f5860a2Smartin 		 * Store a pointer to the packet so we can free it later.
4442f5860a2Smartin 		 */
4452f5860a2Smartin 		ds->ds_mbuf = m0;
4462f5860a2Smartin 
4472f5860a2Smartin 		/* Advance the Tx pointer. */
4482f5860a2Smartin 		sc->sc_txpending++;
4492f5860a2Smartin 		last = producer;
4502f5860a2Smartin 		producer = SF_NEXTTX(producer);
4512f5860a2Smartin 
4522f5860a2Smartin #if NBPFILTER > 0
4532f5860a2Smartin 		/*
4542f5860a2Smartin 		 * Pass the packet to any BPF listeners.
4552f5860a2Smartin 		 */
4562f5860a2Smartin 		if (ifp->if_bpf)
4572f5860a2Smartin 			bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
4582f5860a2Smartin #endif
4592f5860a2Smartin 	}
4602f5860a2Smartin 
4612f5860a2Smartin 	if (sc->sc_txpending == (SF_NTXDESC - 1)) {
4622f5860a2Smartin 		/* No more slots left; notify upper layer. */
463de6cd8fbSdlg 		ifq_set_oactive(&ifp->if_snd);
4642f5860a2Smartin 	}
4652f5860a2Smartin 
4662f5860a2Smartin 	if (sc->sc_txpending != opending) {
4672f5860a2Smartin 		KASSERT(last != -1);
4682f5860a2Smartin 		/*
4692f5860a2Smartin 		 * We enqueued packets.  Cause a transmit interrupt to
4702f5860a2Smartin 		 * happen on the last packet we enqueued, and give the
4712f5860a2Smartin 		 * new descriptors to the chip by writing the new
4722f5860a2Smartin 		 * producer index.
4732f5860a2Smartin 		 */
4742f5860a2Smartin 		sc->sc_txdescs[last].td_word0 |= TD_W0_INTR;
4752f5860a2Smartin 		SF_CDTXDSYNC(sc, last, BUS_DMASYNC_PREWRITE);
4762f5860a2Smartin 
4772f5860a2Smartin 		sf_funcreg_write(sc, SF_TxDescQueueProducerIndex,
4782f5860a2Smartin 		    TDQPI_HiPrTxProducerIndex(SF_TXDINDEX_TO_CHIP(producer)));
4792f5860a2Smartin 
4802f5860a2Smartin 		/* Set a watchdog timer in case the chip flakes out. */
4812f5860a2Smartin 		ifp->if_timer = 5;
4822f5860a2Smartin 	}
4832f5860a2Smartin }
4842f5860a2Smartin 
4852f5860a2Smartin /*
4862f5860a2Smartin  * sf_watchdog:		[ifnet interface function]
4872f5860a2Smartin  *
4882f5860a2Smartin  *	Watchdog timer handler.
4892f5860a2Smartin  */
4902f5860a2Smartin void
sf_watchdog(struct ifnet * ifp)4912f5860a2Smartin sf_watchdog(struct ifnet *ifp)
4922f5860a2Smartin {
4932f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
4942f5860a2Smartin 
4952f5860a2Smartin 	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
4962f5860a2Smartin 	ifp->if_oerrors++;
4972f5860a2Smartin 
4982f5860a2Smartin 	(void) sf_init(ifp);
4992f5860a2Smartin 
5002f5860a2Smartin 	/* Try to get more packets going. */
5012f5860a2Smartin 	sf_start(ifp);
5022f5860a2Smartin }
5032f5860a2Smartin 
5042f5860a2Smartin /*
5052f5860a2Smartin  * sf_ioctl:		[ifnet interface function]
5062f5860a2Smartin  *
5072f5860a2Smartin  *	Handle control requests from the operator.
5082f5860a2Smartin  */
5092f5860a2Smartin int
sf_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)5102f5860a2Smartin sf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
5112f5860a2Smartin {
5122f5860a2Smartin 	struct sf_softc *sc = (struct sf_softc *)ifp->if_softc;
5132f5860a2Smartin 	struct ifreq *ifr = (struct ifreq *) data;
51462e5525bSmartin 	int s, error = 0;
5152f5860a2Smartin 
5162f5860a2Smartin 	s = splnet();
51762e5525bSmartin 
5182f5860a2Smartin 	switch (cmd) {
5192f5860a2Smartin 	case SIOCSIFADDR:
5202f5860a2Smartin 		ifp->if_flags |= IFF_UP;
52162e5525bSmartin 		if (!(ifp->if_flags & IFF_RUNNING))
52262e5525bSmartin 			sf_init(ifp);
52362e5525bSmartin 		break;
52462e5525bSmartin 
5252f5860a2Smartin 	case SIOCSIFFLAGS:
5262f5860a2Smartin 		if (ifp->if_flags & IFF_UP) {
52762e5525bSmartin 			if (ifp->if_flags & IFF_RUNNING &&
52862e5525bSmartin 			    ((ifp->if_flags ^ sc->sc_flags) &
52962e5525bSmartin 			     IFF_PROMISC)) {
5302f5860a2Smartin 				sf_set_filter(sc);
53162e5525bSmartin 			} else {
53262e5525bSmartin 				if (!(ifp->if_flags & IFF_RUNNING))
5332f5860a2Smartin 					sf_init(ifp);
53462e5525bSmartin 			}
5352f5860a2Smartin 		} else {
5362f5860a2Smartin 			if (ifp->if_flags & IFF_RUNNING)
5372f5860a2Smartin 				sf_stop(ifp, 1);
5382f5860a2Smartin 		}
53962e5525bSmartin 		sc->sc_flags = ifp->if_flags;
5402f5860a2Smartin 		break;
5412f5860a2Smartin 
5422f5860a2Smartin 	case SIOCGIFMEDIA:
5432f5860a2Smartin 	case SIOCSIFMEDIA:
5442f5860a2Smartin 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
5452f5860a2Smartin 		break;
5462f5860a2Smartin 
5472f5860a2Smartin 	default:
548775775feSbrad 		error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
5492f5860a2Smartin 	}
5502f5860a2Smartin 
55134f0f0fdSbrad 	if (error == ENETRESET) {
55234f0f0fdSbrad 		if (ifp->if_flags & IFF_RUNNING)
55334f0f0fdSbrad 			sf_set_filter(sc);
55434f0f0fdSbrad 		error = 0;
55534f0f0fdSbrad 	}
55634f0f0fdSbrad 
5572f5860a2Smartin 	/* Try to get more packets going. */
5582f5860a2Smartin 	sf_start(ifp);
5592f5860a2Smartin 
5602f5860a2Smartin 	splx(s);
5612f5860a2Smartin 	return (error);
5622f5860a2Smartin }
5632f5860a2Smartin 
5642f5860a2Smartin /*
5652f5860a2Smartin  * sf_intr:
5662f5860a2Smartin  *
5672f5860a2Smartin  *	Interrupt service routine.
5682f5860a2Smartin  */
5692f5860a2Smartin int
sf_intr(void * arg)5702f5860a2Smartin sf_intr(void *arg)
5712f5860a2Smartin {
5722f5860a2Smartin 	struct sf_softc *sc = arg;
5732f5860a2Smartin 	uint32_t isr;
5742f5860a2Smartin 	int handled = 0, wantinit = 0;
5752f5860a2Smartin 
5762f5860a2Smartin 	for (;;) {
5772f5860a2Smartin 		/* Reading clears all interrupts we're interested in. */
5782f5860a2Smartin 		isr = sf_funcreg_read(sc, SF_InterruptStatus);
5792f5860a2Smartin 		if ((isr & IS_PCIPadInt) == 0)
5802f5860a2Smartin 			break;
5812f5860a2Smartin 
5822f5860a2Smartin 		handled = 1;
5832f5860a2Smartin 
5842f5860a2Smartin 		/* Handle receive interrupts. */
5852f5860a2Smartin 		if (isr & IS_RxQ1DoneInt)
5862f5860a2Smartin 			sf_rxintr(sc);
5872f5860a2Smartin 
5882f5860a2Smartin 		/* Handle transmit completion interrupts. */
5892f5860a2Smartin 		if (isr & (IS_TxDmaDoneInt|IS_TxQueueDoneInt))
5902f5860a2Smartin 			sf_txintr(sc);
5912f5860a2Smartin 
5922f5860a2Smartin 		/* Handle abnormal interrupts. */
5932f5860a2Smartin 		if (isr & IS_AbnormalInterrupt) {
5942f5860a2Smartin 			/* Statistics. */
5952f5860a2Smartin 			if (isr & IS_StatisticWrapInt)
5962f5860a2Smartin 				sf_stats_update(sc);
5972f5860a2Smartin 
5982f5860a2Smartin 			/* DMA errors. */
5992f5860a2Smartin 			if (isr & IS_DmaErrInt) {
6002f5860a2Smartin 				wantinit = 1;
6012f5860a2Smartin 				printf("%s: WARNING: DMA error\n",
6022f5860a2Smartin 				    sc->sc_dev.dv_xname);
6032f5860a2Smartin 			}
6042f5860a2Smartin 
6052f5860a2Smartin 			/* Transmit FIFO underruns. */
6062f5860a2Smartin 			if (isr & IS_TxDataLowInt) {
6072f5860a2Smartin 				if (sc->sc_txthresh < 0xff)
6082f5860a2Smartin 					sc->sc_txthresh++;
6092f5860a2Smartin #ifdef DEBUG
6102f5860a2Smartin 				printf("%s: transmit FIFO underrun, new "
6112f5860a2Smartin 				    "threshold: %d bytes\n",
6122f5860a2Smartin 				    sc->sc_dev.dv_xname,
6132f5860a2Smartin 				    sc->sc_txthresh * 16);
6142f5860a2Smartin #endif
6152f5860a2Smartin 				sf_funcreg_write(sc, SF_TransmitFrameCSR,
6162f5860a2Smartin 				    sc->sc_TransmitFrameCSR |
6172f5860a2Smartin 				    TFCSR_TransmitThreshold(sc->sc_txthresh));
6182f5860a2Smartin 				sf_funcreg_write(sc, SF_TxDescQueueCtrl,
6192f5860a2Smartin 				    sc->sc_TxDescQueueCtrl |
6202f5860a2Smartin 				    TDQC_TxHighPriorityFifoThreshold(
6212f5860a2Smartin 							sc->sc_txthresh));
6222f5860a2Smartin 			}
6232f5860a2Smartin 		}
6242f5860a2Smartin 	}
6252f5860a2Smartin 
6262f5860a2Smartin 	if (handled) {
6272f5860a2Smartin 		/* Reset the interface, if necessary. */
6282f5860a2Smartin 		if (wantinit)
6292f5860a2Smartin 			sf_init(&sc->sc_arpcom.ac_if);
6302f5860a2Smartin 
6312f5860a2Smartin 		/* Try and get more packets going. */
6322f5860a2Smartin 		sf_start(&sc->sc_arpcom.ac_if);
6332f5860a2Smartin 	}
6342f5860a2Smartin 
6352f5860a2Smartin 	return (handled);
6362f5860a2Smartin }
6372f5860a2Smartin 
6382f5860a2Smartin /*
6392f5860a2Smartin  * sf_txintr:
6402f5860a2Smartin  *
6412f5860a2Smartin  *	Helper -- handle transmit completion interrupts.
6422f5860a2Smartin  */
6432f5860a2Smartin void
sf_txintr(struct sf_softc * sc)6442f5860a2Smartin sf_txintr(struct sf_softc *sc)
6452f5860a2Smartin {
6462f5860a2Smartin 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
6472f5860a2Smartin 	struct sf_descsoft *ds;
6482f5860a2Smartin 	uint32_t cqci, tcd;
6492f5860a2Smartin 	int consumer, producer, txidx;
6502f5860a2Smartin 
6512f5860a2Smartin  try_again:
6522f5860a2Smartin 	cqci = sf_funcreg_read(sc, SF_CompletionQueueConsumerIndex);
6532f5860a2Smartin 
6542f5860a2Smartin 	consumer = CQCI_TxCompletionConsumerIndex_get(cqci);
6552f5860a2Smartin 	producer = CQPI_TxCompletionProducerIndex_get(
6562f5860a2Smartin 	    sf_funcreg_read(sc, SF_CompletionQueueProducerIndex));
6572f5860a2Smartin 
6582f5860a2Smartin 	if (consumer == producer)
6592f5860a2Smartin 		return;
6602f5860a2Smartin 
661de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
6622f5860a2Smartin 
6632f5860a2Smartin 	while (consumer != producer) {
6642f5860a2Smartin 		SF_CDTXCSYNC(sc, consumer, BUS_DMASYNC_POSTREAD);
6652f5860a2Smartin 		tcd = letoh32(sc->sc_txcomp[consumer].tcd_word0);
6662f5860a2Smartin 
6672f5860a2Smartin 		txidx = SF_TCD_INDEX_TO_HOST(TCD_INDEX(tcd));
6682f5860a2Smartin #ifdef DIAGNOSTIC
6692f5860a2Smartin 		if ((tcd & TCD_PR) == 0)
6702f5860a2Smartin 			printf("%s: Tx queue mismatch, index %d\n",
6712f5860a2Smartin 			    sc->sc_dev.dv_xname, txidx);
6722f5860a2Smartin #endif
6732f5860a2Smartin 		/*
6742f5860a2Smartin 		 * NOTE: stats are updated later.  We're just
6752f5860a2Smartin 		 * releasing packets that have been DMA'd to
6762f5860a2Smartin 		 * the chip.
6772f5860a2Smartin 		 */
6782f5860a2Smartin 		ds = &sc->sc_txsoft[txidx];
6792f5860a2Smartin 		SF_CDTXDSYNC(sc, txidx, BUS_DMASYNC_POSTWRITE);
6802f5860a2Smartin 		bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap,
6812f5860a2Smartin 		    0, ds->ds_dmamap->dm_mapsize,
6822f5860a2Smartin 		    BUS_DMASYNC_POSTWRITE);
6832f5860a2Smartin 		m_freem(ds->ds_mbuf);
6842f5860a2Smartin 		ds->ds_mbuf = NULL;
6852f5860a2Smartin 
6862f5860a2Smartin 		consumer = SF_NEXTTCD(consumer);
6872f5860a2Smartin 		sc->sc_txpending--;
6882f5860a2Smartin 	}
6892f5860a2Smartin 
6902f5860a2Smartin 	/* XXXJRT -- should be KDASSERT() */
6912f5860a2Smartin 	KASSERT(sc->sc_txpending >= 0);
6922f5860a2Smartin 
6932f5860a2Smartin 	/* If all packets are done, cancel the watchdog timer. */
6942f5860a2Smartin 	if (sc->sc_txpending == 0)
6952f5860a2Smartin 		ifp->if_timer = 0;
6962f5860a2Smartin 
6972f5860a2Smartin 	/* Update the consumer index. */
6982f5860a2Smartin 	sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
6992f5860a2Smartin 	    (cqci & ~CQCI_TxCompletionConsumerIndex(0x7ff)) |
7002f5860a2Smartin 	     CQCI_TxCompletionConsumerIndex(consumer));
7012f5860a2Smartin 
7022f5860a2Smartin 	/* Double check for new completions. */
7032f5860a2Smartin 	goto try_again;
7042f5860a2Smartin }
7052f5860a2Smartin 
7062f5860a2Smartin /*
7072f5860a2Smartin  * sf_rxintr:
7082f5860a2Smartin  *
7092f5860a2Smartin  *	Helper -- handle receive interrupts.
7102f5860a2Smartin  */
7112f5860a2Smartin void
sf_rxintr(struct sf_softc * sc)7122f5860a2Smartin sf_rxintr(struct sf_softc *sc)
7132f5860a2Smartin {
7142f5860a2Smartin 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
7152f5860a2Smartin 	struct sf_descsoft *ds;
7162f5860a2Smartin 	struct sf_rcd_full *rcd;
717cdea9bebSmpi 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
7182f5860a2Smartin 	struct mbuf *m;
7192f5860a2Smartin 	uint32_t cqci, word0;
7202f5860a2Smartin 	int consumer, producer, bufproducer, rxidx, len;
7212f5860a2Smartin 
7222f5860a2Smartin 	cqci = sf_funcreg_read(sc, SF_CompletionQueueConsumerIndex);
7232f5860a2Smartin 
7242f5860a2Smartin 	consumer = CQCI_RxCompletionQ1ConsumerIndex_get(cqci);
7252f5860a2Smartin 	producer = CQPI_RxCompletionQ1ProducerIndex_get(
7262f5860a2Smartin 	    sf_funcreg_read(sc, SF_CompletionQueueProducerIndex));
7272f5860a2Smartin 	bufproducer = RXQ1P_RxDescQ1Producer_get(
7282f5860a2Smartin 	    sf_funcreg_read(sc, SF_RxDescQueue1Ptrs));
7292f5860a2Smartin 
7302f5860a2Smartin 	if (consumer == producer)
7312f5860a2Smartin 		return;
7322f5860a2Smartin 
7332f5860a2Smartin 	while (consumer != producer) {
7342f5860a2Smartin 		rcd = &sc->sc_rxcomp[consumer];
7352f5860a2Smartin 		SF_CDRXCSYNC(sc, consumer,
7362f5860a2Smartin 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
7372f5860a2Smartin 		SF_CDRXCSYNC(sc, consumer,
7382f5860a2Smartin 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
7392f5860a2Smartin 
7402f5860a2Smartin 		word0 = letoh32(rcd->rcd_word0);
7412f5860a2Smartin 		rxidx = RCD_W0_EndIndex(word0);
7422f5860a2Smartin 
7432f5860a2Smartin 		ds = &sc->sc_rxsoft[rxidx];
7442f5860a2Smartin 
7452f5860a2Smartin 		consumer = SF_NEXTRCD(consumer);
7462f5860a2Smartin 		bufproducer = SF_NEXTRX(bufproducer);
7472f5860a2Smartin 
7482f5860a2Smartin 		if ((word0 & RCD_W0_OK) == 0) {
7492f5860a2Smartin 			SF_INIT_RXDESC(sc, rxidx);
7502f5860a2Smartin 			continue;
7512f5860a2Smartin 		}
7522f5860a2Smartin 
7532f5860a2Smartin 		bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
7542f5860a2Smartin 		    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
7552f5860a2Smartin 
7562f5860a2Smartin 		/*
7572f5860a2Smartin 		 * No errors; receive the packet.  Note that we have
7582f5860a2Smartin 		 * configured the Starfire to NOT transfer the CRC
7592f5860a2Smartin 		 * with the packet.
7602f5860a2Smartin 		 */
7612f5860a2Smartin 		len = RCD_W0_Length(word0);
7622f5860a2Smartin 
763a4adbbcbSmartin #ifndef __STRICT_ALIGNMENT
7642f5860a2Smartin 		/*
7652f5860a2Smartin 		 * Allocate a new mbuf cluster.  If that fails, we are
7662f5860a2Smartin 		 * out of memory, and must drop the packet and recycle
7672f5860a2Smartin 		 * the buffer that's already attached to this descriptor.
7682f5860a2Smartin 		 */
7692f5860a2Smartin 		m = ds->ds_mbuf;
7702f5860a2Smartin 		if (sf_add_rxbuf(sc, rxidx) != 0) {
7712f5860a2Smartin 			ifp->if_ierrors++;
7722f5860a2Smartin 			SF_INIT_RXDESC(sc, rxidx);
7732f5860a2Smartin 			bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
7742f5860a2Smartin 			    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
7752f5860a2Smartin 			continue;
7762f5860a2Smartin 		}
7772f5860a2Smartin #else
7782f5860a2Smartin 		/*
7792f5860a2Smartin 		 * The Starfire's receive buffer must be 4-byte aligned.
7802f5860a2Smartin 		 * But this means that the data after the Ethernet header
7812f5860a2Smartin 		 * is misaligned.  We must allocate a new buffer and
7822f5860a2Smartin 		 * copy the data, shifted forward 2 bytes.
7832f5860a2Smartin 		 */
7842f5860a2Smartin 		MGETHDR(m, M_DONTWAIT, MT_DATA);
7852f5860a2Smartin 		if (m == NULL) {
7862f5860a2Smartin  dropit:
7872f5860a2Smartin 			ifp->if_ierrors++;
7882f5860a2Smartin 			SF_INIT_RXDESC(sc, rxidx);
7892f5860a2Smartin 			bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
7902f5860a2Smartin 			    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
7912f5860a2Smartin 			continue;
7922f5860a2Smartin 		}
7932f5860a2Smartin 		if (len > (MHLEN - 2)) {
7942f5860a2Smartin 			MCLGET(m, M_DONTWAIT);
7952f5860a2Smartin 			if ((m->m_flags & M_EXT) == 0) {
7962f5860a2Smartin 				m_freem(m);
7972f5860a2Smartin 				goto dropit;
7982f5860a2Smartin 			}
7992f5860a2Smartin 		}
8002f5860a2Smartin 		m->m_data += 2;
8012f5860a2Smartin 
8022f5860a2Smartin 		/*
8032f5860a2Smartin 		 * Note that we use cluster for incoming frames, so the
8042f5860a2Smartin 		 * buffer is virtually contiguous.
8052f5860a2Smartin 		 */
8062f5860a2Smartin 		memcpy(mtod(m, caddr_t), mtod(ds->ds_mbuf, caddr_t), len);
8072f5860a2Smartin 
8082f5860a2Smartin 		/* Allow the receive descriptor to continue using its mbuf. */
8092f5860a2Smartin 		SF_INIT_RXDESC(sc, rxidx);
8102f5860a2Smartin 		bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
8112f5860a2Smartin 		    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
812a4adbbcbSmartin #endif /* __STRICT_ALIGNMENT */
8132f5860a2Smartin 
8142f5860a2Smartin 		m->m_pkthdr.len = m->m_len = len;
8152f5860a2Smartin 
816cdea9bebSmpi 		ml_enqueue(&ml, m);
8172f5860a2Smartin 	}
8182f5860a2Smartin 
819cdea9bebSmpi 	if_input(ifp, &ml);
820cdea9bebSmpi 
8212f5860a2Smartin 	/* Update the chip's pointers. */
8222f5860a2Smartin 	sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
8232f5860a2Smartin 	    (cqci & ~CQCI_RxCompletionQ1ConsumerIndex(0x7ff)) |
8242f5860a2Smartin 	     CQCI_RxCompletionQ1ConsumerIndex(consumer));
8252f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue1Ptrs,
8262f5860a2Smartin 	    RXQ1P_RxDescQ1Producer(bufproducer));
8272f5860a2Smartin }
8282f5860a2Smartin 
8292f5860a2Smartin /*
8302f5860a2Smartin  * sf_tick:
8312f5860a2Smartin  *
8322f5860a2Smartin  *	One second timer, used to tick the MII and update stats.
8332f5860a2Smartin  */
8342f5860a2Smartin void
sf_tick(void * arg)8352f5860a2Smartin sf_tick(void *arg)
8362f5860a2Smartin {
8372f5860a2Smartin 	struct sf_softc *sc = arg;
8382f5860a2Smartin 	int s;
8392f5860a2Smartin 
8402f5860a2Smartin 	s = splnet();
8412f5860a2Smartin 	mii_tick(&sc->sc_mii);
8422f5860a2Smartin 	sf_stats_update(sc);
8432f5860a2Smartin 	splx(s);
8442f5860a2Smartin 
845e15e1c8cSblambert 	timeout_add_sec(&sc->sc_mii_timeout, 1);
8462f5860a2Smartin }
8472f5860a2Smartin 
8482f5860a2Smartin /*
8492f5860a2Smartin  * sf_stats_update:
8502f5860a2Smartin  *
8514b1a56afSjsg  *	Read the statistics counters.
8522f5860a2Smartin  */
8532f5860a2Smartin void
sf_stats_update(struct sf_softc * sc)8542f5860a2Smartin sf_stats_update(struct sf_softc *sc)
8552f5860a2Smartin {
8562f5860a2Smartin 	struct sf_stats stats;
8572f5860a2Smartin 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
8582f5860a2Smartin 	uint32_t *p;
8592f5860a2Smartin 	u_int i;
8602f5860a2Smartin 
8612f5860a2Smartin 	p = &stats.TransmitOKFrames;
8622f5860a2Smartin 	for (i = 0; i < (sizeof(stats) / sizeof(uint32_t)); i++) {
8632f5860a2Smartin 		*p++ = sf_genreg_read(sc,
8642f5860a2Smartin 		    SF_STATS_BASE + (i * sizeof(uint32_t)));
8652f5860a2Smartin 		sf_genreg_write(sc, SF_STATS_BASE + (i * sizeof(uint32_t)), 0);
8662f5860a2Smartin 	}
8672f5860a2Smartin 
8682f5860a2Smartin 	ifp->if_collisions += stats.SingleCollisionFrames +
8692f5860a2Smartin 	    stats.MultipleCollisionFrames;
8702f5860a2Smartin 
8712f5860a2Smartin 	ifp->if_oerrors += stats.TransmitAbortDueToExcessiveCollisions +
8722f5860a2Smartin 	    stats.TransmitAbortDueToExcessingDeferral +
8732f5860a2Smartin 	    stats.FramesLostDueToInternalTransmitErrors;
8742f5860a2Smartin 
8752f5860a2Smartin 	ifp->if_ierrors += stats.ReceiveCRCErrors + stats.AlignmentErrors +
8762f5860a2Smartin 	    stats.ReceiveFramesTooLong + stats.ReceiveFramesTooShort +
8772f5860a2Smartin 	    stats.ReceiveFramesJabbersError +
8782f5860a2Smartin 	    stats.FramesLostDueToInternalReceiveErrors;
8792f5860a2Smartin }
8802f5860a2Smartin 
8812f5860a2Smartin /*
8822f5860a2Smartin  * sf_reset:
8832f5860a2Smartin  *
8842f5860a2Smartin  *	Perform a soft reset on the Starfire.
8852f5860a2Smartin  */
8862f5860a2Smartin void
sf_reset(struct sf_softc * sc)8872f5860a2Smartin sf_reset(struct sf_softc *sc)
8882f5860a2Smartin {
8892f5860a2Smartin 	int i;
8902f5860a2Smartin 
8912f5860a2Smartin 	sf_funcreg_write(sc, SF_GeneralEthernetCtrl, 0);
8922f5860a2Smartin 
8932f5860a2Smartin 	sf_macreset(sc);
8942f5860a2Smartin 
8952f5860a2Smartin 	sf_funcreg_write(sc, SF_PciDeviceConfig, PDC_SoftReset);
8962f5860a2Smartin 	for (i = 0; i < 1000; i++) {
8972f5860a2Smartin 		delay(10);
8982f5860a2Smartin 		if ((sf_funcreg_read(sc, SF_PciDeviceConfig) &
8992f5860a2Smartin 		     PDC_SoftReset) == 0)
9002f5860a2Smartin 			break;
9012f5860a2Smartin 	}
9022f5860a2Smartin 
9032f5860a2Smartin 	if (i == 1000) {
9042f5860a2Smartin 		printf("%s: reset failed to complete\n", sc->sc_dev.dv_xname);
9052f5860a2Smartin 		sf_funcreg_write(sc, SF_PciDeviceConfig, 0);
9062f5860a2Smartin 	}
9072f5860a2Smartin 
9082f5860a2Smartin 	delay(1000);
9092f5860a2Smartin }
9102f5860a2Smartin 
9112f5860a2Smartin /*
9122f5860a2Smartin  * sf_macreset:
9132f5860a2Smartin  *
9142f5860a2Smartin  *	Reset the MAC portion of the Starfire.
9152f5860a2Smartin  */
9162f5860a2Smartin void
sf_macreset(struct sf_softc * sc)9172f5860a2Smartin sf_macreset(struct sf_softc *sc)
9182f5860a2Smartin {
9192f5860a2Smartin 
9202f5860a2Smartin 	sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1 | MC1_SoftRst);
9212f5860a2Smartin 	delay(1000);
9222f5860a2Smartin 	sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1);
9232f5860a2Smartin }
9242f5860a2Smartin 
9252f5860a2Smartin /*
9262f5860a2Smartin  * sf_init:		[ifnet interface function]
9272f5860a2Smartin  *
9282f5860a2Smartin  *	Initialize the interface.  Must be called at splnet().
9292f5860a2Smartin  */
9302f5860a2Smartin int
sf_init(struct ifnet * ifp)9312f5860a2Smartin sf_init(struct ifnet *ifp)
9322f5860a2Smartin {
9332f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
9342f5860a2Smartin 	struct sf_descsoft *ds;
9352f5860a2Smartin 	int error = 0;
9362f5860a2Smartin 	u_int i;
9372f5860a2Smartin 
9382f5860a2Smartin 	/*
9392f5860a2Smartin 	 * Cancel any pending I/O.
9402f5860a2Smartin 	 */
9412f5860a2Smartin 	sf_stop(ifp, 0);
9422f5860a2Smartin 
9432f5860a2Smartin 	/*
9442f5860a2Smartin 	 * Reset the Starfire to a known state.
9452f5860a2Smartin 	 */
9462f5860a2Smartin 	sf_reset(sc);
9472f5860a2Smartin 
9482f5860a2Smartin 	/* Clear the stat counters. */
9492f5860a2Smartin 	for (i = 0; i < sizeof(struct sf_stats); i += sizeof(uint32_t))
9502f5860a2Smartin 		sf_genreg_write(sc, SF_STATS_BASE + i, 0);
9512f5860a2Smartin 
9522f5860a2Smartin 	/*
9532f5860a2Smartin 	 * Initialize the transmit descriptor ring.
9542f5860a2Smartin 	 */
9552f5860a2Smartin 	memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
9562f5860a2Smartin 	sf_funcreg_write(sc, SF_TxDescQueueHighAddr, 0);
9572f5860a2Smartin 	sf_funcreg_write(sc, SF_HiPrTxDescQueueBaseAddr, SF_CDTXDADDR(sc, 0));
9582f5860a2Smartin 	sf_funcreg_write(sc, SF_LoPrTxDescQueueBaseAddr, 0);
9592f5860a2Smartin 
9602f5860a2Smartin 	/*
9612f5860a2Smartin 	 * Initialize the transmit completion ring.
9622f5860a2Smartin 	 */
9632f5860a2Smartin 	for (i = 0; i < SF_NTCD; i++) {
9642f5860a2Smartin 		sc->sc_txcomp[i].tcd_word0 = TCD_DMA_ID;
9652f5860a2Smartin 		SF_CDTXCSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
9662f5860a2Smartin 	}
9672f5860a2Smartin 	sf_funcreg_write(sc, SF_CompletionQueueHighAddr, 0);
9682f5860a2Smartin 	sf_funcreg_write(sc, SF_TxCompletionQueueCtrl, SF_CDTXCADDR(sc, 0));
9692f5860a2Smartin 
9702f5860a2Smartin 	/*
9712f5860a2Smartin 	 * Initialize the receive descriptor ring.
9722f5860a2Smartin 	 */
9732f5860a2Smartin 	for (i = 0; i < SF_NRXDESC; i++) {
9742f5860a2Smartin 		ds = &sc->sc_rxsoft[i];
9752f5860a2Smartin 		if (ds->ds_mbuf == NULL) {
9762f5860a2Smartin 			if ((error = sf_add_rxbuf(sc, i)) != 0) {
9772f5860a2Smartin 				printf("%s: unable to allocate or map rx "
9782f5860a2Smartin 				    "buffer %d, error = %d\n",
9792f5860a2Smartin 				    sc->sc_dev.dv_xname, i, error);
9802f5860a2Smartin 				/*
9812f5860a2Smartin 				 * XXX Should attempt to run with fewer receive
9822f5860a2Smartin 				 * XXX buffers instead of just failing.
9832f5860a2Smartin 				 */
9842f5860a2Smartin 				sf_rxdrain(sc);
9852f5860a2Smartin 				goto out;
9862f5860a2Smartin 			}
9872f5860a2Smartin 		} else
9882f5860a2Smartin 			SF_INIT_RXDESC(sc, i);
9892f5860a2Smartin 	}
9902f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueueHighAddress, 0);
9912f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue1LowAddress, SF_CDRXDADDR(sc, 0));
9922f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue2LowAddress, 0);
9932f5860a2Smartin 
9942f5860a2Smartin 	/*
9952f5860a2Smartin 	 * Initialize the receive completion ring.
9962f5860a2Smartin 	 */
9972f5860a2Smartin 	for (i = 0; i < SF_NRCD; i++) {
9982f5860a2Smartin 		sc->sc_rxcomp[i].rcd_word0 = RCD_W0_ID;
9992f5860a2Smartin 		sc->sc_rxcomp[i].rcd_word1 = 0;
10002f5860a2Smartin 		sc->sc_rxcomp[i].rcd_word2 = 0;
10012f5860a2Smartin 		sc->sc_rxcomp[i].rcd_timestamp = 0;
10022f5860a2Smartin 		SF_CDRXCSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
10032f5860a2Smartin 	}
10042f5860a2Smartin 	sf_funcreg_write(sc, SF_RxCompletionQueue1Ctrl, SF_CDRXCADDR(sc, 0) |
10052f5860a2Smartin 	    RCQ1C_RxCompletionQ1Type(3));
10062f5860a2Smartin 	sf_funcreg_write(sc, SF_RxCompletionQueue2Ctrl, 0);
10072f5860a2Smartin 
10082f5860a2Smartin 	/*
10092f5860a2Smartin 	 * Initialize the Tx CSR.
10102f5860a2Smartin 	 */
10112f5860a2Smartin 	sc->sc_TransmitFrameCSR = 0;
10122f5860a2Smartin 	sf_funcreg_write(sc, SF_TransmitFrameCSR,
10132f5860a2Smartin 	    sc->sc_TransmitFrameCSR |
10142f5860a2Smartin 	    TFCSR_TransmitThreshold(sc->sc_txthresh));
10152f5860a2Smartin 
10162f5860a2Smartin 	/*
10172f5860a2Smartin 	 * Initialize the Tx descriptor control register.
10182f5860a2Smartin 	 */
10192f5860a2Smartin 	sc->sc_TxDescQueueCtrl = TDQC_SkipLength(0) |
10202f5860a2Smartin 	    TDQC_TxDmaBurstSize(4) |	/* default */
10212f5860a2Smartin 	    TDQC_MinFrameSpacing(3) |	/* 128 bytes */
10222f5860a2Smartin 	    TDQC_TxDescType(0);
10232f5860a2Smartin 	sf_funcreg_write(sc, SF_TxDescQueueCtrl,
10242f5860a2Smartin 	    sc->sc_TxDescQueueCtrl |
10252f5860a2Smartin 	    TDQC_TxHighPriorityFifoThreshold(sc->sc_txthresh));
10262f5860a2Smartin 
10272f5860a2Smartin 	/*
10282f5860a2Smartin 	 * Initialize the Rx descriptor control registers.
10292f5860a2Smartin 	 */
10302f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue1Ctrl,
10312f5860a2Smartin 	    RDQ1C_RxQ1BufferLength(MCLBYTES) |
10322f5860a2Smartin 	    RDQ1C_RxDescSpacing(0));
10332f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue2Ctrl, 0);
10342f5860a2Smartin 
10352f5860a2Smartin 	/*
10362f5860a2Smartin 	 * Initialize the Tx descriptor producer indices.
10372f5860a2Smartin 	 */
10382f5860a2Smartin 	sf_funcreg_write(sc, SF_TxDescQueueProducerIndex,
10392f5860a2Smartin 	    TDQPI_HiPrTxProducerIndex(0) |
10402f5860a2Smartin 	    TDQPI_LoPrTxProducerIndex(0));
10412f5860a2Smartin 
10422f5860a2Smartin 	/*
10432f5860a2Smartin 	 * Initialize the Rx descriptor producer indices.
10442f5860a2Smartin 	 */
10452f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue1Ptrs,
10462f5860a2Smartin 	    RXQ1P_RxDescQ1Producer(SF_NRXDESC - 1));
10472f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDescQueue2Ptrs,
10482f5860a2Smartin 	    RXQ2P_RxDescQ2Producer(0));
10492f5860a2Smartin 
10502f5860a2Smartin 	/*
10512f5860a2Smartin 	 * Initialize the Tx and Rx completion queue consumer indices.
10522f5860a2Smartin 	 */
10532f5860a2Smartin 	sf_funcreg_write(sc, SF_CompletionQueueConsumerIndex,
10542f5860a2Smartin 	    CQCI_TxCompletionConsumerIndex(0) |
10552f5860a2Smartin 	    CQCI_RxCompletionQ1ConsumerIndex(0));
10562f5860a2Smartin 	sf_funcreg_write(sc, SF_RxHiPrCompletionPtrs, 0);
10572f5860a2Smartin 
10582f5860a2Smartin 	/*
10592f5860a2Smartin 	 * Initialize the Rx DMA control register.
10602f5860a2Smartin 	 */
10612f5860a2Smartin 	sf_funcreg_write(sc, SF_RxDmaCtrl,
10622f5860a2Smartin 	    RDC_RxHighPriorityThreshold(6) |	/* default */
10632f5860a2Smartin 	    RDC_RxBurstSize(4));		/* default */
10642f5860a2Smartin 
10652f5860a2Smartin 	/*
10662f5860a2Smartin 	 * Set the receive filter.
10672f5860a2Smartin 	 */
10682f5860a2Smartin 	sc->sc_RxAddressFilteringCtl = 0;
10692f5860a2Smartin 	sf_set_filter(sc);
10702f5860a2Smartin 
10712f5860a2Smartin 	/*
10722f5860a2Smartin 	 * Set MacConfig1.  When we set the media, MacConfig1 will
10732f5860a2Smartin 	 * actually be written and the MAC part reset.
10742f5860a2Smartin 	 */
10752f5860a2Smartin 	sc->sc_MacConfig1 = MC1_PadEn;
10762f5860a2Smartin 
10772f5860a2Smartin 	/*
10782f5860a2Smartin 	 * Set the media.
10792f5860a2Smartin 	 */
10802f5860a2Smartin 	mii_mediachg(&sc->sc_mii);
10812f5860a2Smartin 
10822f5860a2Smartin 	/*
10832f5860a2Smartin 	 * Initialize the interrupt register.
10842f5860a2Smartin 	 */
10852f5860a2Smartin 	sc->sc_InterruptEn = IS_PCIPadInt | IS_RxQ1DoneInt |
10862f5860a2Smartin 	    IS_TxQueueDoneInt | IS_TxDmaDoneInt | IS_DmaErrInt |
10872f5860a2Smartin 	    IS_StatisticWrapInt;
10882f5860a2Smartin 	sf_funcreg_write(sc, SF_InterruptEn, sc->sc_InterruptEn);
10892f5860a2Smartin 
10902f5860a2Smartin 	sf_funcreg_write(sc, SF_PciDeviceConfig, PDC_IntEnable |
10912f5860a2Smartin 	    PDC_PCIMstDmaEn | (1 << PDC_FifoThreshold_SHIFT));
10922f5860a2Smartin 
10932f5860a2Smartin 	/*
10942f5860a2Smartin 	 * Start the transmit and receive processes.
10952f5860a2Smartin 	 */
10962f5860a2Smartin 	sf_funcreg_write(sc, SF_GeneralEthernetCtrl,
10972f5860a2Smartin 	    GEC_TxDmaEn|GEC_RxDmaEn|GEC_TransmitEn|GEC_ReceiveEn);
10982f5860a2Smartin 
10992f5860a2Smartin 	/* Start the on second clock. */
1100e15e1c8cSblambert 	timeout_add_sec(&sc->sc_mii_timeout, 1);
11012f5860a2Smartin 
11022f5860a2Smartin 	/*
11032f5860a2Smartin 	 * Note that the interface is now running.
11042f5860a2Smartin 	 */
11052f5860a2Smartin 	ifp->if_flags |= IFF_RUNNING;
1106de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
11072f5860a2Smartin 
11082f5860a2Smartin  out:
11092f5860a2Smartin 	if (error) {
1110de6cd8fbSdlg 		ifp->if_flags &= ~IFF_RUNNING;
1111de6cd8fbSdlg 		ifq_clr_oactive(&ifp->if_snd);
11122f5860a2Smartin 		ifp->if_timer = 0;
11132f5860a2Smartin 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
11142f5860a2Smartin 	}
11152f5860a2Smartin 	return (error);
11162f5860a2Smartin }
11172f5860a2Smartin 
11182f5860a2Smartin /*
11192f5860a2Smartin  * sf_rxdrain:
11202f5860a2Smartin  *
11212f5860a2Smartin  *	Drain the receive queue.
11222f5860a2Smartin  */
11232f5860a2Smartin void
sf_rxdrain(struct sf_softc * sc)11242f5860a2Smartin sf_rxdrain(struct sf_softc *sc)
11252f5860a2Smartin {
11262f5860a2Smartin 	struct sf_descsoft *ds;
11272f5860a2Smartin 	int i;
11282f5860a2Smartin 
11292f5860a2Smartin 	for (i = 0; i < SF_NRXDESC; i++) {
11302f5860a2Smartin 		ds = &sc->sc_rxsoft[i];
11312f5860a2Smartin 		if (ds->ds_mbuf != NULL) {
11322f5860a2Smartin 			bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
11332f5860a2Smartin 			m_freem(ds->ds_mbuf);
11342f5860a2Smartin 			ds->ds_mbuf = NULL;
11352f5860a2Smartin 		}
11362f5860a2Smartin 	}
11372f5860a2Smartin }
11382f5860a2Smartin 
11392f5860a2Smartin /*
11402f5860a2Smartin  * sf_stop:		[ifnet interface function]
11412f5860a2Smartin  *
11422f5860a2Smartin  *	Stop transmission on the interface.
11432f5860a2Smartin  */
11442f5860a2Smartin void
sf_stop(struct ifnet * ifp,int disable)11452f5860a2Smartin sf_stop(struct ifnet *ifp, int disable)
11462f5860a2Smartin {
11472f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
11482f5860a2Smartin 	struct sf_descsoft *ds;
11492f5860a2Smartin 	int i;
11502f5860a2Smartin 
11512f5860a2Smartin 	/* Stop the one second clock. */
11522f5860a2Smartin 	timeout_del(&sc->sc_mii_timeout);
11532f5860a2Smartin 
11542f5860a2Smartin 	/* Down the MII. */
11552f5860a2Smartin 	mii_down(&sc->sc_mii);
11562f5860a2Smartin 
11572f5860a2Smartin 	/* Disable interrupts. */
11582f5860a2Smartin 	sf_funcreg_write(sc, SF_InterruptEn, 0);
11592f5860a2Smartin 
11602f5860a2Smartin 	/* Stop the transmit and receive processes. */
11612f5860a2Smartin 	sf_funcreg_write(sc, SF_GeneralEthernetCtrl, 0);
11622f5860a2Smartin 
11632f5860a2Smartin 	/*
11642f5860a2Smartin 	 * Release any queued transmit buffers.
11652f5860a2Smartin 	 */
11662f5860a2Smartin 	for (i = 0; i < SF_NTXDESC; i++) {
11672f5860a2Smartin 		ds = &sc->sc_txsoft[i];
11682f5860a2Smartin 		if (ds->ds_mbuf != NULL) {
11692f5860a2Smartin 			bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
11702f5860a2Smartin 			m_freem(ds->ds_mbuf);
11712f5860a2Smartin 			ds->ds_mbuf = NULL;
11722f5860a2Smartin 		}
11732f5860a2Smartin 	}
11742c828e54Sbrad 	sc->sc_txpending = 0;
11752f5860a2Smartin 
11762f5860a2Smartin 	if (disable)
11772f5860a2Smartin 		sf_rxdrain(sc);
11782f5860a2Smartin 
11792f5860a2Smartin 	/*
11802f5860a2Smartin 	 * Mark the interface down and cancel the watchdog timer.
11812f5860a2Smartin 	 */
1182de6cd8fbSdlg 	ifp->if_flags &= ~IFF_RUNNING;
1183de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
11842f5860a2Smartin 	ifp->if_timer = 0;
11852f5860a2Smartin }
11862f5860a2Smartin 
11872f5860a2Smartin /*
11882f5860a2Smartin  * sf_read_eeprom:
11892f5860a2Smartin  *
11902f5860a2Smartin  *	Read from the Starfire EEPROM.
11912f5860a2Smartin  */
11922f5860a2Smartin uint8_t
sf_read_eeprom(struct sf_softc * sc,int offset)11932f5860a2Smartin sf_read_eeprom(struct sf_softc *sc, int offset)
11942f5860a2Smartin {
11952f5860a2Smartin 	uint32_t reg;
11962f5860a2Smartin 
11972f5860a2Smartin 	reg = sf_genreg_read(sc, SF_EEPROM_BASE + (offset & ~3));
11982f5860a2Smartin 
11992f5860a2Smartin 	return ((reg >> (8 * (offset & 3))) & 0xff);
12002f5860a2Smartin }
12012f5860a2Smartin 
12022f5860a2Smartin /*
12032f5860a2Smartin  * sf_add_rxbuf:
12042f5860a2Smartin  *
12052f5860a2Smartin  *	Add a receive buffer to the indicated descriptor.
12062f5860a2Smartin  */
12072f5860a2Smartin int
sf_add_rxbuf(struct sf_softc * sc,int idx)12082f5860a2Smartin sf_add_rxbuf(struct sf_softc *sc, int idx)
12092f5860a2Smartin {
12102f5860a2Smartin 	struct sf_descsoft *ds = &sc->sc_rxsoft[idx];
12112f5860a2Smartin 	struct mbuf *m;
12122f5860a2Smartin 	int error;
12132f5860a2Smartin 
12142f5860a2Smartin 	MGETHDR(m, M_DONTWAIT, MT_DATA);
12152f5860a2Smartin 	if (m == NULL)
12162f5860a2Smartin 		return (ENOBUFS);
12172f5860a2Smartin 
12182f5860a2Smartin 	MCLGET(m, M_DONTWAIT);
12192f5860a2Smartin 	if ((m->m_flags & M_EXT) == 0) {
12202f5860a2Smartin 		m_freem(m);
12212f5860a2Smartin 		return (ENOBUFS);
12222f5860a2Smartin 	}
12232f5860a2Smartin 
12242f5860a2Smartin 	if (ds->ds_mbuf != NULL)
12252f5860a2Smartin 		bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
12262f5860a2Smartin 
12272f5860a2Smartin 	ds->ds_mbuf = m;
12282f5860a2Smartin 
12292f5860a2Smartin 	error = bus_dmamap_load(sc->sc_dmat, ds->ds_dmamap,
12302f5860a2Smartin 	    m->m_ext.ext_buf, m->m_ext.ext_size, NULL,
12312f5860a2Smartin 	    BUS_DMA_READ|BUS_DMA_NOWAIT);
12322f5860a2Smartin 	if (error) {
12332f5860a2Smartin 		printf("%s: can't load rx DMA map %d, error = %d\n",
12342f5860a2Smartin 		    sc->sc_dev.dv_xname, idx, error);
12352f5860a2Smartin 		panic("sf_add_rxbuf"); /* XXX */
12362f5860a2Smartin 	}
12372f5860a2Smartin 
12382f5860a2Smartin 	bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
12392f5860a2Smartin 	    ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
12402f5860a2Smartin 
12412f5860a2Smartin 	SF_INIT_RXDESC(sc, idx);
12422f5860a2Smartin 
12432f5860a2Smartin 	return (0);
12442f5860a2Smartin }
12452f5860a2Smartin 
12462f5860a2Smartin void
sf_set_filter_perfect(struct sf_softc * sc,int slot,uint8_t * enaddr)12472f5860a2Smartin sf_set_filter_perfect(struct sf_softc *sc, int slot, uint8_t *enaddr)
12482f5860a2Smartin {
12492f5860a2Smartin 	uint32_t reg0, reg1, reg2;
12502f5860a2Smartin 
12512f5860a2Smartin 	reg0 = enaddr[5] | (enaddr[4] << 8);
12522f5860a2Smartin 	reg1 = enaddr[3] | (enaddr[2] << 8);
12532f5860a2Smartin 	reg2 = enaddr[1] | (enaddr[0] << 8);
12542f5860a2Smartin 
12552f5860a2Smartin 	sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 0, reg0);
12562f5860a2Smartin 	sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 4, reg1);
12572f5860a2Smartin 	sf_genreg_write(sc, SF_PERFECT_BASE + (slot * 0x10) + 8, reg2);
12582f5860a2Smartin }
12592f5860a2Smartin 
12602f5860a2Smartin void
sf_set_filter_hash(struct sf_softc * sc,uint8_t * enaddr)12612f5860a2Smartin sf_set_filter_hash(struct sf_softc *sc, uint8_t *enaddr)
12622f5860a2Smartin {
12632f5860a2Smartin 	uint32_t hash, slot, reg;
12642f5860a2Smartin 
12652f5860a2Smartin 	hash = ether_crc32_be(enaddr, ETHER_ADDR_LEN) >> 23;
12662f5860a2Smartin 	slot = hash >> 4;
12672f5860a2Smartin 
12682f5860a2Smartin 	reg = sf_genreg_read(sc, SF_HASH_BASE + (slot * 0x10));
12692f5860a2Smartin 	reg |= 1 << (hash & 0xf);
12702f5860a2Smartin 	sf_genreg_write(sc, SF_HASH_BASE + (slot * 0x10), reg);
12712f5860a2Smartin }
12722f5860a2Smartin 
12732f5860a2Smartin /*
12742f5860a2Smartin  * sf_set_filter:
12752f5860a2Smartin  *
12762f5860a2Smartin  *	Set the Starfire receive filter.
12772f5860a2Smartin  */
12782f5860a2Smartin void
sf_set_filter(struct sf_softc * sc)12792f5860a2Smartin sf_set_filter(struct sf_softc *sc)
12802f5860a2Smartin {
12812f5860a2Smartin 	struct arpcom *ac = &sc->sc_arpcom;
12822f5860a2Smartin 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
12832f5860a2Smartin 	struct ether_multi *enm;
12842f5860a2Smartin 	struct ether_multistep step;
12852f5860a2Smartin 	int i;
12862f5860a2Smartin 
12872f5860a2Smartin 	/* Start by clearing the perfect and hash tables. */
12882f5860a2Smartin 	for (i = 0; i < SF_PERFECT_SIZE; i += sizeof(uint32_t))
12892f5860a2Smartin 		sf_genreg_write(sc, SF_PERFECT_BASE + i, 0);
12902f5860a2Smartin 
12912f5860a2Smartin 	for (i = 0; i < SF_HASH_SIZE; i += sizeof(uint32_t))
12922f5860a2Smartin 		sf_genreg_write(sc, SF_HASH_BASE + i, 0);
12932f5860a2Smartin 
12942f5860a2Smartin 	/*
12952f5860a2Smartin 	 * Clear the perfect and hash mode bits.
12962f5860a2Smartin 	 */
12972f5860a2Smartin 	sc->sc_RxAddressFilteringCtl &=
12982f5860a2Smartin 	    ~(RAFC_PerfectFilteringMode(3) | RAFC_HashFilteringMode(3));
12992f5860a2Smartin 
13002f5860a2Smartin 	if (ifp->if_flags & IFF_BROADCAST)
13012f5860a2Smartin 		sc->sc_RxAddressFilteringCtl |= RAFC_PassBroadcast;
13022f5860a2Smartin 	else
13032f5860a2Smartin 		sc->sc_RxAddressFilteringCtl &= ~RAFC_PassBroadcast;
13042f5860a2Smartin 
13052f5860a2Smartin 	if (ifp->if_flags & IFF_PROMISC) {
13062f5860a2Smartin 		sc->sc_RxAddressFilteringCtl |= RAFC_PromiscuousMode;
13072f5860a2Smartin 		goto allmulti;
13082f5860a2Smartin 	} else
13092f5860a2Smartin 		sc->sc_RxAddressFilteringCtl &= ~RAFC_PromiscuousMode;
13102f5860a2Smartin 
13112f5860a2Smartin 	/*
13122f5860a2Smartin 	 * Set normal perfect filtering mode.
13132f5860a2Smartin 	 */
13142f5860a2Smartin 	sc->sc_RxAddressFilteringCtl |= RAFC_PerfectFilteringMode(1);
13152f5860a2Smartin 
13162f5860a2Smartin 	/*
13172f5860a2Smartin 	 * First, write the station address to the perfect filter
13182f5860a2Smartin 	 * table.
13192f5860a2Smartin 	 */
13202f5860a2Smartin 	sf_set_filter_perfect(sc, 0, LLADDR(ifp->if_sadl));
13212f5860a2Smartin 
1322f2e23e59Smpi 	if (ac->ac_multirangecnt > 0)
1323f2e23e59Smpi 		goto allmulti;
1324f2e23e59Smpi 
13252f5860a2Smartin 	/*
13262f5860a2Smartin 	 * Now set the hash bits for each multicast address in our
13272f5860a2Smartin 	 * list.
13282f5860a2Smartin 	 */
13292f5860a2Smartin 	ETHER_FIRST_MULTI(step, ac, enm);
13302f5860a2Smartin 	if (enm == NULL)
13312f5860a2Smartin 		goto done;
13322f5860a2Smartin 	while (enm != NULL) {
13332f5860a2Smartin 		sf_set_filter_hash(sc, enm->enm_addrlo);
13342f5860a2Smartin 		ETHER_NEXT_MULTI(step, enm);
13352f5860a2Smartin 	}
13362f5860a2Smartin 
13372f5860a2Smartin 	/*
13382f5860a2Smartin 	 * Set "hash only multicast dest, match regardless of VLAN ID".
13392f5860a2Smartin 	 */
13402f5860a2Smartin 	sc->sc_RxAddressFilteringCtl |= RAFC_HashFilteringMode(2);
13412f5860a2Smartin 	goto done;
13422f5860a2Smartin 
13432f5860a2Smartin  allmulti:
13442f5860a2Smartin 	/*
13452f5860a2Smartin 	 * XXX RAFC_PassMulticast is sub-optimal if using VLAN mode.
13462f5860a2Smartin 	 */
13472f5860a2Smartin 	sc->sc_RxAddressFilteringCtl |= RAFC_PassMulticast;
13482f5860a2Smartin 	ifp->if_flags |= IFF_ALLMULTI;
13492f5860a2Smartin 
13502f5860a2Smartin  done:
13512f5860a2Smartin 	sf_funcreg_write(sc, SF_RxAddressFilteringCtl,
13522f5860a2Smartin 	    sc->sc_RxAddressFilteringCtl);
13532f5860a2Smartin }
13542f5860a2Smartin 
13552f5860a2Smartin /*
13562f5860a2Smartin  * sf_mii_read:		[mii interface function]
13572f5860a2Smartin  *
13582f5860a2Smartin  *	Read from the MII.
13592f5860a2Smartin  */
13602f5860a2Smartin int
sf_mii_read(struct device * self,int phy,int reg)13612f5860a2Smartin sf_mii_read(struct device *self, int phy, int reg)
13622f5860a2Smartin {
13632f5860a2Smartin 	struct sf_softc *sc = (void *) self;
13642f5860a2Smartin 	uint32_t v;
13652f5860a2Smartin 	int i;
13662f5860a2Smartin 
13672f5860a2Smartin 	for (i = 0; i < 1000; i++) {
13682f5860a2Smartin 		v = sf_genreg_read(sc, SF_MII_PHY_REG(phy, reg));
13692f5860a2Smartin 		if (v & MiiDataValid)
13702f5860a2Smartin 			break;
13712f5860a2Smartin 		delay(1);
13722f5860a2Smartin 	}
13732f5860a2Smartin 
13742f5860a2Smartin 	if ((v & MiiDataValid) == 0)
13752f5860a2Smartin 		return (0);
13762f5860a2Smartin 
13772f5860a2Smartin 	if (MiiRegDataPort(v) == 0xffff)
13782f5860a2Smartin 		return (0);
13792f5860a2Smartin 
13802f5860a2Smartin 	return (MiiRegDataPort(v));
13812f5860a2Smartin }
13822f5860a2Smartin 
13832f5860a2Smartin /*
13842f5860a2Smartin  * sf_mii_write:	[mii interface function]
13852f5860a2Smartin  *
13862f5860a2Smartin  *	Write to the MII.
13872f5860a2Smartin  */
13882f5860a2Smartin void
sf_mii_write(struct device * self,int phy,int reg,int val)13892f5860a2Smartin sf_mii_write(struct device *self, int phy, int reg, int val)
13902f5860a2Smartin {
13912f5860a2Smartin 	struct sf_softc *sc = (void *) self;
13922f5860a2Smartin 	int i;
13932f5860a2Smartin 
13942f5860a2Smartin 	sf_genreg_write(sc, SF_MII_PHY_REG(phy, reg), val);
13952f5860a2Smartin 
13962f5860a2Smartin 	for (i = 0; i < 1000; i++) {
13972f5860a2Smartin 		if ((sf_genreg_read(sc, SF_MII_PHY_REG(phy, reg)) &
13982f5860a2Smartin 		     MiiBusy) == 0)
13992f5860a2Smartin 			return;
14002f5860a2Smartin 		delay(1);
14012f5860a2Smartin 	}
14022f5860a2Smartin 
14032f5860a2Smartin 	printf("%s: MII write timed out\n", sc->sc_dev.dv_xname);
14042f5860a2Smartin }
14052f5860a2Smartin 
14062f5860a2Smartin /*
14072f5860a2Smartin  * sf_mii_statchg:	[mii interface function]
14082f5860a2Smartin  *
14092f5860a2Smartin  *	Callback from the PHY when the media changes.
14102f5860a2Smartin  */
14112f5860a2Smartin void
sf_mii_statchg(struct device * self)14122f5860a2Smartin sf_mii_statchg(struct device *self)
14132f5860a2Smartin {
14142f5860a2Smartin 	struct sf_softc *sc = (void *) self;
14152f5860a2Smartin 	uint32_t ipg;
14162f5860a2Smartin 
14172f5860a2Smartin 	if (sc->sc_mii.mii_media_active & IFM_FDX) {
14182f5860a2Smartin 		sc->sc_MacConfig1 |= MC1_FullDuplex;
14192f5860a2Smartin 		ipg = 0x15;
14202f5860a2Smartin 	} else {
14212f5860a2Smartin 		sc->sc_MacConfig1 &= ~MC1_FullDuplex;
14222f5860a2Smartin 		ipg = 0x11;
14232f5860a2Smartin 	}
14242f5860a2Smartin 
14252f5860a2Smartin 	sf_genreg_write(sc, SF_MacConfig1, sc->sc_MacConfig1);
14262f5860a2Smartin 	sf_macreset(sc);
14272f5860a2Smartin 
14282f5860a2Smartin 	sf_genreg_write(sc, SF_BkToBkIPG, ipg);
14292f5860a2Smartin }
14302f5860a2Smartin 
14312f5860a2Smartin /*
14322f5860a2Smartin  * sf_mediastatus:	[ifmedia interface function]
14332f5860a2Smartin  *
14342f5860a2Smartin  *	Callback from ifmedia to request current media status.
14352f5860a2Smartin  */
14362f5860a2Smartin void
sf_mediastatus(struct ifnet * ifp,struct ifmediareq * ifmr)14372f5860a2Smartin sf_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
14382f5860a2Smartin {
14392f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
14402f5860a2Smartin 
14412f5860a2Smartin 	mii_pollstat(&sc->sc_mii);
14422f5860a2Smartin 	ifmr->ifm_status = sc->sc_mii.mii_media_status;
14432f5860a2Smartin 	ifmr->ifm_active = sc->sc_mii.mii_media_active;
14442f5860a2Smartin }
14452f5860a2Smartin 
14462f5860a2Smartin /*
14472f5860a2Smartin  * sf_mediachange:	[ifmedia interface function]
14482f5860a2Smartin  *
14492f5860a2Smartin  *	Callback from ifmedia to request new media setting.
14502f5860a2Smartin  */
14512f5860a2Smartin int
sf_mediachange(struct ifnet * ifp)14522f5860a2Smartin sf_mediachange(struct ifnet *ifp)
14532f5860a2Smartin {
14542f5860a2Smartin 	struct sf_softc *sc = ifp->if_softc;
14552f5860a2Smartin 
14562f5860a2Smartin 	if (ifp->if_flags & IFF_UP)
14572f5860a2Smartin 		mii_mediachg(&sc->sc_mii);
14582f5860a2Smartin 	return (0);
14592f5860a2Smartin }
1460