Home | History | Annotate | Line # | Download | only in dev
if_aumac.c revision 1.12.12.1
      1  1.12.12.1     yamt /* $NetBSD: if_aumac.c,v 1.12.12.1 2006/06/21 14:53:28 yamt Exp $ */
      2        1.1   simonb 
      3        1.1   simonb /*
      4        1.1   simonb  * Copyright (c) 2001 Wasabi Systems, Inc.
      5        1.1   simonb  * All rights reserved.
      6        1.1   simonb  *
      7        1.1   simonb  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
      8        1.1   simonb  *
      9        1.1   simonb  * Redistribution and use in source and binary forms, with or without
     10        1.1   simonb  * modification, are permitted provided that the following conditions
     11        1.1   simonb  * are met:
     12        1.1   simonb  * 1. Redistributions of source code must retain the above copyright
     13        1.1   simonb  *    notice, this list of conditions and the following disclaimer.
     14        1.1   simonb  * 2. Redistributions in binary form must reproduce the above copyright
     15        1.1   simonb  *    notice, this list of conditions and the following disclaimer in the
     16        1.1   simonb  *    documentation and/or other materials provided with the distribution.
     17        1.1   simonb  * 3. All advertising materials mentioning features or use of this software
     18        1.1   simonb  *    must display the following acknowledgement:
     19        1.1   simonb  *	This product includes software developed for the NetBSD Project by
     20        1.1   simonb  *	Wasabi Systems, Inc.
     21        1.1   simonb  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22        1.1   simonb  *    or promote products derived from this software without specific prior
     23        1.1   simonb  *    written permission.
     24        1.1   simonb  *
     25        1.1   simonb  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26        1.1   simonb  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27        1.1   simonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28        1.1   simonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29        1.1   simonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30        1.1   simonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31        1.1   simonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32        1.1   simonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33        1.1   simonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34        1.1   simonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35        1.1   simonb  * POSSIBILITY OF SUCH DAMAGE.
     36        1.1   simonb  */
     37        1.1   simonb 
     38        1.1   simonb /*
     39        1.1   simonb  * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media
     40        1.1   simonb  * Access Controller.
     41        1.1   simonb  *
     42        1.1   simonb  * TODO:
     43        1.1   simonb  *
     44        1.1   simonb  *	Better Rx buffer management; we want to get new Rx buffers
     45        1.1   simonb  *	to the chip more quickly than we currently do.
     46        1.1   simonb  */
     47        1.1   simonb 
     48        1.1   simonb #include <sys/cdefs.h>
     49  1.12.12.1     yamt __KERNEL_RCSID(0, "$NetBSD: if_aumac.c,v 1.12.12.1 2006/06/21 14:53:28 yamt Exp $");
     50        1.1   simonb 
     51        1.1   simonb #include "bpfilter.h"
     52  1.12.12.1     yamt #include "rnd.h"
     53        1.1   simonb 
     54        1.1   simonb #include <sys/param.h>
     55        1.1   simonb #include <sys/systm.h>
     56        1.1   simonb #include <sys/callout.h>
     57        1.1   simonb #include <sys/mbuf.h>
     58        1.1   simonb #include <sys/malloc.h>
     59        1.1   simonb #include <sys/kernel.h>
     60        1.1   simonb #include <sys/socket.h>
     61        1.1   simonb #include <sys/ioctl.h>
     62        1.1   simonb #include <sys/errno.h>
     63        1.1   simonb #include <sys/device.h>
     64        1.1   simonb #include <sys/queue.h>
     65        1.1   simonb 
     66        1.1   simonb #include <uvm/uvm_extern.h>		/* for PAGE_SIZE */
     67        1.1   simonb 
     68        1.1   simonb #include <net/if.h>
     69        1.1   simonb #include <net/if_dl.h>
     70        1.1   simonb #include <net/if_media.h>
     71        1.1   simonb #include <net/if_ether.h>
     72        1.1   simonb 
     73        1.1   simonb #if NBPFILTER > 0
     74        1.1   simonb #include <net/bpf.h>
     75        1.1   simonb #endif
     76  1.12.12.1     yamt #if NRND > 0
     77  1.12.12.1     yamt #include <sys/rnd.h>
     78  1.12.12.1     yamt #endif
     79        1.1   simonb 
     80        1.1   simonb #include <machine/bus.h>
     81        1.1   simonb #include <machine/intr.h>
     82        1.1   simonb #include <machine/endian.h>
     83        1.1   simonb 
     84        1.1   simonb #include <dev/mii/mii.h>
     85        1.1   simonb #include <dev/mii/miivar.h>
     86        1.1   simonb 
     87        1.1   simonb #include <mips/alchemy/include/aureg.h>
     88        1.1   simonb #include <mips/alchemy/include/auvar.h>
     89        1.1   simonb #include <mips/alchemy/include/aubusvar.h>
     90        1.1   simonb #include <mips/alchemy/dev/if_aumacreg.h>
     91        1.1   simonb 
     92        1.1   simonb /*
     93        1.1   simonb  * The Au1X00 MAC has 4 transmit and receive descriptors.  Each buffer
     94        1.1   simonb  * must consist of a single DMA segment, and must be aligned to a 2K
     95        1.1   simonb  * boundary.  Therefore, this driver does not perform DMA directly
     96        1.1   simonb  * to/from mbufs.  Instead, we copy the data to/from buffers allocated
     97        1.1   simonb  * at device attach time.
     98        1.1   simonb  *
     99        1.1   simonb  * We also skip the bus_dma dance.  The MAC is built in to the CPU, so
    100        1.1   simonb  * there's little point in not making assumptions based on the CPU type.
    101        1.1   simonb  * We also program the Au1X00 cache to be DMA coherent, so the buffers
    102        1.1   simonb  * are accessed via KSEG0 addresses.
    103        1.1   simonb  */
    104        1.1   simonb #define	AUMAC_NTXDESC		4
    105        1.1   simonb #define	AUMAC_NTXDESC_MASK	(AUMAC_NTXDESC - 1)
    106        1.1   simonb 
    107        1.1   simonb #define	AUMAC_NRXDESC		4
    108        1.1   simonb #define	AUMAC_NRXDESC_MASK	(AUMAC_NRXDESC - 1)
    109        1.1   simonb 
    110        1.1   simonb #define	AUMAC_NEXTTX(x)		(((x) + 1) & AUMAC_NTXDESC_MASK)
    111        1.1   simonb #define	AUMAC_NEXTRX(x)		(((x) + 1) & AUMAC_NRXDESC_MASK)
    112        1.1   simonb 
    113        1.1   simonb #define	AUMAC_TXBUF_OFFSET	0
    114        1.1   simonb #define	AUMAC_RXBUF_OFFSET	(MAC_BUFLEN * AUMAC_NTXDESC)
    115        1.1   simonb #define	AUMAC_BUFSIZE		(MAC_BUFLEN * (AUMAC_NTXDESC + AUMAC_NRXDESC))
    116        1.1   simonb 
    117        1.1   simonb struct aumac_buf {
    118        1.1   simonb 	caddr_t buf_vaddr;		/* virtual address of buffer */
    119        1.1   simonb 	bus_addr_t buf_paddr;		/* DMA address of buffer */
    120        1.1   simonb };
    121        1.1   simonb 
    122        1.1   simonb /*
    123        1.1   simonb  * Software state per device.
    124        1.1   simonb  */
    125        1.1   simonb struct aumac_softc {
    126        1.1   simonb 	struct device sc_dev;		/* generic device information */
    127        1.1   simonb 	bus_space_tag_t sc_st;		/* bus space tag */
    128        1.1   simonb 	bus_space_handle_t sc_mac_sh;	/* MAC space handle */
    129        1.1   simonb 	bus_space_handle_t sc_macen_sh;	/* MAC enable space handle */
    130        1.1   simonb 	bus_space_handle_t sc_dma_sh;	/* DMA space handle */
    131        1.1   simonb 	struct ethercom sc_ethercom;	/* Ethernet common data */
    132        1.1   simonb 	void *sc_sdhook;		/* shutdown hook */
    133        1.1   simonb 
    134        1.1   simonb 	void *sc_ih;			/* interrupt cookie */
    135        1.1   simonb 
    136        1.1   simonb 	struct mii_data sc_mii;		/* MII/media information */
    137        1.1   simonb 
    138        1.1   simonb 	struct callout sc_tick_ch;	/* tick callout */
    139        1.1   simonb 
    140        1.1   simonb 	/* Transmit and receive buffers */
    141        1.1   simonb 	struct aumac_buf sc_txbufs[AUMAC_NTXDESC];
    142        1.1   simonb 	struct aumac_buf sc_rxbufs[AUMAC_NRXDESC];
    143        1.1   simonb 	caddr_t sc_bufaddr;
    144        1.1   simonb 
    145        1.1   simonb 	int sc_txfree;			/* number of free Tx descriptors */
    146        1.1   simonb 	int sc_txnext;			/* next Tx descriptor to use */
    147        1.1   simonb 	int sc_txdirty;			/* first dirty Tx descriptor */
    148        1.1   simonb 
    149        1.1   simonb 	int sc_rxptr;			/* next ready Rx descriptor */
    150        1.1   simonb 
    151  1.12.12.1     yamt #if NRND > 0
    152  1.12.12.1     yamt 	rndsource_element_t rnd_source;
    153  1.12.12.1     yamt #endif
    154  1.12.12.1     yamt 
    155        1.1   simonb #ifdef AUMAC_EVENT_COUNTERS
    156        1.1   simonb 	struct evcnt sc_ev_txstall;	/* Tx stalled */
    157        1.1   simonb 	struct evcnt sc_ev_rxstall;	/* Rx stalled */
    158        1.1   simonb 	struct evcnt sc_ev_txintr;	/* Tx interrupts */
    159        1.1   simonb 	struct evcnt sc_ev_rxintr;	/* Rx interrupts */
    160        1.1   simonb #endif
    161        1.1   simonb 
    162        1.1   simonb 	uint32_t sc_control;		/* MAC_CONTROL contents */
    163        1.1   simonb 	uint32_t sc_flowctrl;		/* MAC_FLOWCTRL contents */
    164        1.1   simonb };
    165        1.1   simonb 
    166        1.1   simonb #ifdef AUMAC_EVENT_COUNTERS
    167        1.1   simonb #define	AUMAC_EVCNT_INCR(ev)	(ev)->ev_count++
    168        1.8   simonb #else
    169        1.8   simonb #define	AUMAC_EVCNT_INCR(ev)	/* nothing */
    170        1.1   simonb #endif
    171        1.1   simonb 
    172        1.1   simonb #define	AUMAC_INIT_RXDESC(sc, x)					\
    173        1.1   simonb do {									\
    174        1.1   simonb 	bus_space_write_4((sc)->sc_st, (sc)->sc_dma_sh,			\
    175        1.1   simonb 	    MACDMA_RX_STAT((x)), 0);					\
    176        1.1   simonb 	bus_space_write_4((sc)->sc_st, (sc)->sc_dma_sh,			\
    177        1.1   simonb 	    MACDMA_RX_ADDR((x)),					\
    178        1.1   simonb 	    (sc)->sc_rxbufs[(x)].buf_paddr | RX_ADDR_EN);		\
    179        1.1   simonb } while (/*CONSTCOND*/0)
    180        1.1   simonb 
    181        1.1   simonb static void	aumac_start(struct ifnet *);
    182        1.1   simonb static void	aumac_watchdog(struct ifnet *);
    183        1.1   simonb static int	aumac_ioctl(struct ifnet *, u_long, caddr_t);
    184        1.1   simonb static int	aumac_init(struct ifnet *);
    185        1.1   simonb static void	aumac_stop(struct ifnet *, int);
    186        1.1   simonb 
    187        1.1   simonb static void	aumac_shutdown(void *);
    188        1.1   simonb 
    189        1.1   simonb static void	aumac_tick(void *);
    190        1.1   simonb 
    191        1.1   simonb static void	aumac_set_filter(struct aumac_softc *);
    192        1.1   simonb 
    193        1.1   simonb static void	aumac_powerup(struct aumac_softc *);
    194        1.1   simonb static void	aumac_powerdown(struct aumac_softc *);
    195        1.1   simonb 
    196        1.1   simonb static int	aumac_intr(void *);
    197  1.12.12.1     yamt static int	aumac_txintr(struct aumac_softc *);
    198  1.12.12.1     yamt static int	aumac_rxintr(struct aumac_softc *);
    199        1.1   simonb 
    200        1.1   simonb static int	aumac_mii_readreg(struct device *, int, int);
    201        1.1   simonb static void	aumac_mii_writereg(struct device *, int, int, int);
    202        1.1   simonb static void	aumac_mii_statchg(struct device *);
    203        1.1   simonb static int	aumac_mii_wait(struct aumac_softc *, const char *);
    204        1.1   simonb 
    205        1.1   simonb static int	aumac_mediachange(struct ifnet *);
    206        1.1   simonb static void	aumac_mediastatus(struct ifnet *, struct ifmediareq *);
    207        1.1   simonb 
    208        1.1   simonb static int	aumac_match(struct device *, struct cfdata *, void *);
    209        1.1   simonb static void	aumac_attach(struct device *, struct device *, void *);
    210        1.1   simonb 
    211        1.1   simonb int	aumac_copy_small = 0;
    212        1.1   simonb 
    213        1.5  thorpej CFATTACH_DECL(aumac, sizeof(struct aumac_softc),
    214        1.6  thorpej     aumac_match, aumac_attach, NULL, NULL);
    215        1.1   simonb 
    216        1.1   simonb static int
    217        1.1   simonb aumac_match(struct device *parent, struct cfdata *cf, void *aux)
    218        1.1   simonb {
    219        1.1   simonb 	struct aubus_attach_args *aa = aux;
    220        1.1   simonb 
    221        1.3  thorpej 	if (strcmp(aa->aa_name, cf->cf_name) == 0)
    222        1.1   simonb 		return (1);
    223        1.1   simonb 
    224        1.1   simonb 	return (0);
    225        1.1   simonb }
    226        1.1   simonb 
    227        1.1   simonb static void
    228        1.1   simonb aumac_attach(struct device *parent, struct device *self, void *aux)
    229        1.1   simonb {
    230  1.12.12.1     yamt 	const uint8_t *enaddr;
    231  1.12.12.1     yamt 	prop_data_t ea;
    232        1.1   simonb 	struct aumac_softc *sc = (void *) self;
    233        1.1   simonb 	struct aubus_attach_args *aa = aux;
    234        1.1   simonb 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    235        1.1   simonb 	struct pglist pglist;
    236        1.1   simonb 	paddr_t bufaddr;
    237        1.1   simonb 	caddr_t vbufaddr;
    238        1.1   simonb 	int i;
    239        1.1   simonb 
    240        1.1   simonb 	callout_init(&sc->sc_tick_ch);
    241        1.1   simonb 
    242        1.1   simonb 	printf(": Au1X00 10/100 Ethernet\n");
    243        1.1   simonb 
    244        1.1   simonb 	sc->sc_st = aa->aa_st;
    245        1.1   simonb 
    246        1.1   simonb 	/* Get the MAC address. */
    247  1.12.12.1     yamt 	ea = prop_dictionary_get(device_properties(&sc->sc_dev), "mac-addr");
    248  1.12.12.1     yamt 	if (ea == NULL) {
    249       1.11  thorpej 		printf("%s: unable to get mac-addr property\n",
    250        1.1   simonb 		    sc->sc_dev.dv_xname);
    251        1.1   simonb 		return;
    252        1.1   simonb 	}
    253  1.12.12.1     yamt 	KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
    254  1.12.12.1     yamt 	KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
    255  1.12.12.1     yamt 	enaddr = prop_data_data_nocopy(ea);
    256        1.1   simonb 
    257        1.1   simonb 	printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname,
    258        1.1   simonb 	    ether_sprintf(enaddr));
    259        1.1   simonb 
    260        1.1   simonb 	/* Map the device. */
    261        1.1   simonb 	if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_BASE],
    262        1.1   simonb 	    MACx_SIZE, 0, &sc->sc_mac_sh) != 0) {
    263        1.1   simonb 		printf("%s: unable to map MAC registers\n",
    264        1.1   simonb 		    sc->sc_dev.dv_xname);
    265        1.1   simonb 		return;
    266        1.1   simonb 	}
    267        1.1   simonb 	if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_ENABLE],
    268        1.1   simonb 	    MACENx_SIZE, 0, &sc->sc_macen_sh) != 0) {
    269        1.1   simonb 		printf("%s: unable to map MACEN registers\n",
    270        1.1   simonb 		    sc->sc_dev.dv_xname);
    271        1.1   simonb 		return;
    272        1.1   simonb 	}
    273        1.1   simonb 	if (bus_space_map(sc->sc_st, aa->aa_addrs[AA_MAC_DMA_BASE],
    274        1.1   simonb 	    MACx_DMA_SIZE, 0, &sc->sc_dma_sh) != 0) {
    275        1.1   simonb 		printf("%s: unable to map MACDMA registers\n",
    276        1.1   simonb 		    sc->sc_dev.dv_xname);
    277        1.1   simonb 		return;
    278        1.1   simonb 	}
    279        1.1   simonb 
    280        1.1   simonb 	/* Make sure the MAC is powered off. */
    281        1.1   simonb 	aumac_powerdown(sc);
    282        1.1   simonb 
    283        1.1   simonb 	/* Hook up the interrupt handler. */
    284        1.2   simonb 	sc->sc_ih = au_intr_establish(aa->aa_irq[0], 1, IPL_NET, IST_LEVEL,
    285        1.1   simonb 	    aumac_intr, sc);
    286        1.1   simonb 	if (sc->sc_ih == NULL) {
    287        1.1   simonb 		printf("%s: unable to register interrupt handler\n",
    288        1.1   simonb 		    sc->sc_dev.dv_xname);
    289        1.1   simonb 		return;
    290        1.1   simonb 	}
    291        1.1   simonb 
    292        1.1   simonb 	/*
    293        1.1   simonb 	 * Allocate space for the transmit and receive buffers.
    294        1.1   simonb 	 */
    295        1.1   simonb 	if (uvm_pglistalloc(AUMAC_BUFSIZE, 0, ctob(physmem), PAGE_SIZE, 0,
    296        1.1   simonb 	    &pglist, 1, 0))
    297        1.1   simonb 		return;
    298        1.1   simonb 
    299  1.12.12.1     yamt 	bufaddr = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));
    300        1.1   simonb 	vbufaddr = (void *)MIPS_PHYS_TO_KSEG0(bufaddr);
    301        1.1   simonb 
    302        1.1   simonb 	for (i = 0; i < AUMAC_NTXDESC; i++) {
    303        1.1   simonb 		int offset = AUMAC_TXBUF_OFFSET + (i * MAC_BUFLEN);
    304        1.1   simonb 
    305        1.1   simonb 		sc->sc_txbufs[i].buf_vaddr = vbufaddr + offset;
    306        1.1   simonb 		sc->sc_txbufs[i].buf_paddr = bufaddr + offset;
    307        1.1   simonb 	}
    308        1.1   simonb 
    309        1.1   simonb 	for (i = 0; i < AUMAC_NRXDESC; i++) {
    310        1.1   simonb 		int offset = AUMAC_RXBUF_OFFSET + (i * MAC_BUFLEN);
    311        1.1   simonb 
    312        1.1   simonb 		sc->sc_rxbufs[i].buf_vaddr = vbufaddr + offset;
    313        1.1   simonb 		sc->sc_rxbufs[i].buf_paddr = bufaddr + offset;
    314        1.1   simonb 	}
    315        1.1   simonb 
    316        1.1   simonb 	/*
    317        1.1   simonb 	 * Power up the MAC before accessing any MAC registers (including
    318        1.1   simonb 	 * MII configuration.
    319        1.1   simonb 	 */
    320        1.1   simonb 	aumac_powerup(sc);
    321        1.1   simonb 
    322        1.1   simonb 	/*
    323        1.1   simonb 	 * Initialize the media structures and probe the MII.
    324        1.1   simonb 	 */
    325        1.1   simonb 	sc->sc_mii.mii_ifp = ifp;
    326        1.1   simonb 	sc->sc_mii.mii_readreg = aumac_mii_readreg;
    327        1.1   simonb 	sc->sc_mii.mii_writereg = aumac_mii_writereg;
    328        1.1   simonb 	sc->sc_mii.mii_statchg = aumac_mii_statchg;
    329        1.1   simonb 	ifmedia_init(&sc->sc_mii.mii_media, 0, aumac_mediachange,
    330        1.1   simonb 	    aumac_mediastatus);
    331        1.1   simonb 
    332        1.1   simonb 	mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
    333        1.1   simonb 	    MII_OFFSET_ANY, 0);
    334        1.1   simonb 
    335        1.1   simonb 	if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
    336        1.1   simonb 		ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
    337        1.1   simonb 		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
    338        1.1   simonb 	} else
    339        1.1   simonb 		ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
    340        1.1   simonb 
    341        1.1   simonb 	strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
    342        1.1   simonb 	ifp->if_softc = sc;
    343        1.1   simonb 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    344        1.1   simonb 	ifp->if_ioctl = aumac_ioctl;
    345        1.1   simonb 	ifp->if_start = aumac_start;
    346        1.1   simonb 	ifp->if_watchdog = aumac_watchdog;
    347        1.1   simonb 	ifp->if_init = aumac_init;
    348        1.1   simonb 	ifp->if_stop = aumac_stop;
    349        1.1   simonb 	IFQ_SET_READY(&ifp->if_snd);
    350        1.1   simonb 
    351        1.1   simonb 	/* Attach the interface. */
    352        1.1   simonb 	if_attach(ifp);
    353        1.1   simonb 	ether_ifattach(ifp, enaddr);
    354        1.1   simonb 
    355  1.12.12.1     yamt #if NRND > 0
    356  1.12.12.1     yamt 	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
    357  1.12.12.1     yamt 	    RND_TYPE_NET, 0);
    358  1.12.12.1     yamt #endif
    359  1.12.12.1     yamt 
    360        1.1   simonb #ifdef AUMAC_EVENT_COUNTERS
    361        1.1   simonb 	evcnt_attach_dynamic(&sc->sc_ev_txstall, EVCNT_TYPE_MISC,
    362        1.1   simonb 	    NULL, sc->sc_dev.dv_xname, "txstall");
    363        1.1   simonb 	evcnt_attach_dynamic(&sc->sc_ev_rxstall, EVCNT_TYPE_MISC,
    364        1.1   simonb 	    NULL, sc->sc_dev.dv_xname, "rxstall");
    365        1.1   simonb 	evcnt_attach_dynamic(&sc->sc_ev_txintr, EVCNT_TYPE_MISC,
    366        1.1   simonb 	    NULL, sc->sc_dev.dv_xname, "txintr");
    367        1.1   simonb 	evcnt_attach_dynamic(&sc->sc_ev_rxintr, EVCNT_TYPE_MISC,
    368       1.10   simonb 	    NULL, sc->sc_dev.dv_xname, "rxintr");
    369        1.1   simonb #endif
    370        1.1   simonb 
    371        1.1   simonb 	/* Make sure the interface is shutdown during reboot. */
    372        1.1   simonb 	sc->sc_sdhook = shutdownhook_establish(aumac_shutdown, sc);
    373        1.1   simonb 	if (sc->sc_sdhook == NULL)
    374        1.1   simonb 		printf("%s: WARNING: unable to establish shutdown hook\n",
    375        1.1   simonb 		    sc->sc_dev.dv_xname);
    376        1.1   simonb 	return;
    377        1.1   simonb }
    378        1.1   simonb 
    379        1.1   simonb /*
    380        1.1   simonb  * aumac_shutdown:
    381        1.1   simonb  *
    382        1.1   simonb  *	Make sure the interface is stopped at reboot time.
    383        1.1   simonb  */
    384        1.1   simonb static void
    385        1.1   simonb aumac_shutdown(void *arg)
    386        1.1   simonb {
    387        1.1   simonb 	struct aumac_softc *sc = arg;
    388        1.1   simonb 
    389        1.1   simonb 	aumac_stop(&sc->sc_ethercom.ec_if, 1);
    390        1.1   simonb 
    391        1.1   simonb 	/*
    392        1.1   simonb 	 * XXX aumac_stop leaves device powered up at the moment
    393        1.1   simonb 	 * XXX but this still isn't enough to keep yamon happy... :-(
    394        1.1   simonb 	 */
    395        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, 0);
    396        1.1   simonb }
    397        1.1   simonb 
    398        1.1   simonb /*
    399        1.1   simonb  * aumac_start:		[ifnet interface function]
    400        1.1   simonb  *
    401        1.1   simonb  *	Start packet transmission on the interface.
    402        1.1   simonb  */
    403        1.1   simonb static void
    404        1.1   simonb aumac_start(struct ifnet *ifp)
    405        1.1   simonb {
    406        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    407        1.1   simonb 	struct mbuf *m;
    408        1.1   simonb 	int nexttx;
    409        1.1   simonb 
    410        1.1   simonb 	if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
    411        1.1   simonb 		return;
    412        1.1   simonb 
    413        1.1   simonb 	/*
    414        1.1   simonb 	 * Loop through the send queue, setting up transmit descriptors
    415        1.1   simonb 	 * unitl we drain the queue, or use up all available transmit
    416        1.1   simonb 	 * descriptors.
    417        1.1   simonb 	 */
    418        1.1   simonb 	for (;;) {
    419        1.1   simonb 		/* Grab a packet off the queue. */
    420        1.1   simonb 		IFQ_POLL(&ifp->if_snd, m);
    421        1.1   simonb 		if (m == NULL)
    422        1.1   simonb 			return;
    423        1.1   simonb 
    424        1.1   simonb 		/* Get a spare descriptor. */
    425        1.1   simonb 		if (sc->sc_txfree == 0) {
    426        1.1   simonb 			/* No more slots left; notify upper layer. */
    427        1.1   simonb 			ifp->if_flags |= IFF_OACTIVE;
    428        1.1   simonb 			AUMAC_EVCNT_INCR(&sc->sc_ev_txstall);
    429        1.1   simonb 			return;
    430        1.1   simonb 		}
    431        1.1   simonb 		nexttx = sc->sc_txnext;
    432        1.1   simonb 
    433        1.1   simonb 		IFQ_DEQUEUE(&ifp->if_snd, m);
    434        1.1   simonb 
    435        1.1   simonb 		/*
    436        1.1   simonb 		 * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
    437        1.1   simonb 		 */
    438        1.1   simonb 
    439        1.1   simonb 		m_copydata(m, 0, m->m_pkthdr.len,
    440        1.1   simonb 		    sc->sc_txbufs[nexttx].buf_vaddr);
    441        1.9   simonb 
    442        1.9   simonb 		/* Zero out the remainder of any short packets. */
    443        1.9   simonb 		if (m->m_pkthdr.len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
    444        1.9   simonb 			memset(sc->sc_txbufs[nexttx].buf_vaddr +
    445        1.9   simonb 			    m->m_pkthdr.len, 0,
    446        1.9   simonb 			    ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len);
    447        1.1   simonb 
    448        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    449        1.1   simonb 		    MACDMA_TX_STAT(nexttx), 0);
    450        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    451        1.1   simonb 		    MACDMA_TX_LEN(nexttx),
    452        1.1   simonb 		    m->m_pkthdr.len < (ETHER_MIN_LEN - ETHER_CRC_LEN) ?
    453        1.1   simonb 		    ETHER_MIN_LEN - ETHER_CRC_LEN : m->m_pkthdr.len);
    454        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    455        1.1   simonb 		    MACDMA_TX_ADDR(nexttx),
    456        1.1   simonb 		    sc->sc_txbufs[nexttx].buf_paddr | TX_ADDR_EN);
    457        1.1   simonb 		/* XXX - needed??  we should be coherent */
    458        1.1   simonb 		bus_space_barrier(sc->sc_st, sc->sc_dma_sh, 0 /* XXX */,
    459        1.1   simonb 		    0 /* XXX */, BUS_SPACE_BARRIER_WRITE);
    460        1.1   simonb 
    461        1.1   simonb 		/* Advance the Tx pointer. */
    462        1.1   simonb 		sc->sc_txfree--;
    463        1.1   simonb 		sc->sc_txnext = AUMAC_NEXTTX(nexttx);
    464        1.1   simonb 
    465        1.1   simonb #if NBPFILTER > 0
    466        1.1   simonb 		/* Pass the packet to any BPF listeners. */
    467        1.1   simonb 		if (ifp->if_bpf)
    468        1.1   simonb 			bpf_mtap(ifp->if_bpf, m);
    469        1.1   simonb #endif /* NBPFILTER */
    470        1.1   simonb 
    471        1.1   simonb 		m_freem(m);
    472        1.1   simonb 
    473        1.1   simonb 		/* Set a watchdog timer in case the chip flakes out. */
    474        1.1   simonb 		ifp->if_timer = 5;
    475        1.1   simonb 	}
    476        1.1   simonb 	/* NOTREACHED */
    477        1.1   simonb }
    478        1.1   simonb 
    479        1.1   simonb /*
    480        1.1   simonb  * aumac_watchdog:	[ifnet interface function]
    481        1.1   simonb  *
    482        1.1   simonb  *	Watchdog timer handler.
    483        1.1   simonb  */
    484        1.1   simonb static void
    485        1.1   simonb aumac_watchdog(struct ifnet *ifp)
    486        1.1   simonb {
    487        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    488        1.1   simonb 
    489        1.1   simonb 	printf("%s: device timeout\n", sc->sc_dev.dv_xname);
    490        1.1   simonb 	(void) aumac_init(ifp);
    491        1.1   simonb 
    492        1.1   simonb 	/* Try to get more packets going. */
    493        1.1   simonb 	aumac_start(ifp);
    494        1.1   simonb }
    495        1.1   simonb 
    496        1.1   simonb /*
    497        1.1   simonb  * aumac_ioctl:		[ifnet interface function]
    498        1.1   simonb  *
    499        1.1   simonb  *	Handle control requests from the operator.
    500        1.1   simonb  */
    501        1.1   simonb static int
    502        1.1   simonb aumac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    503        1.1   simonb {
    504        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    505        1.1   simonb 	struct ifreq *ifr = (struct ifreq *) data;
    506        1.1   simonb 	int s, error;
    507        1.1   simonb 
    508        1.1   simonb 	s = splnet();
    509        1.1   simonb 
    510        1.1   simonb 	switch (cmd) {
    511        1.1   simonb 	case SIOCSIFMEDIA:
    512        1.1   simonb 	case SIOCGIFMEDIA:
    513        1.1   simonb 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
    514        1.1   simonb 		break;
    515        1.1   simonb 
    516        1.1   simonb 	default:
    517        1.1   simonb 		error = ether_ioctl(ifp, cmd, data);
    518        1.1   simonb 		if (error == ENETRESET) {
    519        1.1   simonb 			/*
    520        1.1   simonb 			 * Multicast list has changed; set the hardware filter
    521        1.1   simonb 			 * accordingly.
    522        1.1   simonb 			 */
    523       1.12  thorpej 			if (ifp->if_flags & IFF_RUNNING)
    524       1.12  thorpej 				aumac_set_filter(sc);
    525        1.1   simonb 		}
    526        1.1   simonb 		break;
    527        1.1   simonb 	}
    528        1.1   simonb 
    529        1.1   simonb 	/* Try to get more packets going. */
    530        1.1   simonb 	aumac_start(ifp);
    531        1.1   simonb 
    532        1.1   simonb 	splx(s);
    533        1.1   simonb 	return (error);
    534        1.1   simonb }
    535        1.1   simonb 
    536        1.1   simonb /*
    537        1.1   simonb  * aumac_intr:
    538        1.1   simonb  *
    539        1.1   simonb  *	Interrupt service routine.
    540        1.1   simonb  */
    541        1.1   simonb static int
    542        1.1   simonb aumac_intr(void *arg)
    543        1.1   simonb {
    544        1.1   simonb 	struct aumac_softc *sc = arg;
    545  1.12.12.1     yamt 	int status;
    546        1.1   simonb 
    547        1.1   simonb 	/*
    548        1.1   simonb 	 * There aren't really any interrupt status bits on the
    549        1.1   simonb 	 * Au1X00 MAC, and each MAC has a dedicated interrupt
    550        1.1   simonb 	 * in the CPU's built-in interrupt controller.  Just
    551        1.1   simonb 	 * check for new incoming packets, and then Tx completions
    552        1.1   simonb 	 * (for status updating).
    553        1.1   simonb 	 */
    554        1.1   simonb 	if ((sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING) == 0)
    555        1.1   simonb 		return (0);
    556        1.1   simonb 
    557  1.12.12.1     yamt 	status = aumac_rxintr(sc);
    558  1.12.12.1     yamt 	status += aumac_txintr(sc);
    559        1.1   simonb 
    560  1.12.12.1     yamt #if NRND > 0
    561  1.12.12.1     yamt 	if (RND_ENABLED(&sc->rnd_source))
    562  1.12.12.1     yamt 		rnd_add_uint32(&sc->rnd_source, status);
    563  1.12.12.1     yamt #endif
    564  1.12.12.1     yamt 
    565  1.12.12.1     yamt 	return status;
    566        1.1   simonb }
    567        1.1   simonb 
    568        1.1   simonb /*
    569        1.1   simonb  * aumac_txintr:
    570        1.1   simonb  *
    571        1.1   simonb  *	Helper; handle transmit interrupts.
    572        1.1   simonb  */
    573  1.12.12.1     yamt static int
    574        1.1   simonb aumac_txintr(struct aumac_softc *sc)
    575        1.1   simonb {
    576        1.1   simonb 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    577        1.1   simonb 	uint32_t stat;
    578        1.1   simonb 	int i;
    579  1.12.12.1     yamt 	int pkts = 0;
    580        1.1   simonb 
    581        1.1   simonb 	for (i = sc->sc_txdirty; sc->sc_txfree != AUMAC_NTXDESC;
    582        1.1   simonb 	     i = AUMAC_NEXTTX(i)) {
    583        1.1   simonb 		if ((bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    584        1.1   simonb 		     MACDMA_TX_ADDR(i)) & TX_ADDR_DN) == 0)
    585        1.1   simonb 			break;
    586  1.12.12.1     yamt 		pkts++;
    587        1.1   simonb 
    588        1.1   simonb 		/* ACK interrupt. */
    589        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    590        1.1   simonb 		    MACDMA_TX_ADDR(i), 0);
    591        1.1   simonb 
    592        1.1   simonb 		stat = bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    593        1.1   simonb 		    MACDMA_TX_STAT(i));
    594        1.1   simonb 
    595        1.1   simonb 		if (stat & TX_STAT_FA) {
    596        1.1   simonb 			/* XXX STATS */
    597        1.1   simonb 			ifp->if_oerrors++;
    598        1.1   simonb 		} else
    599        1.1   simonb 			ifp->if_opackets++;
    600        1.1   simonb 
    601        1.1   simonb 		if (stat & TX_STAT_EC)
    602        1.1   simonb 			ifp->if_collisions += 16;
    603        1.1   simonb 		else
    604        1.1   simonb 			ifp->if_collisions += TX_STAT_CC(stat);
    605        1.1   simonb 
    606        1.1   simonb 		sc->sc_txfree++;
    607        1.1   simonb 		ifp->if_flags &= ~IFF_OACTIVE;
    608        1.1   simonb 
    609        1.1   simonb 		/* Try to queue more packets. */
    610        1.1   simonb 		aumac_start(ifp);
    611        1.1   simonb 	}
    612        1.1   simonb 
    613  1.12.12.1     yamt 	if (pkts)
    614        1.1   simonb 		AUMAC_EVCNT_INCR(&sc->sc_ev_txintr);
    615        1.1   simonb 
    616        1.1   simonb 	/* Update the dirty descriptor pointer. */
    617        1.1   simonb 	sc->sc_txdirty = i;
    618        1.1   simonb 
    619        1.1   simonb 	/*
    620        1.1   simonb 	 * If there are no more pending transmissions, cancel the watchdog
    621        1.1   simonb 	 * timer.
    622        1.1   simonb 	 */
    623        1.1   simonb 	if (sc->sc_txfree == AUMAC_NTXDESC)
    624        1.1   simonb 		ifp->if_timer = 0;
    625  1.12.12.1     yamt 
    626  1.12.12.1     yamt 	return pkts;
    627        1.1   simonb }
    628        1.1   simonb 
    629        1.1   simonb /*
    630        1.1   simonb  * aumac_rxintr:
    631        1.1   simonb  *
    632        1.1   simonb  *	Helper; handle receive interrupts.
    633        1.1   simonb  */
    634  1.12.12.1     yamt static int
    635        1.1   simonb aumac_rxintr(struct aumac_softc *sc)
    636        1.1   simonb {
    637        1.1   simonb 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    638        1.1   simonb 	struct mbuf *m;
    639        1.1   simonb 	uint32_t stat;
    640        1.1   simonb 	int i, len;
    641        1.1   simonb 	int pkts = 0;
    642        1.1   simonb 
    643        1.1   simonb 	for (i = sc->sc_rxptr;; i = AUMAC_NEXTRX(i)) {
    644        1.1   simonb 		if ((bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    645        1.1   simonb 		     MACDMA_RX_ADDR(i)) & RX_ADDR_DN) == 0)
    646        1.1   simonb 			break;
    647        1.1   simonb 		pkts++;
    648        1.1   simonb 
    649        1.1   simonb 		stat = bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    650        1.1   simonb 		    MACDMA_RX_STAT(i));
    651        1.1   simonb 
    652        1.1   simonb #define PRINTERR(str)							\
    653        1.1   simonb 	do {								\
    654        1.1   simonb 		error++;						\
    655        1.1   simonb 		printf("%s: %s\n", sc->sc_dev.dv_xname, str);		\
    656        1.1   simonb 	} while (0)
    657        1.1   simonb 
    658        1.1   simonb 		if (stat & RX_STAT_ERRS) {
    659        1.1   simonb 			int error = 0;
    660        1.1   simonb 
    661        1.1   simonb 			if (stat & RX_STAT_MI)
    662        1.1   simonb 				PRINTERR("missed frame");
    663        1.1   simonb 			if (stat & RX_STAT_UC)
    664        1.1   simonb 				PRINTERR("unknown control frame");
    665        1.1   simonb 			if (stat & RX_STAT_LE)
    666        1.1   simonb 				PRINTERR("short frame");
    667        1.1   simonb 			if (stat & RX_STAT_CR)
    668        1.1   simonb 				PRINTERR("CRC error");
    669        1.1   simonb 			if (stat & RX_STAT_ME)
    670        1.1   simonb 				PRINTERR("medium error");
    671        1.1   simonb 			if (stat & RX_STAT_CS)
    672        1.1   simonb 				PRINTERR("late collision");
    673        1.1   simonb 			if (stat & RX_STAT_FL)
    674        1.1   simonb 				PRINTERR("frame too big");
    675        1.1   simonb 			if (stat & RX_STAT_RF)
    676        1.1   simonb 				PRINTERR("runt frame (collision)");
    677        1.1   simonb 			if (stat & RX_STAT_WT)
    678        1.1   simonb 				PRINTERR("watch dog");
    679        1.1   simonb 			if (stat & RX_STAT_DB) {
    680        1.1   simonb 				if (stat & (RX_STAT_CS | RX_STAT_RF |
    681        1.1   simonb 				    RX_STAT_CR)) {
    682        1.1   simonb 					if (!error)
    683        1.1   simonb 						goto pktok;
    684        1.1   simonb 				} else
    685        1.1   simonb 					PRINTERR("dribbling bit");
    686        1.1   simonb 			}
    687        1.1   simonb #undef PRINTERR
    688        1.1   simonb 			ifp->if_ierrors++;
    689        1.1   simonb 
    690        1.1   simonb  dropit:
    691        1.1   simonb 			/* reuse the current descriptor */
    692        1.1   simonb 			AUMAC_INIT_RXDESC(sc, i);
    693        1.1   simonb 			continue;
    694        1.1   simonb 		}
    695        1.1   simonb  pktok:
    696        1.1   simonb 		len = RX_STAT_L(stat);
    697        1.1   simonb 
    698        1.1   simonb 		/*
    699        1.1   simonb 		 * The Au1X00 MAC includes the CRC with every packet;
    700        1.1   simonb 		 * trim it off here.
    701        1.1   simonb 		 */
    702        1.1   simonb 		len -= ETHER_CRC_LEN;
    703        1.1   simonb 
    704        1.1   simonb 		/*
    705        1.1   simonb 		 * Truncate the packet if it's too big to fit in
    706        1.1   simonb 		 * a single mbuf cluster.
    707        1.1   simonb 		 */
    708        1.1   simonb 		if (len > MCLBYTES - 2)
    709        1.1   simonb 			len = MCLBYTES - 2;
    710        1.1   simonb 
    711        1.1   simonb 		MGETHDR(m, M_DONTWAIT, MT_DATA);
    712        1.1   simonb 		if (m == NULL) {
    713        1.1   simonb 			printf("%s: unable to allocate Rx mbuf\n",
    714        1.1   simonb 			    sc->sc_dev.dv_xname);
    715        1.1   simonb 			goto dropit;
    716        1.1   simonb 		}
    717        1.1   simonb 		if (len > MHLEN - 2) {
    718        1.1   simonb 			MCLGET(m, M_DONTWAIT);
    719        1.1   simonb 			if ((m->m_flags & M_EXT) == 0) {
    720        1.1   simonb 				printf("%s: unable to allocate Rx cluster\n",
    721        1.1   simonb 				    sc->sc_dev.dv_xname);
    722        1.1   simonb 				m_freem(m);
    723        1.1   simonb 				goto dropit;
    724        1.1   simonb 			}
    725        1.1   simonb 		}
    726        1.1   simonb 
    727        1.1   simonb 		m->m_data += 2;		/* align payload */
    728        1.1   simonb 		memcpy(mtod(m, caddr_t),
    729        1.1   simonb 		    sc->sc_rxbufs[i].buf_vaddr, len);
    730        1.1   simonb 		AUMAC_INIT_RXDESC(sc, i);
    731        1.1   simonb 
    732        1.1   simonb 		m->m_pkthdr.rcvif = ifp;
    733        1.1   simonb 		m->m_pkthdr.len = m->m_len = len;
    734        1.1   simonb 
    735        1.1   simonb #if NBPFILTER > 0
    736        1.1   simonb 		/* Pass this up to any BPF listeners. */
    737        1.1   simonb 		if (ifp->if_bpf)
    738        1.1   simonb 			bpf_mtap(ifp->if_bpf, m);
    739        1.1   simonb #endif /* NBPFILTER > 0 */
    740        1.1   simonb 
    741        1.1   simonb 		/* Pass it on. */
    742        1.1   simonb 		(*ifp->if_input)(ifp, m);
    743        1.1   simonb 		ifp->if_ipackets++;
    744        1.1   simonb 	}
    745        1.1   simonb 	if (pkts)
    746        1.1   simonb 		AUMAC_EVCNT_INCR(&sc->sc_ev_rxintr);
    747        1.1   simonb 	if (pkts == AUMAC_NRXDESC)
    748        1.1   simonb 		AUMAC_EVCNT_INCR(&sc->sc_ev_rxstall);
    749        1.1   simonb 
    750        1.1   simonb 	/* Update the receive pointer. */
    751        1.1   simonb 	sc->sc_rxptr = i;
    752  1.12.12.1     yamt 
    753  1.12.12.1     yamt 	return pkts;
    754        1.1   simonb }
    755        1.1   simonb 
    756        1.1   simonb /*
    757        1.1   simonb  * aumac_tick:
    758        1.1   simonb  *
    759        1.1   simonb  *	One second timer, used to tick the MII.
    760        1.1   simonb  */
    761        1.1   simonb static void
    762        1.1   simonb aumac_tick(void *arg)
    763        1.1   simonb {
    764        1.1   simonb 	struct aumac_softc *sc = arg;
    765        1.1   simonb 	int s;
    766        1.1   simonb 
    767        1.1   simonb 	s = splnet();
    768        1.1   simonb 	mii_tick(&sc->sc_mii);
    769        1.1   simonb 	splx(s);
    770        1.1   simonb 
    771        1.1   simonb 	callout_reset(&sc->sc_tick_ch, hz, aumac_tick, sc);
    772        1.1   simonb }
    773        1.1   simonb 
    774        1.1   simonb /*
    775        1.1   simonb  * aumac_init:		[ifnet interface function]
    776        1.1   simonb  *
    777        1.1   simonb  *	Initialize the interface.  Must be called at splnet().
    778        1.1   simonb  */
    779        1.1   simonb static int
    780        1.1   simonb aumac_init(struct ifnet *ifp)
    781        1.1   simonb {
    782        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    783        1.1   simonb 	int i, error = 0;
    784        1.1   simonb 
    785        1.1   simonb 	/* Cancel any pending I/O, reset MAC. */
    786        1.1   simonb 	aumac_stop(ifp, 0);
    787        1.1   simonb 
    788        1.1   simonb 	/* Set up the transmit ring. */
    789        1.1   simonb 	for (i = 0; i < AUMAC_NTXDESC; i++) {
    790        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    791        1.1   simonb 		    MACDMA_TX_STAT(i), 0);
    792        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    793        1.1   simonb 		    MACDMA_TX_LEN(i), 0);
    794        1.1   simonb 		bus_space_write_4(sc->sc_st, sc->sc_dma_sh,
    795        1.1   simonb 		    MACDMA_TX_ADDR(i), sc->sc_txbufs[i].buf_paddr);
    796        1.1   simonb 	}
    797        1.1   simonb 	sc->sc_txfree = AUMAC_NTXDESC;
    798        1.1   simonb 	sc->sc_txnext = TX_ADDR_CB(bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    799        1.1   simonb 	    MACDMA_TX_ADDR(0)));
    800        1.1   simonb 	sc->sc_txdirty = sc->sc_txnext;
    801        1.1   simonb 
    802        1.1   simonb 	/* Set up the receive ring. */
    803        1.1   simonb 	for (i = 0; i < AUMAC_NRXDESC; i++)
    804        1.1   simonb 			AUMAC_INIT_RXDESC(sc, i);
    805        1.1   simonb 	sc->sc_rxptr = RX_ADDR_CB(bus_space_read_4(sc->sc_st, sc->sc_dma_sh,
    806        1.1   simonb 	    MACDMA_RX_ADDR(0)));
    807        1.1   simonb 
    808        1.1   simonb 	/*
    809        1.1   simonb 	 * Power up the MAC.
    810        1.1   simonb 	 */
    811        1.1   simonb 	aumac_powerup(sc);
    812        1.1   simonb 
    813        1.1   simonb 	sc->sc_control |= CONTROL_DO | CONTROL_TE | CONTROL_RE;
    814        1.1   simonb #if _BYTE_ORDER == _BIG_ENDIAN
    815        1.1   simonb 	sc->sc_control |= CONTROL_EM;
    816        1.1   simonb #endif
    817        1.1   simonb 
    818        1.1   simonb 	/* Set the media. */
    819        1.1   simonb 	aumac_mediachange(ifp);
    820        1.1   simonb 
    821        1.1   simonb 	/*
    822        1.1   simonb 	 * Set the receive filter.  This will actually start the transmit
    823        1.1   simonb 	 * and receive processes.
    824        1.1   simonb 	 */
    825        1.1   simonb 	aumac_set_filter(sc);
    826        1.1   simonb 
    827        1.1   simonb 	/* Start the one second clock. */
    828        1.1   simonb 	callout_reset(&sc->sc_tick_ch, hz, aumac_tick, sc);
    829        1.1   simonb 
    830        1.1   simonb 	/* ...all done! */
    831        1.1   simonb 	ifp->if_flags |= IFF_RUNNING;
    832        1.1   simonb 	ifp->if_flags &= ~IFF_OACTIVE;
    833        1.1   simonb 
    834        1.1   simonb 	if (error)
    835        1.1   simonb 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
    836        1.1   simonb 	return (error);
    837        1.1   simonb }
    838        1.1   simonb 
    839        1.1   simonb /*
    840        1.1   simonb  * aumac_stop:		[ifnet interface function]
    841        1.1   simonb  *
    842        1.1   simonb  *	Stop transmission on the interface.
    843        1.1   simonb  */
    844        1.1   simonb static void
    845        1.1   simonb aumac_stop(struct ifnet *ifp, int disable)
    846        1.1   simonb {
    847        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    848        1.1   simonb 
    849        1.1   simonb 	/* Stop the one-second clock. */
    850        1.1   simonb 	callout_stop(&sc->sc_tick_ch);
    851        1.1   simonb 
    852        1.1   simonb 	/* Down the MII. */
    853        1.1   simonb 	mii_down(&sc->sc_mii);
    854        1.1   simonb 
    855        1.1   simonb 	/* Stop the transmit and receive processes. */
    856        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL, 0);
    857        1.1   simonb 
    858        1.1   simonb 	/* Power down/reset the MAC. */
    859        1.1   simonb 	aumac_powerdown(sc);
    860        1.1   simonb 
    861        1.1   simonb 	/* Mark the interface as down and cancel the watchdog timer. */
    862        1.1   simonb 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
    863        1.1   simonb 	ifp->if_timer = 0;
    864        1.1   simonb }
    865        1.1   simonb 
    866        1.1   simonb /*
    867        1.1   simonb  * aumac_powerdown:
    868        1.1   simonb  *
    869        1.1   simonb  *	Power down the MAC.
    870        1.1   simonb  */
    871        1.1   simonb static void
    872        1.1   simonb aumac_powerdown(struct aumac_softc *sc)
    873        1.1   simonb {
    874        1.1   simonb 
    875        1.1   simonb 	/* Disable the MAC clocks, and place the device in reset. */
    876        1.1   simonb 	// bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, MACEN_JP);
    877        1.1   simonb 
    878        1.1   simonb 	// delay(10000);
    879        1.1   simonb }
    880        1.1   simonb 
    881        1.1   simonb /*
    882        1.1   simonb  * aumac_powerup:
    883        1.1   simonb  *
    884        1.1   simonb  *	Bring the device out of reset.
    885        1.1   simonb  */
    886        1.1   simonb static void
    887        1.1   simonb aumac_powerup(struct aumac_softc *sc)
    888        1.1   simonb {
    889        1.1   simonb 
    890        1.1   simonb 	/* Enable clocks to the MAC. */
    891        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0, MACEN_JP|MACEN_CE);
    892        1.1   simonb 
    893        1.1   simonb 	/* Enable MAC, coherent transactions, pass only valid frames. */
    894        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_macen_sh, 0,
    895        1.1   simonb 	    MACEN_E2|MACEN_E1|MACEN_E0|MACEN_CE);
    896        1.1   simonb 
    897        1.1   simonb 	delay(20000);
    898        1.1   simonb }
    899        1.1   simonb 
    900        1.1   simonb /*
    901        1.1   simonb  * aumac_set_filter:
    902        1.1   simonb  *
    903        1.1   simonb  *	Set up the receive filter.
    904        1.1   simonb  */
    905        1.1   simonb static void
    906        1.1   simonb aumac_set_filter(struct aumac_softc *sc)
    907        1.1   simonb {
    908        1.1   simonb 	struct ethercom *ec = &sc->sc_ethercom;
    909        1.1   simonb 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
    910        1.1   simonb 	struct ether_multi *enm;
    911        1.1   simonb 	struct ether_multistep step;
    912        1.1   simonb 	const uint8_t *enaddr = LLADDR(ifp->if_sadl);
    913        1.1   simonb 	uint32_t mchash[2], crc;
    914        1.1   simonb 
    915        1.1   simonb 	sc->sc_control &= ~(CONTROL_PM | CONTROL_PR);
    916        1.1   simonb 
    917        1.1   simonb 	/* Stop the receiver. */
    918        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL,
    919        1.1   simonb 	    sc->sc_control & ~CONTROL_RE);
    920        1.1   simonb 
    921        1.1   simonb 	if (ifp->if_flags & IFF_PROMISC) {
    922        1.1   simonb 		sc->sc_control |= CONTROL_PR;
    923        1.1   simonb 		goto allmulti;
    924        1.1   simonb 	}
    925        1.1   simonb 
    926        1.1   simonb 	/* Set the station address. */
    927        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_ADDRHIGH,
    928        1.1   simonb 	    enaddr[4] | (enaddr[5] << 8));
    929        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_ADDRLOW,
    930        1.1   simonb 	    enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) |
    931        1.1   simonb 	    (enaddr[3] << 24));
    932        1.1   simonb 
    933        1.1   simonb 	sc->sc_control |= CONTROL_HP;
    934        1.1   simonb 
    935        1.1   simonb 	mchash[0] = mchash[1] = 0;
    936        1.1   simonb 
    937        1.1   simonb 	/*
    938        1.1   simonb 	 * Set up the multicast address filter by passing all multicast
    939        1.1   simonb 	 * addresses through a CRC generator, and then using the high
    940        1.1   simonb 	 * order 6 bits as an index into the 64-bit multicast hash table.
    941        1.1   simonb 	 * The high order bits select the word, while the rest of the bits
    942        1.1   simonb 	 * select the bit within the word.
    943        1.1   simonb 	 */
    944        1.1   simonb 	ETHER_FIRST_MULTI(step, ec, enm);
    945        1.1   simonb 	while (enm != NULL) {
    946        1.1   simonb 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
    947        1.1   simonb 			/*
    948        1.1   simonb 			 * We must listen to a range of multicast addresses.
    949        1.1   simonb 			 * For now, just accept all multicasts, rather than
    950        1.1   simonb 			 * trying to set only those filter bits needed to match
    951        1.1   simonb 			 * the range.  (At this time, the only use of address
    952        1.1   simonb 			 * ranges is for IP multicast routing, for which the
    953        1.1   simonb 			 * range is large enough to require all bits set.)
    954        1.1   simonb 			 */
    955        1.1   simonb 			goto allmulti;
    956        1.1   simonb 		}
    957        1.1   simonb 
    958        1.1   simonb 		crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
    959        1.1   simonb 
    960        1.1   simonb 		/* Just want the 6 most significant bits. */
    961        1.1   simonb 		crc >>= 26;
    962        1.1   simonb 
    963        1.1   simonb 		/* Set the corresponding bit in the filter. */
    964        1.1   simonb 		mchash[crc >> 5] |= 1U << (crc & 0x1f);
    965        1.1   simonb 
    966        1.1   simonb 		ETHER_NEXT_MULTI(step, enm);
    967        1.1   simonb 	}
    968        1.1   simonb 
    969        1.1   simonb 	ifp->if_flags &= ~IFF_ALLMULTI;
    970        1.1   simonb 
    971        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_HASHHIGH,
    972        1.1   simonb 	    mchash[1]);
    973        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_HASHLOW,
    974        1.1   simonb 	    mchash[0]);
    975        1.1   simonb 
    976        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL,
    977        1.1   simonb 	    sc->sc_control);
    978        1.1   simonb 	return;
    979        1.1   simonb 
    980        1.1   simonb  allmulti:
    981        1.1   simonb 	sc->sc_control |= CONTROL_PM;
    982        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL,
    983        1.1   simonb 	    sc->sc_control);
    984        1.1   simonb }
    985        1.1   simonb 
    986        1.1   simonb /*
    987        1.1   simonb  * aumac_mediastatus:	[ifmedia interface function]
    988        1.1   simonb  *
    989        1.1   simonb  *	Get the current interface media status.
    990        1.1   simonb  */
    991        1.1   simonb static void
    992        1.1   simonb aumac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
    993        1.1   simonb {
    994        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
    995        1.1   simonb 
    996        1.1   simonb 	mii_pollstat(&sc->sc_mii);
    997        1.1   simonb 	ifmr->ifm_status = sc->sc_mii.mii_media_status;
    998        1.1   simonb 	ifmr->ifm_active = sc->sc_mii.mii_media_active;
    999        1.1   simonb }
   1000        1.1   simonb 
   1001        1.1   simonb /*
   1002        1.1   simonb  * aumac_mediachange:	[ifmedia interface function]
   1003        1.1   simonb  *
   1004        1.1   simonb  *	Set hardware to newly selected media.
   1005        1.1   simonb  */
   1006        1.1   simonb static int
   1007        1.1   simonb aumac_mediachange(struct ifnet *ifp)
   1008        1.1   simonb {
   1009        1.1   simonb 	struct aumac_softc *sc = ifp->if_softc;
   1010        1.1   simonb 
   1011        1.1   simonb 	if (ifp->if_flags & IFF_UP)
   1012        1.1   simonb 		mii_mediachg(&sc->sc_mii);
   1013        1.1   simonb 	return (0);
   1014        1.1   simonb }
   1015        1.1   simonb 
   1016        1.1   simonb /*
   1017        1.1   simonb  * aumac_mii_wait:
   1018        1.1   simonb  *
   1019        1.1   simonb  *	Wait for the MII interface to not be busy.
   1020        1.1   simonb  */
   1021        1.1   simonb static int
   1022        1.1   simonb aumac_mii_wait(struct aumac_softc *sc, const char *msg)
   1023        1.1   simonb {
   1024        1.1   simonb 	int i;
   1025        1.1   simonb 
   1026        1.1   simonb 	for (i = 0; i < 10000; i++) {
   1027        1.1   simonb 		if ((bus_space_read_4(sc->sc_st, sc->sc_mac_sh,
   1028        1.1   simonb 		     MAC_MIICTRL) & MIICTRL_MB) == 0)
   1029        1.1   simonb 			return (0);
   1030        1.1   simonb 		delay(10);
   1031        1.1   simonb 	}
   1032        1.1   simonb 
   1033        1.1   simonb 	printf("%s: MII failed to %s\n", sc->sc_dev.dv_xname, msg);
   1034        1.1   simonb 	return (1);
   1035        1.1   simonb }
   1036        1.1   simonb 
   1037        1.1   simonb /*
   1038        1.1   simonb  * aumac_mii_readreg:	[mii interface function]
   1039        1.1   simonb  *
   1040        1.1   simonb  *	Read a PHY register on the MII.
   1041        1.1   simonb  */
   1042        1.1   simonb static int
   1043        1.1   simonb aumac_mii_readreg(struct device *self, int phy, int reg)
   1044        1.1   simonb {
   1045        1.1   simonb 	struct aumac_softc *sc = (void *) self;
   1046        1.1   simonb 
   1047        1.1   simonb 	if (aumac_mii_wait(sc, "become ready"))
   1048        1.1   simonb 		return (0);
   1049        1.1   simonb 
   1050        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIICTRL,
   1051        1.1   simonb 	    MIICTRL_PHYADDR(phy) | MIICTRL_MIIREG(reg));
   1052        1.1   simonb 
   1053        1.1   simonb 	if (aumac_mii_wait(sc, "complete"))
   1054        1.1   simonb 		return (0);
   1055        1.1   simonb 
   1056        1.1   simonb 	return (bus_space_read_4(sc->sc_st, sc->sc_mac_sh, MAC_MIIDATA) &
   1057        1.1   simonb 	    MIIDATA_MASK);
   1058        1.1   simonb }
   1059        1.1   simonb 
   1060        1.1   simonb /*
   1061        1.1   simonb  * aumac_mii_writereg:	[mii interface function]
   1062        1.1   simonb  *
   1063        1.1   simonb  *	Write a PHY register on the MII.
   1064        1.1   simonb  */
   1065        1.1   simonb static void
   1066        1.1   simonb aumac_mii_writereg(struct device *self, int phy, int reg, int val)
   1067        1.1   simonb {
   1068        1.1   simonb 	struct aumac_softc *sc = (void *) self;
   1069        1.1   simonb 
   1070        1.1   simonb 	if (aumac_mii_wait(sc, "become ready"))
   1071        1.1   simonb 		return;
   1072        1.1   simonb 
   1073        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIIDATA, val);
   1074        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_MIICTRL,
   1075        1.1   simonb 	    MIICTRL_PHYADDR(phy) | MIICTRL_MIIREG(reg) | MIICTRL_MW);
   1076        1.1   simonb 
   1077        1.1   simonb 	(void) aumac_mii_wait(sc, "complete");
   1078        1.1   simonb }
   1079        1.1   simonb 
   1080        1.1   simonb /*
   1081        1.1   simonb  * aumac_mii_statchg:	[mii interface function]
   1082        1.1   simonb  *
   1083        1.1   simonb  *	Callback from MII layer when media changes.
   1084        1.1   simonb  */
   1085        1.1   simonb static void
   1086        1.1   simonb aumac_mii_statchg(struct device *self)
   1087        1.1   simonb {
   1088        1.1   simonb 	struct aumac_softc *sc = (void *) self;
   1089        1.1   simonb 
   1090        1.1   simonb 	if ((sc->sc_mii.mii_media_active & IFM_FDX) != 0)
   1091        1.1   simonb 		sc->sc_control |= CONTROL_F;
   1092        1.1   simonb 	else
   1093        1.1   simonb 		sc->sc_control &= ~CONTROL_F;
   1094        1.1   simonb 
   1095        1.1   simonb 	bus_space_write_4(sc->sc_st, sc->sc_mac_sh, MAC_CONTROL,
   1096        1.1   simonb 	    sc->sc_control);
   1097        1.1   simonb }
   1098