Home | History | Annotate | Line # | Download | only in dev
if_temac.c revision 1.12.14.1
      1  1.12.14.1  pgoyette /* 	$NetBSD: if_temac.c,v 1.12.14.1 2019/01/26 22:00:02 pgoyette Exp $ */
      2        1.1     freza 
      3        1.1     freza /*
      4        1.1     freza  * Copyright (c) 2006 Jachym Holecek
      5        1.1     freza  * All rights reserved.
      6        1.1     freza  *
      7        1.1     freza  * Written for DFC Design, s.r.o.
      8        1.1     freza  *
      9        1.1     freza  * Redistribution and use in source and binary forms, with or without
     10        1.1     freza  * modification, are permitted provided that the following conditions
     11        1.1     freza  * are met:
     12        1.1     freza  *
     13        1.1     freza  * 1. Redistributions of source code must retain the above copyright
     14        1.1     freza  *    notice, this list of conditions and the following disclaimer.
     15        1.1     freza  *
     16        1.1     freza  * 2. Redistributions in binary form must reproduce the above copyright
     17        1.1     freza  *    notice, this list of conditions and the following disclaimer in the
     18        1.1     freza  *    documentation and/or other materials provided with the distribution.
     19        1.1     freza  *
     20        1.1     freza  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21        1.1     freza  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22        1.1     freza  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23        1.1     freza  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24        1.1     freza  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25        1.1     freza  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26        1.1     freza  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27        1.1     freza  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28        1.1     freza  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29        1.1     freza  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30        1.1     freza  */
     31        1.1     freza 
     32        1.1     freza /*
     33        1.1     freza  * Driver for Xilinx LocalLink TEMAC as wired on the GSRD platform.
     34        1.1     freza  *
     35        1.1     freza  * TODO:
     36        1.1     freza  * 	- Optimize
     37        1.1     freza  * 	- Checksum offload
     38        1.1     freza  * 	- Address filters
     39        1.1     freza  * 	- Support jumbo frames
     40        1.1     freza  */
     41        1.1     freza 
     42        1.1     freza #include <sys/cdefs.h>
     43  1.12.14.1  pgoyette __KERNEL_RCSID(0, "$NetBSD: if_temac.c,v 1.12.14.1 2019/01/26 22:00:02 pgoyette Exp $");
     44        1.1     freza 
     45        1.1     freza 
     46        1.1     freza #include <sys/param.h>
     47        1.1     freza #include <sys/systm.h>
     48        1.1     freza #include <sys/mbuf.h>
     49        1.1     freza #include <sys/kernel.h>
     50        1.1     freza #include <sys/socket.h>
     51        1.1     freza #include <sys/ioctl.h>
     52        1.1     freza #include <sys/device.h>
     53        1.8      matt #include <sys/bus.h>
     54        1.8      matt #include <sys/cpu.h>
     55        1.1     freza 
     56        1.1     freza #include <uvm/uvm_extern.h>
     57        1.1     freza 
     58        1.1     freza #include <net/if.h>
     59        1.1     freza #include <net/if_dl.h>
     60        1.1     freza #include <net/if_media.h>
     61        1.1     freza #include <net/if_ether.h>
     62        1.1     freza 
     63        1.1     freza #include <net/bpf.h>
     64        1.1     freza 
     65        1.8      matt #include <powerpc/ibm4xx/cpu.h>
     66        1.1     freza 
     67        1.1     freza #include <evbppc/virtex/idcr.h>
     68        1.1     freza #include <evbppc/virtex/dev/xcvbusvar.h>
     69        1.1     freza #include <evbppc/virtex/dev/cdmacreg.h>
     70        1.1     freza #include <evbppc/virtex/dev/temacreg.h>
     71        1.1     freza #include <evbppc/virtex/dev/temacvar.h>
     72        1.1     freza 
     73        1.1     freza #include <dev/mii/miivar.h>
     74        1.1     freza 
     75        1.1     freza 
     76        1.1     freza /* This is outside of TEMAC's DCR window, we have to hardcode it... */
     77        1.1     freza #define DCR_ETH_BASE 		0x0030
     78        1.1     freza 
     79        1.1     freza #define	TEMAC_REGDEBUG 		0
     80        1.1     freza #define	TEMAC_RXDEBUG 		0
     81        1.1     freza #define	TEMAC_TXDEBUG 		0
     82        1.1     freza 
     83        1.1     freza #if TEMAC_RXDEBUG > 0 || TEMAC_TXDEBUG > 0
     84        1.1     freza #define	TEMAC_DEBUG 		1
     85        1.1     freza #else
     86        1.1     freza #define	TEMAC_DEBUG 		0
     87        1.1     freza #endif
     88        1.1     freza 
     89        1.1     freza #if TEMAC_REGDEBUG > 0
     90        1.1     freza #define	TRACEREG(arg) 		printf arg
     91        1.1     freza #else
     92        1.1     freza #define	TRACEREG(arg) 		/* nop */
     93        1.1     freza #endif
     94        1.1     freza 
     95        1.1     freza /* DMA control chains take up one (16KB) page. */
     96        1.1     freza #define TEMAC_NTXDESC 		256
     97        1.1     freza #define TEMAC_NRXDESC 		256
     98        1.1     freza 
     99        1.1     freza #define TEMAC_TXQLEN 		64 	/* Software Tx queue length */
    100        1.1     freza #define TEMAC_NTXSEG 		16 	/* Maximum Tx segments per packet */
    101        1.1     freza 
    102        1.1     freza #define TEMAC_NRXSEG 		1 	/* Maximum Rx segments per packet */
    103        1.1     freza #define TEMAC_RXPERIOD 		1 	/* Interrupt every N descriptors. */
    104        1.1     freza #define TEMAC_RXTIMO_HZ 	100 	/* Rx reaper frequency */
    105        1.1     freza 
    106        1.1     freza /* Next Tx descriptor and descriptor's offset WRT sc_cdaddr. */
    107        1.1     freza #define TEMAC_TXSINC(n, i) 	(((n) + TEMAC_TXQLEN + (i)) % TEMAC_TXQLEN)
    108        1.1     freza #define TEMAC_TXINC(n, i) 	(((n) + TEMAC_NTXDESC + (i)) % TEMAC_NTXDESC)
    109        1.1     freza 
    110        1.1     freza #define TEMAC_TXSNEXT(n) 	TEMAC_TXSINC((n), 1)
    111        1.1     freza #define TEMAC_TXNEXT(n) 	TEMAC_TXINC((n), 1)
    112        1.1     freza #define TEMAC_TXDOFF(n) 	(offsetof(struct temac_control, cd_txdesc) + \
    113        1.1     freza 				 (n) * sizeof(struct cdmac_descr))
    114        1.1     freza 
    115        1.1     freza /* Next Rx descriptor and descriptor's offset WRT sc_cdaddr. */
    116        1.1     freza #define TEMAC_RXINC(n, i) 	(((n) + TEMAC_NRXDESC + (i)) % TEMAC_NRXDESC)
    117        1.1     freza #define TEMAC_RXNEXT(n) 	TEMAC_RXINC((n), 1)
    118        1.1     freza #define TEMAC_RXDOFF(n) 	(offsetof(struct temac_control, cd_rxdesc) + \
    119        1.1     freza 				 (n) * sizeof(struct cdmac_descr))
    120        1.1     freza #define TEMAC_ISINTR(i) 	(((i) % TEMAC_RXPERIOD) == 0)
    121        1.1     freza #define TEMAC_ISLAST(i) 	((i) == (TEMAC_NRXDESC - 1))
    122        1.1     freza 
    123        1.1     freza 
    124        1.1     freza struct temac_control {
    125        1.1     freza 	struct cdmac_descr 	cd_txdesc[TEMAC_NTXDESC];
    126        1.1     freza 	struct cdmac_descr 	cd_rxdesc[TEMAC_NRXDESC];
    127        1.1     freza };
    128        1.1     freza 
    129        1.1     freza struct temac_txsoft {
    130        1.1     freza 	bus_dmamap_t 		txs_dmap;
    131        1.1     freza 	struct mbuf 		*txs_mbuf;
    132        1.1     freza 	int 			txs_last;
    133        1.1     freza };
    134        1.1     freza 
    135        1.1     freza struct temac_rxsoft {
    136        1.1     freza 	bus_dmamap_t 		rxs_dmap;
    137        1.1     freza 	struct mbuf 		*rxs_mbuf;
    138        1.1     freza };
    139        1.1     freza 
    140        1.1     freza struct temac_softc {
    141        1.8      matt 	device_t 		sc_dev;
    142        1.1     freza 	struct ethercom 	sc_ec;
    143        1.1     freza #define sc_if 			sc_ec.ec_if
    144        1.1     freza 
    145        1.1     freza 	/* Peripheral registers */
    146        1.1     freza 	bus_space_tag_t 	sc_iot;
    147        1.1     freza 	bus_space_handle_t 	sc_ioh;
    148        1.1     freza 
    149        1.1     freza 	/* CDMAC channel registers */
    150        1.1     freza 	bus_space_tag_t 	sc_dma_rxt;
    151        1.1     freza 	bus_space_handle_t 	sc_dma_rxh; 	/* Rx channel */
    152        1.1     freza 	bus_space_handle_t 	sc_dma_rsh; 	/* Rx status */
    153        1.1     freza 
    154        1.1     freza 	bus_space_tag_t 	sc_dma_txt;
    155        1.1     freza 	bus_space_handle_t 	sc_dma_txh; 	/* Tx channel */
    156        1.1     freza 	bus_space_handle_t 	sc_dma_tsh; 	/* Tx status */
    157        1.1     freza 
    158        1.1     freza 	struct temac_txsoft 	sc_txsoft[TEMAC_TXQLEN];
    159        1.1     freza 	struct temac_rxsoft 	sc_rxsoft[TEMAC_NRXDESC];
    160        1.1     freza 
    161        1.1     freza 	struct callout 		sc_rx_timo;
    162        1.1     freza 	struct callout 		sc_mii_tick;
    163        1.1     freza 	struct mii_data 	sc_mii;
    164        1.1     freza 
    165        1.1     freza 	bus_dmamap_t 		sc_control_dmap;
    166        1.1     freza #define sc_cdaddr 		sc_control_dmap->dm_segs[0].ds_addr
    167        1.1     freza 
    168        1.1     freza 	struct temac_control 	*sc_control_data;
    169        1.1     freza #define sc_rxdescs 		sc_control_data->cd_rxdesc
    170        1.1     freza #define sc_txdescs 		sc_control_data->cd_txdesc
    171        1.1     freza 
    172        1.1     freza 	int 			sc_txbusy;
    173        1.1     freza 
    174        1.1     freza 	int 			sc_txfree;
    175        1.1     freza 	int 			sc_txcur;
    176        1.1     freza 	int 			sc_txreap;
    177        1.1     freza 
    178        1.1     freza 	int 			sc_rxreap;
    179        1.1     freza 
    180        1.1     freza 	int 			sc_txsfree;
    181        1.1     freza 	int 			sc_txscur;
    182        1.1     freza 	int 			sc_txsreap;
    183        1.1     freza 
    184        1.1     freza 	int 			sc_dead; 	/* Rx/Tx DMA error (fatal) */
    185        1.1     freza 	int 			sc_rx_drained;
    186        1.1     freza 
    187        1.1     freza 	int 			sc_rx_chan;
    188        1.1     freza 	int 			sc_tx_chan;
    189        1.1     freza 
    190        1.1     freza 	void 			*sc_sdhook;
    191        1.1     freza 	void 			*sc_rx_ih;
    192        1.1     freza 	void 			*sc_tx_ih;
    193        1.1     freza 
    194        1.1     freza 	bus_dma_tag_t 		sc_dmat;
    195        1.1     freza };
    196        1.1     freza 
    197        1.1     freza /* Device interface. */
    198        1.8      matt static void 	temac_attach(device_t, device_t, void *);
    199        1.1     freza 
    200        1.1     freza /* Ifnet interface. */
    201        1.1     freza static int 	temac_init(struct ifnet *);
    202        1.2  christos static int 	temac_ioctl(struct ifnet *, u_long, void *);
    203        1.1     freza static void 	temac_start(struct ifnet *);
    204        1.1     freza static void 	temac_stop(struct ifnet *, int);
    205        1.1     freza 
    206        1.1     freza /* Media management. */
    207  1.12.14.1  pgoyette static int	temac_mii_readreg(device_t, int, int, uint16_t *);
    208        1.9      matt static void	temac_mii_statchg(struct ifnet *);
    209        1.1     freza static void	temac_mii_tick(void *);
    210  1.12.14.1  pgoyette static int	temac_mii_writereg(device_t, int, int, uint16_t);
    211        1.1     freza 
    212        1.1     freza /* Indirect hooks. */
    213        1.1     freza static void 	temac_shutdown(void *);
    214        1.1     freza static void 	temac_rx_intr(void *);
    215        1.1     freza static void 	temac_tx_intr(void *);
    216        1.1     freza 
    217        1.1     freza /* Tools. */
    218        1.1     freza static inline void 	temac_rxcdsync(struct temac_softc *, int, int, int);
    219        1.1     freza static inline void 	temac_txcdsync(struct temac_softc *, int, int, int);
    220        1.1     freza static void 		temac_txreap(struct temac_softc *);
    221        1.1     freza static void 		temac_rxreap(struct temac_softc *);
    222        1.1     freza static int 		temac_rxalloc(struct temac_softc *, int, int);
    223        1.1     freza static void 		temac_rxtimo(void *);
    224        1.1     freza static void 		temac_rxdrain(struct temac_softc *);
    225        1.1     freza static void 		temac_reset(struct temac_softc *);
    226        1.1     freza static void 		temac_txkick(struct temac_softc *);
    227        1.1     freza 
    228        1.1     freza /* Register access. */
    229        1.1     freza static inline void 	gmi_write_8(uint32_t, uint32_t, uint32_t);
    230        1.1     freza static inline void 	gmi_write_4(uint32_t, uint32_t);
    231        1.1     freza static inline void 	gmi_read_8(uint32_t, uint32_t *, uint32_t *);
    232        1.1     freza static inline uint32_t 	gmi_read_4(uint32_t);
    233        1.1     freza static inline void 	hif_wait_stat(uint32_t);
    234        1.1     freza 
    235        1.1     freza #define cdmac_rx_stat(sc) \
    236        1.1     freza     bus_space_read_4((sc)->sc_dma_rxt, (sc)->sc_dma_rsh, 0 /* XXX hack */)
    237        1.1     freza 
    238        1.1     freza #define cdmac_rx_reset(sc) \
    239        1.1     freza     bus_space_write_4((sc)->sc_dma_rxt, (sc)->sc_dma_rsh, 0, CDMAC_STAT_RESET)
    240        1.1     freza 
    241        1.1     freza #define cdmac_rx_start(sc, val) \
    242        1.1     freza     bus_space_write_4((sc)->sc_dma_rxt, (sc)->sc_dma_rxh, CDMAC_CURDESC, (val))
    243        1.1     freza 
    244        1.1     freza #define cdmac_tx_stat(sc) \
    245        1.1     freza     bus_space_read_4((sc)->sc_dma_txt, (sc)->sc_dma_tsh, 0 /* XXX hack */)
    246        1.1     freza 
    247        1.1     freza #define cdmac_tx_reset(sc) \
    248        1.1     freza     bus_space_write_4((sc)->sc_dma_txt, (sc)->sc_dma_tsh, 0, CDMAC_STAT_RESET)
    249        1.1     freza 
    250        1.1     freza #define cdmac_tx_start(sc, val) \
    251        1.1     freza     bus_space_write_4((sc)->sc_dma_txt, (sc)->sc_dma_txh, CDMAC_CURDESC, (val))
    252        1.1     freza 
    253        1.1     freza 
    254        1.8      matt CFATTACH_DECL_NEW(temac, sizeof(struct temac_softc),
    255        1.1     freza     xcvbus_child_match, temac_attach, NULL, NULL);
    256        1.1     freza 
    257        1.1     freza 
    258        1.1     freza /*
    259        1.1     freza  * Private bus utilities.
    260        1.1     freza  */
    261  1.12.14.1  pgoyette static inline int
    262        1.1     freza hif_wait_stat(uint32_t mask)
    263        1.1     freza {
    264        1.1     freza 	int 			i = 0;
    265  1.12.14.1  pgoyette 	int			rv = 0;
    266        1.1     freza 
    267        1.1     freza 	while (mask != (mfidcr(IDCR_HIF_STAT) & mask)) {
    268        1.1     freza 		if (i++ > 100) {
    269        1.1     freza 			printf("%s: timeout waiting for 0x%08x\n",
    270        1.1     freza 			    __func__, mask);
    271  1.12.14.1  pgoyette 			rv = ETIMEDOUT;
    272        1.1     freza 			break;
    273        1.1     freza 		}
    274        1.1     freza 		delay(5);
    275        1.1     freza 	}
    276        1.1     freza 
    277        1.1     freza 	TRACEREG(("%s: stat %#08x loops %d\n", __func__, mask, i));
    278  1.12.14.1  pgoyette 	return rv;
    279        1.1     freza }
    280        1.1     freza 
    281        1.1     freza static inline void
    282        1.1     freza gmi_write_4(uint32_t addr, uint32_t lo)
    283        1.1     freza {
    284        1.1     freza 	mtidcr(IDCR_HIF_ARG0, lo);
    285        1.1     freza 	mtidcr(IDCR_HIF_CTRL, (addr & HIF_CTRL_GMIADDR) | HIF_CTRL_WRITE);
    286        1.1     freza 	hif_wait_stat(HIF_STAT_GMIWR);
    287        1.1     freza 
    288        1.1     freza 	TRACEREG(("%s: %#08x <- %#08x\n", __func__, addr, lo));
    289        1.1     freza }
    290        1.1     freza 
    291        1.1     freza static inline void
    292        1.1     freza gmi_write_8(uint32_t addr, uint32_t lo, uint32_t hi)
    293        1.1     freza {
    294        1.1     freza 	mtidcr(IDCR_HIF_ARG1, hi);
    295        1.1     freza 	gmi_write_4(addr, lo);
    296        1.1     freza }
    297        1.1     freza 
    298        1.1     freza static inline void
    299        1.1     freza gmi_read_8(uint32_t addr, uint32_t *lo, uint32_t *hi)
    300        1.1     freza {
    301        1.1     freza 	*lo = gmi_read_4(addr);
    302        1.1     freza 	*hi = mfidcr(IDCR_HIF_ARG1);
    303        1.1     freza }
    304        1.1     freza 
    305        1.1     freza static inline uint32_t
    306        1.1     freza gmi_read_4(uint32_t addr)
    307        1.1     freza {
    308        1.1     freza 	uint32_t 		res;
    309        1.1     freza 
    310        1.1     freza 	mtidcr(IDCR_HIF_CTRL, addr & HIF_CTRL_GMIADDR);
    311        1.1     freza 	hif_wait_stat(HIF_STAT_GMIRR);
    312        1.1     freza 
    313        1.1     freza 	res = mfidcr(IDCR_HIF_ARG0);
    314        1.1     freza 	TRACEREG(("%s:  %#08x -> %#08x\n", __func__, addr, res));
    315        1.1     freza 	return (res);
    316        1.1     freza }
    317        1.1     freza 
    318        1.1     freza /*
    319        1.1     freza  * Generic device.
    320        1.1     freza  */
    321        1.1     freza static void
    322        1.8      matt temac_attach(device_t parent, device_t self, void *aux)
    323        1.1     freza {
    324        1.1     freza 	struct xcvbus_attach_args *vaa = aux;
    325        1.1     freza 	struct ll_dmac 		*rx = vaa->vaa_rx_dmac;
    326        1.1     freza 	struct ll_dmac 		*tx = vaa->vaa_tx_dmac;
    327        1.8      matt 	struct temac_softc 	*sc = device_private(self);
    328        1.1     freza 	struct ifnet 		*ifp = &sc->sc_if;
    329        1.1     freza 	struct mii_data 	*mii = &sc->sc_mii;
    330        1.1     freza 	uint8_t 		enaddr[ETHER_ADDR_LEN];
    331        1.1     freza 	bus_dma_segment_t 	seg;
    332        1.1     freza 	int 			error, nseg, i;
    333        1.8      matt 	const char * const xname = device_xname(self);
    334        1.1     freza 
    335        1.8      matt 	aprint_normal(": TEMAC\n"); 	/* XXX will be LL_TEMAC, PLB_TEMAC */
    336        1.1     freza 
    337        1.1     freza 	KASSERT(rx);
    338        1.1     freza 	KASSERT(tx);
    339        1.1     freza 
    340        1.8      matt 	sc->sc_dev = self;
    341        1.1     freza 	sc->sc_dmat = vaa->vaa_dmat;
    342        1.1     freza 	sc->sc_dead = 0;
    343        1.1     freza 	sc->sc_rx_drained = 1;
    344        1.1     freza 	sc->sc_txbusy = 0;
    345        1.1     freza 	sc->sc_iot = vaa->vaa_iot;
    346        1.1     freza 	sc->sc_dma_rxt = rx->dmac_iot;
    347        1.1     freza 	sc->sc_dma_txt = tx->dmac_iot;
    348        1.1     freza 
    349        1.1     freza 	/*
    350        1.1     freza 	 * Map HIF and receive/transmit dmac registers.
    351        1.1     freza 	 */
    352        1.1     freza 	if ((error = bus_space_map(vaa->vaa_iot, vaa->vaa_addr, TEMAC_SIZE, 0,
    353        1.1     freza 	    &sc->sc_ioh)) != 0) {
    354        1.8      matt 		aprint_error_dev(self, "could not map registers\n");
    355        1.1     freza 		goto fail_0;
    356        1.1     freza 	}
    357        1.1     freza 
    358        1.1     freza 	if ((error = bus_space_map(sc->sc_dma_rxt, rx->dmac_ctrl_addr,
    359        1.1     freza 	    CDMAC_CTRL_SIZE, 0, &sc->sc_dma_rxh)) != 0) {
    360        1.8      matt 		aprint_error_dev(self, "could not map Rx control registers\n");
    361        1.1     freza 		goto fail_0;
    362        1.1     freza 	}
    363        1.1     freza 	if ((error = bus_space_map(sc->sc_dma_rxt, rx->dmac_stat_addr,
    364        1.1     freza 	    CDMAC_STAT_SIZE, 0, &sc->sc_dma_rsh)) != 0) {
    365        1.8      matt 		aprint_error_dev(self, "could not map Rx status register\n");
    366        1.1     freza 		goto fail_0;
    367        1.1     freza 	}
    368        1.1     freza 
    369        1.1     freza 	if ((error = bus_space_map(sc->sc_dma_txt, tx->dmac_ctrl_addr,
    370        1.1     freza 	    CDMAC_CTRL_SIZE, 0, &sc->sc_dma_txh)) != 0) {
    371        1.8      matt 		aprint_error_dev(self, "could not map Tx control registers\n");
    372        1.1     freza 		goto fail_0;
    373        1.1     freza 	}
    374        1.1     freza 	if ((error = bus_space_map(sc->sc_dma_txt, tx->dmac_stat_addr,
    375        1.1     freza 	    CDMAC_STAT_SIZE, 0, &sc->sc_dma_tsh)) != 0) {
    376        1.8      matt 		aprint_error_dev(self, "could not map Tx status register\n");
    377        1.1     freza 		goto fail_0;
    378        1.1     freza 	}
    379        1.1     freza 
    380        1.1     freza 	/*
    381        1.1     freza 	 * Allocate and initialize DMA control chains.
    382        1.1     freza 	 */
    383        1.1     freza 	if ((error = bus_dmamem_alloc(sc->sc_dmat,
    384        1.1     freza 	    sizeof(struct temac_control), 8, 0, &seg, 1, &nseg, 0)) != 0) {
    385        1.8      matt 	    	aprint_error_dev(self, "could not allocate control data\n");
    386        1.1     freza 		goto fail_0;
    387        1.1     freza 	}
    388        1.1     freza 
    389        1.1     freza 	if ((error = bus_dmamem_map(sc->sc_dmat, &seg, nseg,
    390        1.1     freza 	    sizeof(struct temac_control),
    391        1.2  christos 	    (void **)&sc->sc_control_data, BUS_DMA_COHERENT)) != 0) {
    392        1.8      matt 	    	aprint_error_dev(self, "could not map control data\n");
    393        1.1     freza 		goto fail_1;
    394        1.1     freza 	}
    395        1.1     freza 
    396        1.1     freza 	if ((error = bus_dmamap_create(sc->sc_dmat,
    397        1.1     freza 	    sizeof(struct temac_control), 1,
    398        1.1     freza 	    sizeof(struct temac_control), 0, 0, &sc->sc_control_dmap)) != 0) {
    399        1.8      matt 	    	aprint_error_dev(self,
    400        1.8      matt 		    "could not create control data DMA map\n");
    401        1.1     freza 		goto fail_2;
    402        1.1     freza 	}
    403        1.1     freza 
    404        1.1     freza 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_control_dmap,
    405        1.1     freza 	    sc->sc_control_data, sizeof(struct temac_control), NULL, 0)) != 0) {
    406        1.8      matt 	    	aprint_error_dev(self, "could not load control data DMA map\n");
    407        1.1     freza 		goto fail_3;
    408        1.1     freza 	}
    409        1.1     freza 
    410        1.1     freza 	/*
    411        1.1     freza 	 * Link descriptor chains.
    412        1.1     freza 	 */
    413        1.1     freza 	memset(sc->sc_control_data, 0, sizeof(struct temac_control));
    414        1.1     freza 
    415        1.1     freza 	for (i = 0; i < TEMAC_NTXDESC; i++) {
    416        1.1     freza 		sc->sc_txdescs[i].desc_next = sc->sc_cdaddr +
    417        1.1     freza 		    TEMAC_TXDOFF(TEMAC_TXNEXT(i));
    418        1.1     freza 		sc->sc_txdescs[i].desc_stat = CDMAC_STAT_DONE;
    419        1.1     freza 	}
    420        1.1     freza 	for (i = 0; i < TEMAC_NRXDESC; i++) {
    421        1.1     freza 		sc->sc_rxdescs[i].desc_next = sc->sc_cdaddr +
    422        1.1     freza 		    TEMAC_RXDOFF(TEMAC_RXNEXT(i));
    423        1.1     freza 		sc->sc_txdescs[i].desc_stat = CDMAC_STAT_DONE;
    424        1.1     freza 	}
    425        1.1     freza 
    426        1.1     freza 	bus_dmamap_sync(sc->sc_dmat, sc->sc_control_dmap, 0,
    427        1.1     freza 	    sizeof(struct temac_control),
    428        1.1     freza 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    429        1.1     freza 
    430        1.1     freza 	/*
    431        1.1     freza 	 * Initialize software state for transmit/receive jobs.
    432        1.1     freza 	 */
    433        1.1     freza 	for (i = 0; i < TEMAC_TXQLEN; i++) {
    434        1.1     freza 		if ((error = bus_dmamap_create(sc->sc_dmat,
    435        1.1     freza 		    ETHER_MAX_LEN_JUMBO, TEMAC_NTXSEG, ETHER_MAX_LEN_JUMBO,
    436        1.1     freza 		    0, 0, &sc->sc_txsoft[i].txs_dmap)) != 0) {
    437        1.8      matt 		    	aprint_error_dev(self,
    438        1.8      matt 			    "could not create Tx DMA map %d\n",
    439        1.8      matt 		    	    i);
    440        1.1     freza 			goto fail_4;
    441        1.1     freza 		}
    442        1.1     freza 		sc->sc_txsoft[i].txs_mbuf = NULL;
    443        1.1     freza 		sc->sc_txsoft[i].txs_last = 0;
    444        1.1     freza 	}
    445        1.1     freza 
    446        1.1     freza 	for (i = 0; i < TEMAC_NRXDESC; i++) {
    447        1.1     freza 		if ((error = bus_dmamap_create(sc->sc_dmat,
    448        1.1     freza 		    MCLBYTES, TEMAC_NRXSEG, MCLBYTES, 0, 0,
    449        1.1     freza 		    &sc->sc_rxsoft[i].rxs_dmap)) != 0) {
    450        1.8      matt 		    	aprint_error_dev(self,
    451        1.8      matt 			    "could not create Rx DMA map %d\n", i);
    452        1.1     freza 			goto fail_5;
    453        1.1     freza 		}
    454        1.1     freza 		sc->sc_rxsoft[i].rxs_mbuf = NULL;
    455        1.1     freza 	}
    456        1.1     freza 
    457        1.1     freza 	/*
    458        1.1     freza 	 * Setup transfer interrupt handlers.
    459        1.1     freza 	 */
    460        1.1     freza 	error = ENOMEM;
    461        1.1     freza 
    462        1.1     freza 	sc->sc_rx_ih = ll_dmac_intr_establish(rx->dmac_chan,
    463        1.1     freza 	    temac_rx_intr, sc);
    464        1.1     freza 	if (sc->sc_rx_ih == NULL) {
    465        1.8      matt 		aprint_error_dev(self, "could not establish Rx interrupt\n");
    466        1.1     freza 		goto fail_5;
    467        1.1     freza 	}
    468        1.1     freza 
    469        1.1     freza 	sc->sc_tx_ih = ll_dmac_intr_establish(tx->dmac_chan,
    470        1.1     freza 	    temac_tx_intr, sc);
    471        1.1     freza 	if (sc->sc_tx_ih == NULL) {
    472        1.8      matt 		aprint_error_dev(self, "could not establish Tx interrupt\n");
    473        1.1     freza 		goto fail_6;
    474        1.1     freza 	}
    475        1.1     freza 
    476        1.1     freza 	/* XXXFreza: faked, should read unicast address filter. */
    477        1.1     freza 	enaddr[0] = 0x00;
    478        1.1     freza 	enaddr[1] = 0x11;
    479        1.1     freza 	enaddr[2] = 0x17;
    480        1.1     freza 	enaddr[3] = 0xff;
    481        1.1     freza 	enaddr[4] = 0xff;
    482        1.1     freza 	enaddr[5] = 0x01;
    483        1.1     freza 
    484        1.1     freza 	/*
    485        1.1     freza 	 * Initialize the TEMAC.
    486        1.1     freza 	 */
    487        1.1     freza 	temac_reset(sc);
    488        1.1     freza 
    489        1.1     freza 	/* Configure MDIO link. */
    490        1.1     freza 	gmi_write_4(TEMAC_GMI_MGMTCF, GMI_MGMT_CLKDIV_100MHz | GMI_MGMT_MDIO);
    491        1.1     freza 
    492        1.1     freza 	/* Initialize PHY. */
    493        1.1     freza 	mii->mii_ifp = ifp;
    494        1.1     freza 	mii->mii_readreg = temac_mii_readreg;
    495        1.1     freza 	mii->mii_writereg = temac_mii_writereg;
    496        1.1     freza 	mii->mii_statchg = temac_mii_statchg;
    497        1.3    dyoung 	sc->sc_ec.ec_mii = mii;
    498        1.3    dyoung 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
    499        1.1     freza 
    500        1.8      matt 	mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
    501        1.1     freza 	    MII_OFFSET_ANY, 0);
    502        1.1     freza 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
    503        1.1     freza 		ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
    504        1.1     freza 		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_NONE);
    505        1.1     freza 	} else {
    506        1.1     freza 		ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
    507        1.1     freza 	}
    508        1.1     freza 
    509        1.1     freza 	/* Hold PHY in reset. */
    510        1.1     freza 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TEMAC_RESET, TEMAC_RESET_PHY);
    511        1.1     freza 
    512        1.1     freza 	/* Reset EMAC. */
    513        1.1     freza 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TEMAC_RESET,
    514        1.1     freza 	    TEMAC_RESET_EMAC);
    515        1.1     freza 	delay(10000);
    516        1.1     freza 
    517        1.1     freza 	/* Reset peripheral, awakes PHY and EMAC. */
    518        1.1     freza 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, TEMAC_RESET,
    519        1.1     freza 	    TEMAC_RESET_PERIPH);
    520        1.1     freza 	delay(40000);
    521        1.1     freza 
    522        1.1     freza 	/* (Re-)Configure MDIO link. */
    523        1.1     freza 	gmi_write_4(TEMAC_GMI_MGMTCF, GMI_MGMT_CLKDIV_100MHz | GMI_MGMT_MDIO);
    524        1.1     freza 
    525        1.1     freza 	/*
    526        1.1     freza 	 * Hook up with network stack.
    527        1.1     freza 	 */
    528        1.8      matt 	strcpy(ifp->if_xname, xname);
    529        1.1     freza 	ifp->if_softc = sc;
    530        1.1     freza 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    531        1.1     freza 	ifp->if_ioctl = temac_ioctl;
    532        1.1     freza 	ifp->if_start = temac_start;
    533        1.1     freza 	ifp->if_init = temac_init;
    534        1.1     freza 	ifp->if_stop = temac_stop;
    535        1.1     freza 	ifp->if_watchdog = NULL;
    536        1.1     freza 	IFQ_SET_READY(&ifp->if_snd);
    537        1.1     freza 	IFQ_SET_MAXLEN(&ifp->if_snd, TEMAC_TXQLEN);
    538        1.1     freza 
    539        1.1     freza 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
    540        1.1     freza 
    541        1.1     freza 	if_attach(ifp);
    542        1.1     freza 	ether_ifattach(ifp, enaddr);
    543        1.1     freza 
    544        1.1     freza 	sc->sc_sdhook = shutdownhook_establish(temac_shutdown, sc);
    545        1.1     freza 	if (sc->sc_sdhook == NULL)
    546        1.8      matt 		aprint_error_dev(self,
    547        1.8      matt 		    "WARNING: unable to establish shutdown hook\n");
    548        1.1     freza 
    549        1.1     freza 	callout_setfunc(&sc->sc_mii_tick, temac_mii_tick, sc);
    550        1.1     freza 	callout_setfunc(&sc->sc_rx_timo, temac_rxtimo, sc);
    551        1.1     freza 
    552        1.1     freza 	return ;
    553        1.1     freza 
    554        1.1     freza  fail_6:
    555        1.1     freza 	ll_dmac_intr_disestablish(rx->dmac_chan, sc->sc_rx_ih);
    556        1.1     freza 	i = TEMAC_NRXDESC;
    557        1.1     freza  fail_5:
    558        1.1     freza  	for (--i; i >= 0; i--)
    559        1.1     freza  		bus_dmamap_destroy(sc->sc_dmat, sc->sc_rxsoft[i].rxs_dmap);
    560        1.1     freza 	i = TEMAC_TXQLEN;
    561        1.1     freza  fail_4:
    562        1.1     freza  	for (--i; i >= 0; i--)
    563        1.1     freza  		bus_dmamap_destroy(sc->sc_dmat, sc->sc_txsoft[i].txs_dmap);
    564        1.1     freza  fail_3:
    565        1.1     freza 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_control_dmap);
    566        1.1     freza  fail_2:
    567        1.2  christos 	bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data,
    568        1.1     freza 	    sizeof(struct temac_control));
    569        1.1     freza  fail_1:
    570        1.1     freza 	bus_dmamem_free(sc->sc_dmat, &seg, nseg);
    571        1.1     freza  fail_0:
    572        1.8      matt  	aprint_error_dev(self, "error = %d\n", error);
    573        1.1     freza }
    574        1.1     freza 
    575        1.1     freza /*
    576        1.1     freza  * Network device.
    577        1.1     freza  */
    578        1.1     freza static int
    579        1.1     freza temac_init(struct ifnet *ifp)
    580        1.1     freza {
    581        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)ifp->if_softc;
    582        1.1     freza 	uint32_t 		rcr, tcr;
    583        1.1     freza 	int 			i, error;
    584        1.1     freza 
    585        1.1     freza 	/* Reset DMA channels. */
    586        1.1     freza 	cdmac_tx_reset(sc);
    587        1.1     freza 	cdmac_rx_reset(sc);
    588        1.1     freza 
    589        1.1     freza 	/* Set current media. */
    590        1.3    dyoung 	if ((error = ether_mediachange(ifp)) != 0)
    591        1.3    dyoung 		return error;
    592        1.3    dyoung 
    593        1.1     freza 	callout_schedule(&sc->sc_mii_tick, hz);
    594        1.1     freza 
    595        1.1     freza 	/* Enable EMAC engine. */
    596        1.1     freza 	rcr = (gmi_read_4(TEMAC_GMI_RXCF1) | GMI_RX_ENABLE) &
    597        1.1     freza 	    ~(GMI_RX_JUMBO | GMI_RX_FCS);
    598        1.1     freza 	gmi_write_4(TEMAC_GMI_RXCF1, rcr);
    599        1.1     freza 
    600        1.1     freza 	tcr = (gmi_read_4(TEMAC_GMI_TXCF) | GMI_TX_ENABLE) &
    601        1.1     freza 	    ~(GMI_TX_JUMBO | GMI_TX_FCS);
    602        1.1     freza 	gmi_write_4(TEMAC_GMI_TXCF, tcr);
    603        1.1     freza 
    604        1.1     freza 	/* XXXFreza: Force promiscuous mode, for now. */
    605        1.1     freza 	gmi_write_4(TEMAC_GMI_AFM, GMI_AFM_PROMISC);
    606        1.1     freza 	ifp->if_flags |= IFF_PROMISC;
    607        1.1     freza 
    608        1.1     freza 	/* Rx/Tx queues are drained -- either from attach() or stop(). */
    609        1.1     freza 	sc->sc_txsfree = TEMAC_TXQLEN;
    610        1.1     freza 	sc->sc_txsreap = 0;
    611        1.1     freza 	sc->sc_txscur = 0;
    612        1.1     freza 
    613        1.1     freza 	sc->sc_txfree = TEMAC_NTXDESC;
    614        1.1     freza 	sc->sc_txreap = 0;
    615        1.1     freza 	sc->sc_txcur = 0;
    616        1.1     freza 
    617        1.1     freza 	sc->sc_rxreap = 0;
    618        1.1     freza 
    619        1.1     freza 	/* Allocate and map receive buffers. */
    620        1.1     freza 	if (sc->sc_rx_drained) {
    621        1.1     freza 		for (i = 0; i < TEMAC_NRXDESC; i++) {
    622        1.1     freza 			if ((error = temac_rxalloc(sc, i, 1)) != 0) {
    623        1.8      matt 				aprint_error_dev(sc->sc_dev,
    624        1.8      matt 				    "failed to allocate Rx descriptor %d\n",
    625        1.8      matt 				    i);
    626        1.1     freza 				temac_rxdrain(sc);
    627        1.1     freza 				return (error);
    628        1.1     freza 			}
    629        1.1     freza 		}
    630        1.1     freza 		sc->sc_rx_drained = 0;
    631        1.1     freza 
    632        1.1     freza 		temac_rxcdsync(sc, 0, TEMAC_NRXDESC,
    633        1.1     freza 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    634        1.1     freza 		cdmac_rx_start(sc, sc->sc_cdaddr + TEMAC_RXDOFF(0));
    635        1.1     freza 	}
    636        1.1     freza 
    637        1.1     freza 	ifp->if_flags |= IFF_RUNNING;
    638        1.1     freza 	ifp->if_flags &= ~IFF_OACTIVE;
    639        1.1     freza 
    640        1.1     freza 	return (0);
    641        1.1     freza }
    642        1.1     freza 
    643        1.1     freza static int
    644        1.2  christos temac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
    645        1.1     freza {
    646        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)ifp->if_softc;
    647        1.1     freza 	int 			s, ret;
    648        1.1     freza 
    649        1.1     freza 	s = splnet();
    650        1.3    dyoung 	if (sc->sc_dead)
    651        1.1     freza 		ret = EIO;
    652        1.3    dyoung 	else
    653        1.3    dyoung 		ret = ether_ioctl(ifp, cmd, data);
    654        1.1     freza 	splx(s);
    655        1.1     freza 	return (ret);
    656        1.1     freza }
    657        1.1     freza 
    658        1.1     freza static void
    659        1.1     freza temac_start(struct ifnet *ifp)
    660        1.1     freza {
    661        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)ifp->if_softc;
    662        1.1     freza 	struct temac_txsoft 	*txs;
    663        1.1     freza 	struct mbuf 		*m;
    664        1.1     freza 	bus_dmamap_t 		dmap;
    665        1.1     freza 	int 			error, head, nsegs, i;
    666        1.1     freza 
    667        1.1     freza 	nsegs = 0;
    668        1.1     freza 	head = sc->sc_txcur;
    669        1.1     freza 	txs = NULL; 		/* gcc */
    670        1.1     freza 
    671        1.1     freza 	if (sc->sc_dead)
    672        1.1     freza 		return;
    673        1.1     freza 
    674        1.1     freza 	KASSERT(sc->sc_txfree >= 0);
    675        1.1     freza 	KASSERT(sc->sc_txsfree >= 0);
    676        1.1     freza 
    677        1.1     freza 	/*
    678        1.1     freza 	 * Push mbufs into descriptor chain until we drain the interface
    679        1.1     freza 	 * queue or run out of descriptors. We'll mark the first segment
    680        1.1     freza 	 * as "done" in hope that we might put CDMAC interrupt above IPL_NET
    681        1.1     freza 	 * and have it start jobs & mark packets for GC preemtively for
    682        1.1     freza 	 * us -- creativity due to limitations in CDMAC transfer engine
    683        1.1     freza 	 * (it really consumes lists, not circular queues, AFAICS).
    684        1.1     freza 	 *
    685        1.1     freza 	 * We schedule one interrupt per Tx batch.
    686        1.1     freza 	 */
    687        1.1     freza 	while (1) {
    688        1.1     freza 		IFQ_POLL(&ifp->if_snd, m);
    689        1.1     freza 		if (m == NULL)
    690        1.1     freza 			break;
    691        1.1     freza 
    692        1.1     freza 		if (sc->sc_txsfree == 0) {
    693        1.1     freza 			ifp->if_flags |= IFF_OACTIVE;
    694        1.1     freza 			break;
    695        1.1     freza 		}
    696        1.1     freza 
    697        1.1     freza 		txs = &sc->sc_txsoft[sc->sc_txscur];
    698        1.1     freza 		dmap = txs->txs_dmap;
    699        1.1     freza 
    700        1.1     freza 		if (txs->txs_mbuf != NULL)
    701        1.1     freza 			printf("FOO\n");
    702        1.1     freza 		if (txs->txs_last)
    703        1.1     freza 			printf("BAR\n");
    704        1.1     freza 
    705        1.1     freza 		if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m,
    706        1.1     freza 		    BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0) {
    707        1.1     freza 		    	if (error == EFBIG) {
    708        1.8      matt 		    		aprint_error_dev(sc->sc_dev,
    709        1.8      matt 				    "Tx consumes too many segments, dropped\n");
    710        1.1     freza 				IFQ_DEQUEUE(&ifp->if_snd, m);
    711        1.1     freza 				m_freem(m);
    712        1.1     freza 				continue;
    713        1.1     freza 		    	} else {
    714        1.8      matt 		    		aprint_debug_dev(sc->sc_dev,
    715        1.8      matt 				    "Tx stall due to resource shortage\n");
    716        1.1     freza 		    		break;
    717        1.1     freza 			}
    718        1.1     freza 		}
    719        1.1     freza 
    720        1.1     freza 		/*
    721        1.1     freza 		 * If we're short on DMA descriptors, notify upper layers
    722        1.1     freza 		 * and leave this packet for later.
    723        1.1     freza 		 */
    724        1.1     freza 		if (dmap->dm_nsegs > sc->sc_txfree) {
    725        1.1     freza 			bus_dmamap_unload(sc->sc_dmat, dmap);
    726        1.1     freza 			ifp->if_flags |= IFF_OACTIVE;
    727        1.1     freza 			break;
    728        1.1     freza 		}
    729        1.1     freza 
    730        1.1     freza 		IFQ_DEQUEUE(&ifp->if_snd, m);
    731        1.1     freza 
    732        1.1     freza 		bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
    733        1.1     freza 		    BUS_DMASYNC_PREWRITE);
    734        1.1     freza 		txs->txs_mbuf = m;
    735        1.1     freza 
    736        1.1     freza 		/*
    737        1.1     freza 		 * Map the packet into descriptor chain. XXX We'll want
    738        1.1     freza 		 * to fill checksum offload commands here.
    739        1.1     freza 		 *
    740        1.1     freza 		 * We would be in a race if we weren't blocking CDMAC intr
    741        1.1     freza 		 * at this point -- we need to be locked against txreap()
    742        1.1     freza 		 * because of dmasync ops.
    743        1.1     freza 		 */
    744        1.1     freza 
    745        1.1     freza 		temac_txcdsync(sc, sc->sc_txcur, dmap->dm_nsegs,
    746        1.1     freza 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
    747        1.1     freza 
    748        1.1     freza 		for (i = 0; i < dmap->dm_nsegs; i++) {
    749        1.1     freza 			sc->sc_txdescs[sc->sc_txcur].desc_addr =
    750        1.1     freza 			    dmap->dm_segs[i].ds_addr;
    751        1.1     freza 			sc->sc_txdescs[sc->sc_txcur].desc_size =
    752        1.1     freza 			    dmap->dm_segs[i].ds_len;
    753        1.1     freza 			sc->sc_txdescs[sc->sc_txcur].desc_stat =
    754        1.1     freza 			    (i == 0 			? CDMAC_STAT_SOP : 0) |
    755        1.1     freza 			    (i == (dmap->dm_nsegs - 1) 	? CDMAC_STAT_EOP : 0);
    756        1.1     freza 
    757        1.1     freza 			sc->sc_txcur = TEMAC_TXNEXT(sc->sc_txcur);
    758        1.1     freza 		}
    759        1.1     freza 
    760        1.1     freza 		sc->sc_txfree -= dmap->dm_nsegs;
    761        1.1     freza 		nsegs += dmap->dm_nsegs;
    762        1.1     freza 
    763        1.1     freza 		sc->sc_txscur = TEMAC_TXSNEXT(sc->sc_txscur);
    764        1.1     freza 		sc->sc_txsfree--;
    765        1.1     freza 	}
    766        1.1     freza 
    767        1.1     freza 	/* Get data running if we queued any. */
    768        1.1     freza 	if (nsegs > 0) {
    769        1.1     freza 		int 		tail = TEMAC_TXINC(sc->sc_txcur, -1);
    770        1.1     freza 
    771        1.1     freza 		/* Mark the last packet in this job. */
    772        1.1     freza 		txs->txs_last = 1;
    773        1.1     freza 
    774        1.1     freza 		/* Mark the last descriptor in this job. */
    775        1.1     freza 		sc->sc_txdescs[tail].desc_stat |= CDMAC_STAT_STOP |
    776        1.1     freza 		    CDMAC_STAT_INTR;
    777        1.1     freza 		temac_txcdsync(sc, head, nsegs,
    778        1.1     freza 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    779        1.1     freza 
    780        1.1     freza 		temac_txkick(sc);
    781        1.1     freza #if TEMAC_TXDEBUG > 0
    782        1.8      matt 		aprint_debug_dev(sc->sc_dev,
    783        1.8      matt 		    "start:  txcur  %03d -> %03d, nseg %03d\n",
    784        1.8      matt 		    head, sc->sc_txcur, nsegs);
    785        1.1     freza #endif
    786        1.1     freza 	}
    787        1.1     freza }
    788        1.1     freza 
    789        1.1     freza static void
    790        1.1     freza temac_stop(struct ifnet *ifp, int disable)
    791        1.1     freza {
    792        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)ifp->if_softc;
    793        1.1     freza 	struct temac_txsoft 	*txs;
    794        1.1     freza 	int 			i;
    795        1.1     freza 
    796        1.1     freza #if TEMAC_DEBUG > 0
    797        1.8      matt 	aprint_debug_dev(sc->sc_dev, "stop\n");
    798        1.1     freza #endif
    799        1.1     freza 
    800        1.1     freza 	/* Down the MII. */
    801        1.1     freza 	callout_stop(&sc->sc_mii_tick);
    802        1.1     freza 	mii_down(&sc->sc_mii);
    803        1.1     freza 
    804        1.1     freza 	/* Stop the engine. */
    805        1.1     freza 	temac_reset(sc);
    806        1.1     freza 
    807        1.1     freza 	/* Drain buffers queues (unconditionally). */
    808        1.1     freza 	temac_rxdrain(sc);
    809        1.1     freza 
    810        1.1     freza 	for (i = 0; i < TEMAC_TXQLEN; i++) {
    811        1.1     freza 		txs = &sc->sc_txsoft[i];
    812        1.1     freza 
    813        1.1     freza 		if (txs->txs_mbuf != NULL) {
    814        1.1     freza 			bus_dmamap_unload(sc->sc_dmat, txs->txs_dmap);
    815        1.1     freza 			m_freem(txs->txs_mbuf);
    816        1.1     freza 			txs->txs_mbuf = NULL;
    817        1.1     freza 			txs->txs_last = 0;
    818        1.1     freza 		}
    819        1.1     freza 	}
    820        1.1     freza 	sc->sc_txbusy = 0;
    821        1.1     freza 
    822        1.1     freza 	/* Acknowledge we're down. */
    823        1.1     freza 	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
    824        1.1     freza }
    825        1.1     freza 
    826        1.1     freza static int
    827  1.12.14.1  pgoyette temac_mii_readreg(device_t self, int phy, int reg, uint16_t *val)
    828        1.1     freza {
    829  1.12.14.1  pgoyette 	int rv;
    830  1.12.14.1  pgoyette 
    831        1.1     freza 	mtidcr(IDCR_HIF_ARG0, (phy << 5) | reg);
    832        1.1     freza 	mtidcr(IDCR_HIF_CTRL, TEMAC_GMI_MII_ADDR);
    833        1.1     freza 
    834  1.12.14.1  pgoyette 	if ((rv = hif_wait_stat(HIF_STAT_MIIRR)) != 0)
    835  1.12.14.1  pgoyette 		return rv;
    836  1.12.14.1  pgoyette 
    837  1.12.14.1  pgoyette 	*val = mfidcr(IDCR_HIF_ARG0) & 0xffff;
    838  1.12.14.1  pgoyette 	return 0;
    839        1.1     freza }
    840        1.1     freza 
    841  1.12.14.1  pgoyette static int
    842  1.12.14.1  pgoyette temac_mii_writereg(device_t self, int phy, int reg, uint16_t val)
    843        1.1     freza {
    844        1.1     freza 	mtidcr(IDCR_HIF_ARG0, val);
    845        1.1     freza 	mtidcr(IDCR_HIF_CTRL, TEMAC_GMI_MII_WRVAL | HIF_CTRL_WRITE);
    846        1.1     freza 	mtidcr(IDCR_HIF_ARG0, (phy << 5) | reg);
    847        1.1     freza 	mtidcr(IDCR_HIF_CTRL, TEMAC_GMI_MII_ADDR | HIF_CTRL_WRITE);
    848  1.12.14.1  pgoyette 	return hif_wait_stat(HIF_STAT_MIIWR);
    849        1.1     freza }
    850        1.1     freza 
    851        1.1     freza static void
    852        1.9      matt temac_mii_statchg(struct ifnet *ifp)
    853        1.1     freza {
    854        1.9      matt 	struct temac_softc 	*sc = ifp->if_softc;
    855        1.1     freza 	uint32_t 		rcf, tcf, mmc;
    856        1.1     freza 
    857        1.1     freza 	/* Full/half duplex link. */
    858        1.1     freza 	rcf = gmi_read_4(TEMAC_GMI_RXCF1);
    859        1.1     freza 	tcf = gmi_read_4(TEMAC_GMI_TXCF);
    860        1.1     freza 
    861        1.1     freza 	if (sc->sc_mii.mii_media_active & IFM_FDX) {
    862        1.1     freza 		gmi_write_4(TEMAC_GMI_RXCF1, rcf & ~GMI_RX_HDX);
    863        1.1     freza 		gmi_write_4(TEMAC_GMI_TXCF, tcf & ~GMI_TX_HDX);
    864        1.1     freza 	} else {
    865        1.1     freza 		gmi_write_4(TEMAC_GMI_RXCF1, rcf | GMI_RX_HDX);
    866        1.1     freza 		gmi_write_4(TEMAC_GMI_TXCF, tcf | GMI_TX_HDX);
    867        1.1     freza 	}
    868        1.1     freza 
    869        1.1     freza 	/* Link speed. */
    870        1.1     freza 	mmc = gmi_read_4(TEMAC_GMI_MMC) & ~GMI_MMC_SPEED_MASK;
    871        1.1     freza 
    872        1.1     freza 	switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
    873        1.1     freza 	case IFM_10_T:
    874        1.1     freza 		/*
    875        1.1     freza 		 * XXXFreza: the GMAC is not happy with 10Mbit ethernet,
    876        1.1     freza 		 * although the documentation claims it's supported. Maybe
    877        1.1     freza 		 * it's just my equipment...
    878        1.1     freza 		 */
    879        1.1     freza 		mmc |= GMI_MMC_SPEED_10;
    880        1.1     freza 		break;
    881        1.1     freza 	case IFM_100_TX:
    882        1.1     freza 		mmc |= GMI_MMC_SPEED_100;
    883        1.1     freza 		break;
    884        1.1     freza 	case IFM_1000_T:
    885        1.1     freza 		mmc |= GMI_MMC_SPEED_1000;
    886        1.1     freza 		break;
    887        1.1     freza 	}
    888        1.1     freza 
    889        1.1     freza 	gmi_write_4(TEMAC_GMI_MMC, mmc);
    890        1.1     freza }
    891        1.1     freza 
    892        1.1     freza static void
    893        1.1     freza temac_mii_tick(void *arg)
    894        1.1     freza {
    895        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)arg;
    896        1.1     freza 	int 			s;
    897        1.1     freza 
    898        1.8      matt 	if (!device_is_active(sc->sc_dev))
    899        1.4    dyoung 		return;
    900        1.1     freza 
    901        1.1     freza 	s = splnet();
    902        1.1     freza 	mii_tick(&sc->sc_mii);
    903        1.1     freza 	splx(s);
    904        1.1     freza 
    905        1.1     freza 	callout_schedule(&sc->sc_mii_tick, hz);
    906        1.1     freza }
    907        1.1     freza 
    908        1.1     freza /*
    909        1.1     freza  * External hooks.
    910        1.1     freza  */
    911        1.1     freza static void
    912        1.1     freza temac_shutdown(void *arg)
    913        1.1     freza {
    914        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)arg;
    915        1.1     freza 
    916        1.1     freza 	temac_reset(sc);
    917        1.1     freza }
    918        1.1     freza 
    919        1.1     freza static void
    920        1.1     freza temac_tx_intr(void *arg)
    921        1.1     freza {
    922        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)arg;
    923        1.1     freza 	uint32_t 		stat;
    924        1.1     freza 
    925        1.1     freza 	/* XXX: We may need to splnet() here if cdmac(4) changes. */
    926        1.1     freza 
    927        1.1     freza 	if ((stat = cdmac_tx_stat(sc)) & CDMAC_STAT_ERROR) {
    928        1.8      matt 		aprint_error_dev(sc->sc_dev,
    929        1.8      matt 		    "transmit DMA is toast (%#08x), halted!\n",
    930        1.8      matt 		    stat);
    931        1.1     freza 
    932        1.1     freza 		/* XXXFreza: how to signal this upstream? */
    933        1.1     freza 		temac_stop(&sc->sc_if, 1);
    934        1.1     freza 		sc->sc_dead = 1;
    935        1.1     freza 	}
    936        1.1     freza 
    937        1.1     freza #if TEMAC_DEBUG > 0
    938        1.8      matt 	aprint_debug_dev(sc->sc_dev, "tx intr 0x%08x\n", stat);
    939        1.1     freza #endif
    940        1.1     freza 	temac_txreap(sc);
    941        1.1     freza }
    942        1.1     freza 
    943        1.1     freza static void
    944        1.1     freza temac_rx_intr(void *arg)
    945        1.1     freza {
    946        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)arg;
    947        1.1     freza 	uint32_t 		stat;
    948        1.1     freza 
    949        1.1     freza 	/* XXX: We may need to splnet() here if cdmac(4) changes. */
    950        1.1     freza 
    951        1.1     freza 	if ((stat = cdmac_rx_stat(sc)) & CDMAC_STAT_ERROR) {
    952        1.8      matt 		aprint_error_dev(sc->sc_dev,
    953        1.8      matt 		    "receive DMA is toast (%#08x), halted!\n",
    954        1.8      matt 		    stat);
    955        1.1     freza 
    956        1.1     freza 		/* XXXFreza: how to signal this upstream? */
    957        1.1     freza 		temac_stop(&sc->sc_if, 1);
    958        1.1     freza 		sc->sc_dead = 1;
    959        1.1     freza 	}
    960        1.1     freza 
    961        1.1     freza #if TEMAC_DEBUG > 0
    962        1.8      matt 	aprint_debug_dev(sc->sc_dev, "rx intr 0x%08x\n", stat);
    963        1.1     freza #endif
    964        1.1     freza 	temac_rxreap(sc);
    965        1.1     freza }
    966        1.1     freza 
    967        1.1     freza /*
    968        1.1     freza  * Utils.
    969        1.1     freza  */
    970        1.1     freza static inline void
    971        1.1     freza temac_txcdsync(struct temac_softc *sc, int first, int cnt, int flag)
    972        1.1     freza {
    973        1.1     freza 	if ((first + cnt) > TEMAC_NTXDESC) {
    974        1.1     freza 		bus_dmamap_sync(sc->sc_dmat, sc->sc_control_dmap,
    975        1.1     freza 		    TEMAC_TXDOFF(first),
    976        1.1     freza 		    sizeof(struct cdmac_descr) * (TEMAC_NTXDESC - first),
    977        1.1     freza 		    flag);
    978        1.1     freza 		cnt = (first + cnt) % TEMAC_NTXDESC;
    979        1.1     freza 		first = 0;
    980        1.1     freza 	}
    981        1.1     freza 
    982        1.1     freza 	bus_dmamap_sync(sc->sc_dmat, sc->sc_control_dmap,
    983        1.1     freza 	    TEMAC_TXDOFF(first),
    984        1.1     freza 	    sizeof(struct cdmac_descr) * cnt,
    985        1.1     freza 	    flag);
    986        1.1     freza }
    987        1.1     freza 
    988        1.1     freza static inline void
    989        1.1     freza temac_rxcdsync(struct temac_softc *sc, int first, int cnt, int flag)
    990        1.1     freza {
    991        1.1     freza 	if ((first + cnt) > TEMAC_NRXDESC) {
    992        1.1     freza 		bus_dmamap_sync(sc->sc_dmat, sc->sc_control_dmap,
    993        1.1     freza 		    TEMAC_RXDOFF(first),
    994        1.1     freza 		    sizeof(struct cdmac_descr) * (TEMAC_NRXDESC - first),
    995        1.1     freza 		    flag);
    996        1.1     freza 		cnt = (first + cnt) % TEMAC_NRXDESC;
    997        1.1     freza 		first = 0;
    998        1.1     freza 	}
    999        1.1     freza 
   1000        1.1     freza 	bus_dmamap_sync(sc->sc_dmat, sc->sc_control_dmap,
   1001        1.1     freza 	    TEMAC_RXDOFF(first),
   1002        1.1     freza 	    sizeof(struct cdmac_descr) * cnt,
   1003        1.1     freza 	    flag);
   1004        1.1     freza }
   1005        1.1     freza 
   1006        1.1     freza static void
   1007        1.1     freza temac_txreap(struct temac_softc *sc)
   1008        1.1     freza {
   1009        1.1     freza 	struct temac_txsoft 	*txs;
   1010        1.1     freza 	bus_dmamap_t 		dmap;
   1011        1.1     freza 	int 			sent = 0;
   1012        1.1     freza 
   1013        1.1     freza 	/*
   1014        1.1     freza 	 * Transmit interrupts happen on the last descriptor of Tx jobs.
   1015        1.1     freza 	 * Hence, every time we're called (and we assume txintr is our
   1016        1.1     freza 	 * only caller!), we reap packets upto and including the one
   1017        1.1     freza 	 * marked as last-in-batch.
   1018        1.1     freza 	 *
   1019        1.1     freza 	 * XXX we rely on that we make EXACTLY one batch per intr, no more
   1020        1.1     freza 	 */
   1021        1.1     freza 	while (sc->sc_txsfree != TEMAC_TXQLEN) {
   1022        1.1     freza 		txs = &sc->sc_txsoft[sc->sc_txsreap];
   1023        1.1     freza 		dmap = txs->txs_dmap;
   1024        1.1     freza 
   1025        1.1     freza 		sc->sc_txreap = TEMAC_TXINC(sc->sc_txreap, dmap->dm_nsegs);
   1026        1.1     freza 		sc->sc_txfree += dmap->dm_nsegs;
   1027        1.1     freza 
   1028        1.1     freza 		bus_dmamap_unload(sc->sc_dmat, txs->txs_dmap);
   1029        1.1     freza 		m_freem(txs->txs_mbuf);
   1030        1.1     freza 		txs->txs_mbuf = NULL;
   1031        1.1     freza 
   1032        1.1     freza 		sc->sc_if.if_opackets++;
   1033        1.1     freza 		sent = 1;
   1034        1.1     freza 
   1035        1.1     freza 		sc->sc_txsreap = TEMAC_TXSNEXT(sc->sc_txsreap);
   1036        1.1     freza 		sc->sc_txsfree++;
   1037        1.1     freza 
   1038        1.1     freza 		if (txs->txs_last) {
   1039        1.1     freza 			txs->txs_last = 0;
   1040        1.1     freza 			sc->sc_txbusy = 0; 	/* channel stopped now */
   1041        1.1     freza 
   1042        1.1     freza 			temac_txkick(sc);
   1043        1.1     freza 			break;
   1044        1.1     freza 		}
   1045        1.1     freza 	}
   1046        1.1     freza 
   1047        1.1     freza 	if (sent && (sc->sc_if.if_flags & IFF_OACTIVE))
   1048        1.1     freza 		sc->sc_if.if_flags &= ~IFF_OACTIVE;
   1049        1.1     freza }
   1050        1.1     freza 
   1051        1.1     freza static int
   1052        1.1     freza temac_rxalloc(struct temac_softc *sc, int which, int verbose)
   1053        1.1     freza {
   1054        1.1     freza 	struct temac_rxsoft 	*rxs;
   1055        1.1     freza 	struct mbuf 		*m;
   1056        1.1     freza 	uint32_t 		stat;
   1057        1.1     freza 	int 			error;
   1058        1.1     freza 
   1059        1.1     freza 	rxs = &sc->sc_rxsoft[which];
   1060        1.1     freza 
   1061        1.1     freza 	/* The mbuf itself is not our problem, just clear DMA related stuff. */
   1062        1.1     freza 	if (rxs->rxs_mbuf != NULL) {
   1063        1.1     freza 		bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmap);
   1064        1.1     freza 		rxs->rxs_mbuf = NULL;
   1065        1.1     freza 	}
   1066        1.1     freza 
   1067        1.1     freza 	/*
   1068        1.1     freza 	 * We would like to store mbuf and dmap in application specific
   1069        1.1     freza 	 * fields of the descriptor, but that doesn't work for Rx. Shame
   1070        1.1     freza 	 * on Xilinx for this (and for the useless timer architecture).
   1071        1.1     freza 	 *
   1072        1.1     freza 	 * Hence each descriptor needs its own soft state. We may want
   1073        1.1     freza 	 * to merge multiple rxs's into a monster mbuf when we support
   1074        1.1     freza 	 * jumbo frames though. Also, we use single set of indexing
   1075        1.1     freza 	 * variables for both sc_rxdescs[] and sc_rxsoft[].
   1076        1.1     freza 	 */
   1077        1.1     freza 	MGETHDR(m, M_DONTWAIT, MT_DATA);
   1078        1.1     freza 	if (m == NULL) {
   1079        1.1     freza 		if (verbose)
   1080        1.8      matt 			aprint_debug_dev(sc->sc_dev,
   1081        1.8      matt 			    "out of Rx header mbufs\n");
   1082        1.1     freza 		return (ENOBUFS);
   1083        1.1     freza 	}
   1084        1.1     freza 	MCLAIM(m, &sc->sc_ec.ec_rx_mowner);
   1085        1.1     freza 
   1086        1.1     freza 	MCLGET(m, M_DONTWAIT);
   1087        1.1     freza 	if ((m->m_flags & M_EXT) == 0) {
   1088        1.1     freza 		if (verbose)
   1089        1.8      matt 			aprint_debug_dev(sc->sc_dev,
   1090        1.8      matt 			    "out of Rx cluster mbufs\n");
   1091        1.1     freza 		m_freem(m);
   1092        1.1     freza 		return (ENOBUFS);
   1093        1.1     freza 	}
   1094        1.1     freza 
   1095        1.1     freza 	rxs->rxs_mbuf = m;
   1096        1.1     freza 	m->m_pkthdr.len = m->m_len = MCLBYTES;
   1097        1.1     freza 
   1098        1.1     freza 	/* Make sure the payload after ethernet header is 4-aligned. */
   1099        1.1     freza 	m_adj(m, 2);
   1100        1.1     freza 
   1101        1.1     freza 	error = bus_dmamap_load_mbuf(sc->sc_dmat, rxs->rxs_dmap, m,
   1102        1.1     freza 	    BUS_DMA_NOWAIT);
   1103        1.1     freza 	if (error) {
   1104        1.1     freza 		if (verbose)
   1105        1.8      matt 			aprint_debug_dev(sc->sc_dev,
   1106        1.8      matt 			    "could not map Rx descriptor %d, error = %d\n",
   1107        1.8      matt 			    which, error);
   1108        1.1     freza 
   1109        1.1     freza 		rxs->rxs_mbuf = NULL;
   1110        1.1     freza 		m_freem(m);
   1111        1.1     freza 
   1112        1.1     freza 		return (error);
   1113        1.1     freza 	}
   1114        1.1     freza 
   1115        1.8      matt 	stat =
   1116        1.1     freza 	    (TEMAC_ISINTR(which) ? CDMAC_STAT_INTR : 0) |
   1117        1.1     freza 	    (TEMAC_ISLAST(which) ? CDMAC_STAT_STOP : 0);
   1118        1.1     freza 
   1119        1.1     freza 	bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmap, 0,
   1120        1.1     freza 	    rxs->rxs_dmap->dm_mapsize, BUS_DMASYNC_PREREAD);
   1121        1.1     freza 
   1122        1.1     freza 	/* Descriptor post-sync, if needed, left to the caller. */
   1123        1.1     freza 
   1124        1.1     freza 	sc->sc_rxdescs[which].desc_addr = rxs->rxs_dmap->dm_segs[0].ds_addr;
   1125        1.1     freza 	sc->sc_rxdescs[which].desc_size  = rxs->rxs_dmap->dm_segs[0].ds_len;
   1126        1.1     freza 	sc->sc_rxdescs[which].desc_stat = stat;
   1127        1.1     freza 
   1128        1.1     freza 	/* Descriptor pre-sync, if needed, left to the caller. */
   1129        1.1     freza 
   1130        1.1     freza 	return (0);
   1131        1.1     freza }
   1132        1.1     freza 
   1133        1.1     freza static void
   1134        1.1     freza temac_rxreap(struct temac_softc *sc)
   1135        1.1     freza {
   1136        1.1     freza 	struct ifnet 		*ifp = &sc->sc_if;
   1137        1.1     freza 	uint32_t 		stat, rxstat, rxsize;
   1138        1.1     freza 	struct mbuf 		*m;
   1139        1.1     freza 	int 			nseg, head, tail;
   1140        1.1     freza 
   1141        1.1     freza 	head = sc->sc_rxreap;
   1142        1.1     freza 	tail = 0; 		/* gcc */
   1143        1.1     freza 	nseg = 0;
   1144        1.1     freza 
   1145        1.1     freza 	/*
   1146        1.1     freza 	 * Collect finished entries on the Rx list, kick DMA if we hit
   1147        1.1     freza 	 * the end. DMA will always stop on the last descriptor in chain,
   1148        1.1     freza 	 * so it will never hit a reap-in-progress descriptor.
   1149        1.1     freza 	 */
   1150        1.1     freza 	while (1) {
   1151        1.1     freza 		/* Maybe we previously failed to refresh this one? */
   1152        1.1     freza 		if (sc->sc_rxsoft[sc->sc_rxreap].rxs_mbuf == NULL) {
   1153        1.1     freza 			if (temac_rxalloc(sc, sc->sc_rxreap, 0) != 0)
   1154        1.1     freza 				break;
   1155        1.1     freza 
   1156        1.1     freza 			sc->sc_rxreap = TEMAC_RXNEXT(sc->sc_rxreap);
   1157        1.1     freza 			continue;
   1158        1.1     freza 		}
   1159        1.1     freza 		temac_rxcdsync(sc, sc->sc_rxreap, 1,
   1160        1.1     freza 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
   1161        1.1     freza 
   1162        1.1     freza 		stat = sc->sc_rxdescs[sc->sc_rxreap].desc_stat;
   1163        1.1     freza 		m = NULL;
   1164        1.1     freza 
   1165        1.1     freza 		if ((stat & CDMAC_STAT_DONE) == 0)
   1166        1.1     freza 			break;
   1167        1.1     freza 
   1168        1.1     freza 		/* Count any decriptor we've collected, regardless of status. */
   1169        1.1     freza 		nseg ++;
   1170        1.1     freza 
   1171        1.1     freza 		/* XXXFreza: This won't work for jumbo frames. */
   1172        1.1     freza 
   1173        1.1     freza 		if ((stat & (CDMAC_STAT_EOP | CDMAC_STAT_SOP)) !=
   1174        1.1     freza 		    (CDMAC_STAT_EOP | CDMAC_STAT_SOP)) {
   1175        1.8      matt 		    	aprint_error_dev(sc->sc_dev,
   1176        1.8      matt 			    "Rx packet doesn't fit in one descriptor, "
   1177        1.8      matt 			    "stat = %#08x\n", stat);
   1178        1.1     freza 			goto badframe;
   1179        1.1     freza 		}
   1180        1.1     freza 
   1181        1.1     freza 		/* Dissect TEMAC footer if this is end of packet. */
   1182        1.1     freza 		rxstat = sc->sc_rxdescs[sc->sc_rxreap].desc_rxstat;
   1183        1.1     freza 		rxsize = sc->sc_rxdescs[sc->sc_rxreap].desc_rxsize &
   1184        1.1     freza 		    RXSIZE_MASK;
   1185        1.1     freza 
   1186        1.1     freza 		if ((rxstat & RXSTAT_GOOD) == 0 ||
   1187        1.1     freza 		    (rxstat & RXSTAT_SICK) != 0) {
   1188        1.8      matt 		    	aprint_error_dev(sc->sc_dev,
   1189        1.8      matt 			    "corrupt Rx packet, rxstat = %#08x\n",
   1190        1.8      matt 		    	    rxstat);
   1191        1.1     freza 			goto badframe;
   1192        1.1     freza 		}
   1193        1.1     freza 
   1194        1.1     freza 		/* We are now bound to succeed. */
   1195        1.1     freza 		bus_dmamap_sync(sc->sc_dmat,
   1196        1.1     freza 		    sc->sc_rxsoft[sc->sc_rxreap].rxs_dmap, 0,
   1197        1.1     freza 		    sc->sc_rxsoft[sc->sc_rxreap].rxs_dmap->dm_mapsize,
   1198        1.1     freza 		    BUS_DMASYNC_POSTREAD);
   1199        1.1     freza 
   1200        1.1     freza 		m = sc->sc_rxsoft[sc->sc_rxreap].rxs_mbuf;
   1201       1.11     ozaki 		m_set_rcvif(m, ifp);
   1202        1.1     freza 		m->m_pkthdr.len = m->m_len = rxsize;
   1203        1.1     freza 
   1204        1.1     freza  badframe:
   1205        1.1     freza  		/* Get ready for more work. */
   1206        1.1     freza 		tail = sc->sc_rxreap;
   1207        1.1     freza 		sc->sc_rxreap = TEMAC_RXNEXT(sc->sc_rxreap);
   1208        1.1     freza 
   1209        1.1     freza  		/* On failures we reuse the descriptor and go ahead. */
   1210        1.1     freza  		if (m == NULL) {
   1211        1.1     freza 			sc->sc_rxdescs[tail].desc_stat =
   1212        1.1     freza 			    (TEMAC_ISINTR(tail) ? CDMAC_STAT_INTR : 0) |
   1213        1.1     freza 			    (TEMAC_ISLAST(tail) ? CDMAC_STAT_STOP : 0);
   1214        1.1     freza 
   1215        1.1     freza 			ifp->if_ierrors++;
   1216        1.1     freza 			continue;
   1217        1.1     freza  		}
   1218        1.1     freza 
   1219       1.10     ozaki 		if_percpuq_enqueue(ifp->if_percpuq, m);
   1220        1.1     freza 
   1221        1.1     freza 		/* Refresh descriptor, bail out if we're out of buffers. */
   1222        1.1     freza 		if (temac_rxalloc(sc, tail, 1) != 0) {
   1223        1.1     freza  			sc->sc_rxreap = TEMAC_RXINC(sc->sc_rxreap, -1);
   1224        1.8      matt  			aprint_error_dev(sc->sc_dev, "Rx give up for now\n");
   1225        1.1     freza 			break;
   1226        1.1     freza 		}
   1227        1.1     freza 	}
   1228        1.1     freza 
   1229        1.1     freza 	/* We may now have a contiguous ready-to-go chunk of descriptors. */
   1230        1.1     freza 	if (nseg > 0) {
   1231        1.1     freza #if TEMAC_RXDEBUG > 0
   1232        1.8      matt 		aprint_debug_dev(sc->sc_dev,
   1233        1.8      matt 		    "rxreap: rxreap %03d -> %03d, nseg %03d\n",
   1234        1.8      matt 		    head, sc->sc_rxreap, nseg);
   1235        1.1     freza #endif
   1236        1.1     freza 		temac_rxcdsync(sc, head, nseg,
   1237        1.1     freza 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
   1238        1.1     freza 
   1239        1.1     freza 		if (TEMAC_ISLAST(tail))
   1240        1.1     freza 			cdmac_rx_start(sc, sc->sc_cdaddr + TEMAC_RXDOFF(0));
   1241        1.1     freza 	}
   1242        1.1     freza 
   1243        1.1     freza 	/* Ensure maximum Rx latency is kept under control. */
   1244        1.1     freza 	callout_schedule(&sc->sc_rx_timo, hz / TEMAC_RXTIMO_HZ);
   1245        1.1     freza }
   1246        1.1     freza 
   1247        1.1     freza static void
   1248        1.1     freza temac_rxtimo(void *arg)
   1249        1.1     freza {
   1250        1.1     freza 	struct temac_softc 	*sc = (struct temac_softc *)arg;
   1251        1.1     freza 	int 			s;
   1252        1.1     freza 
   1253        1.1     freza 	/* We run TEMAC_RXTIMO_HZ times/sec to ensure Rx doesn't stall. */
   1254        1.1     freza 	s = splnet();
   1255        1.1     freza 	temac_rxreap(sc);
   1256        1.1     freza 	splx(s);
   1257        1.1     freza }
   1258        1.1     freza 
   1259        1.1     freza static void
   1260        1.1     freza temac_reset(struct temac_softc *sc)
   1261        1.1     freza {
   1262        1.1     freza 	uint32_t 		rcr, tcr;
   1263        1.1     freza 
   1264        1.1     freza 	/* Kill CDMAC channels. */
   1265        1.1     freza 	cdmac_tx_reset(sc);
   1266        1.1     freza 	cdmac_rx_reset(sc);
   1267        1.1     freza 
   1268        1.1     freza 	/* Disable receiver. */
   1269        1.1     freza 	rcr = gmi_read_4(TEMAC_GMI_RXCF1) & ~GMI_RX_ENABLE;
   1270        1.1     freza 	gmi_write_4(TEMAC_GMI_RXCF1, rcr);
   1271        1.1     freza 
   1272        1.1     freza 	/* Disable transmitter. */
   1273        1.1     freza 	tcr = gmi_read_4(TEMAC_GMI_TXCF) & ~GMI_TX_ENABLE;
   1274        1.1     freza 	gmi_write_4(TEMAC_GMI_TXCF, tcr);
   1275        1.1     freza }
   1276        1.1     freza 
   1277        1.1     freza static void
   1278        1.1     freza temac_rxdrain(struct temac_softc *sc)
   1279        1.1     freza {
   1280        1.1     freza 	struct temac_rxsoft 	*rxs;
   1281        1.1     freza 	int 			i;
   1282        1.1     freza 
   1283        1.1     freza 	for (i = 0; i < TEMAC_NRXDESC; i++) {
   1284        1.1     freza 		rxs = &sc->sc_rxsoft[i];
   1285        1.1     freza 
   1286        1.1     freza 		if (rxs->rxs_mbuf != NULL) {
   1287        1.1     freza 			bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmap);
   1288        1.1     freza 			m_freem(rxs->rxs_mbuf);
   1289        1.1     freza 			rxs->rxs_mbuf = NULL;
   1290        1.1     freza 		}
   1291        1.1     freza 	}
   1292        1.1     freza 
   1293        1.1     freza 	sc->sc_rx_drained = 1;
   1294        1.1     freza }
   1295        1.1     freza 
   1296        1.1     freza static void
   1297        1.1     freza temac_txkick(struct temac_softc *sc)
   1298        1.1     freza {
   1299        1.1     freza 	if (sc->sc_txsoft[sc->sc_txsreap].txs_mbuf != NULL &&
   1300        1.1     freza 	    sc->sc_txbusy == 0) {
   1301        1.1     freza 		cdmac_tx_start(sc, sc->sc_cdaddr + TEMAC_TXDOFF(sc->sc_txreap));
   1302        1.1     freza 		sc->sc_txbusy = 1;
   1303        1.1     freza 	}
   1304        1.1     freza }
   1305