Home | History | Annotate | Line # | Download | only in mpc5200
      1  1.2  rkujawa /*	$NetBSD: fec.c,v 1.2 2026/06/30 21:31:31 rkujawa Exp $	*/
      2  1.1  rkujawa 
      3  1.1  rkujawa /*-
      4  1.1  rkujawa  * Copyright (c) 2008, 2026 The NetBSD Foundation, Inc.
      5  1.1  rkujawa  * All rights reserved.
      6  1.1  rkujawa  *
      7  1.1  rkujawa  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1  rkujawa  * by Radoslaw Kujawa and Robert Swindells.
      9  1.1  rkujawa  *
     10  1.1  rkujawa  * Redistribution and use in source and binary forms, with or without
     11  1.1  rkujawa  * modification, are permitted provided that the following conditions
     12  1.1  rkujawa  * are met:
     13  1.1  rkujawa  * 1. Redistributions of source code must retain the above copyright
     14  1.1  rkujawa  *    notice, this list of conditions and the following disclaimer.
     15  1.1  rkujawa  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1  rkujawa  *    notice, this list of conditions and the following disclaimer in the
     17  1.1  rkujawa  *    documentation and/or other materials provided with the distribution.
     18  1.1  rkujawa  *
     19  1.1  rkujawa  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.1  rkujawa  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.1  rkujawa  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.1  rkujawa  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.1  rkujawa  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.1  rkujawa  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.1  rkujawa  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.1  rkujawa  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.1  rkujawa  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.1  rkujawa  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.1  rkujawa  * POSSIBILITY OF SUCH DAMAGE.
     30  1.1  rkujawa  */
     31  1.1  rkujawa 
     32  1.1  rkujawa /*
     33  1.1  rkujawa  * Driver for the MPC5200B Fast Ethernet Controller (FEC).
     34  1.1  rkujawa  */
     35  1.1  rkujawa 
     36  1.1  rkujawa #include <sys/cdefs.h>
     37  1.2  rkujawa __KERNEL_RCSID(0, "$NetBSD: fec.c,v 1.2 2026/06/30 21:31:31 rkujawa Exp $");
     38  1.1  rkujawa 
     39  1.1  rkujawa #include <sys/param.h>
     40  1.1  rkujawa #include <sys/systm.h>
     41  1.1  rkujawa #include <sys/device.h>
     42  1.1  rkujawa #include <sys/callout.h>
     43  1.1  rkujawa #include <sys/mbuf.h>
     44  1.1  rkujawa #include <sys/bus.h>
     45  1.1  rkujawa 
     46  1.1  rkujawa #include <net/if.h>
     47  1.1  rkujawa #include <net/if_dl.h>
     48  1.1  rkujawa #include <net/if_ether.h>
     49  1.1  rkujawa #include <net/if_media.h>
     50  1.1  rkujawa #include <net/bpf.h>
     51  1.1  rkujawa 
     52  1.1  rkujawa #include <dev/mii/mii.h>
     53  1.1  rkujawa #include <dev/mii/miivar.h>
     54  1.1  rkujawa 
     55  1.1  rkujawa #include <dev/ofw/openfirm.h>
     56  1.1  rkujawa 
     57  1.1  rkujawa #include <machine/autoconf.h>
     58  1.1  rkujawa 
     59  1.1  rkujawa #include <powerpc/mpc5200/obiovar.h>
     60  1.1  rkujawa #include <powerpc/mpc5200/mpc5200reg.h>
     61  1.1  rkujawa #include <powerpc/mpc5200/fecreg.h>
     62  1.1  rkujawa #include <powerpc/mpc5200/fecvar.h>
     63  1.1  rkujawa #include <powerpc/mpc5200/cdmvar.h>
     64  1.1  rkujawa #include <powerpc/mpc5200/bestcommvar.h>
     65  1.1  rkujawa 
     66  1.1  rkujawa #define	FEC_READ(sc, r)		bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (r))
     67  1.1  rkujawa #define	FEC_WRITE(sc, r, v)	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
     68  1.1  rkujawa 
     69  1.1  rkujawa #define	FEC_RX_TASK		3	/* TASK_FEC_RX image slot	*/
     70  1.1  rkujawa #define	FEC_TX_TASK		2	/* TASK_FEC_TX image slot	*/
     71  1.1  rkujawa #define	FEC_RX_INITIATOR	3	/* INITIATOR_FEC_RX		*/
     72  1.1  rkujawa #define	FEC_TX_INITIATOR	4	/* INITIATOR_FEC_TX		*/
     73  1.1  rkujawa 
     74  1.1  rkujawa static const struct bestcomm_bd_layout fec_rx_layout = BESTCOMM_LAYOUT_FEC_RX;
     75  1.1  rkujawa static const struct bestcomm_bd_layout fec_tx_layout = BESTCOMM_LAYOUT_FEC_TX;
     76  1.1  rkujawa 
     77  1.1  rkujawa static int	fec_match(device_t, cfdata_t, void *);
     78  1.1  rkujawa static void	fec_attach(device_t, device_t, void *);
     79  1.1  rkujawa 
     80  1.1  rkujawa static int	fec_miibus_readreg(device_t, int, int, uint16_t *);
     81  1.1  rkujawa static int	fec_miibus_writereg(device_t, int, int, uint16_t);
     82  1.1  rkujawa static void	fec_miibus_statchg(struct ifnet *);
     83  1.1  rkujawa 
     84  1.1  rkujawa static int	fec_ioctl(struct ifnet *, u_long, void *);
     85  1.1  rkujawa static int	fec_init(struct ifnet *);
     86  1.1  rkujawa static void	fec_stop(struct ifnet *, int);
     87  1.1  rkujawa static void	fec_start(struct ifnet *);
     88  1.1  rkujawa static void	fec_tick(void *);
     89  1.1  rkujawa 
     90  1.1  rkujawa static void	fec_reset(struct fec_softc *);
     91  1.1  rkujawa static void	fec_mac_setup(struct fec_softc *);
     92  1.2  rkujawa static void	fec_set_filter(struct fec_softc *);
     93  1.2  rkujawa static void	fec_mib_sync(struct fec_softc *, bool);
     94  1.1  rkujawa static int	fec_newbuf(struct fec_softc *, u_int);
     95  1.1  rkujawa static int	fec_intr(void *);
     96  1.1  rkujawa static int	fec_rxintr(void *);
     97  1.1  rkujawa static int	fec_txintr(void *);
     98  1.1  rkujawa 
     99  1.1  rkujawa CFATTACH_DECL_NEW(fec, sizeof(struct fec_softc),
    100  1.1  rkujawa     fec_match, fec_attach, NULL, NULL);
    101  1.1  rkujawa 
    102  1.1  rkujawa static int
    103  1.1  rkujawa fec_match(device_t parent, cfdata_t cf, void *aux)
    104  1.1  rkujawa {
    105  1.1  rkujawa 	struct obio_attach_args *oba = aux;
    106  1.1  rkujawa 	char compat[40];
    107  1.1  rkujawa 	int len;
    108  1.1  rkujawa 
    109  1.1  rkujawa 	if (strcmp(oba->obio_name, "ethernet") == 0)
    110  1.1  rkujawa 		return 1;
    111  1.1  rkujawa 
    112  1.1  rkujawa 	len = OF_getprop(oba->obio_node, "compatible", compat, sizeof(compat));
    113  1.1  rkujawa 	if (len > 0 &&
    114  1.1  rkujawa 	    (strcmp(compat, "mpc5200-fec") == 0 ||
    115  1.1  rkujawa 	     strcmp(compat, "mpc5200b-fec") == 0))
    116  1.1  rkujawa 		return 1;
    117  1.1  rkujawa 
    118  1.1  rkujawa 	return 0;
    119  1.1  rkujawa }
    120  1.1  rkujawa 
    121  1.1  rkujawa static void
    122  1.1  rkujawa fec_attach(device_t parent, device_t self, void *aux)
    123  1.1  rkujawa {
    124  1.1  rkujawa 	struct fec_softc *sc = device_private(self);
    125  1.1  rkujawa 	struct obio_attach_args *oba = aux;
    126  1.1  rkujawa 	struct ifnet *ifp = &sc->sc_if;
    127  1.1  rkujawa 	struct mii_data *mii = &sc->sc_mii;
    128  1.1  rkujawa 	uint8_t enaddr[ETHER_ADDR_LEN];
    129  1.1  rkujawa 	bus_size_t size;
    130  1.1  rkujawa 	int ist;
    131  1.1  rkujawa 
    132  1.1  rkujawa 	sc->sc_dev = self;
    133  1.1  rkujawa 	sc->sc_iot = oba->obio_bst;
    134  1.1  rkujawa 	sc->sc_dmat = oba->obio_dmat;
    135  1.1  rkujawa 	sc->sc_pa = oba->obio_addr;
    136  1.1  rkujawa 	callout_init(&sc->sc_tick_ch, 0);
    137  1.1  rkujawa 	callout_setfunc(&sc->sc_tick_ch, fec_tick, sc);
    138  1.1  rkujawa 
    139  1.1  rkujawa 	size = oba->obio_size != 0 ? oba->obio_size : FEC_REG_SIZE;
    140  1.1  rkujawa 	if (bus_space_map(sc->sc_iot, oba->obio_addr, size, 0,
    141  1.1  rkujawa 	    &sc->sc_ioh) != 0) {
    142  1.1  rkujawa 		aprint_error(": can't map registers\n");
    143  1.1  rkujawa 		return;
    144  1.1  rkujawa 	}
    145  1.1  rkujawa 
    146  1.1  rkujawa 	if (OF_getprop(oba->obio_node, "local-mac-address", enaddr,
    147  1.1  rkujawa 	    sizeof(enaddr)) != sizeof(enaddr) &&
    148  1.1  rkujawa 	    OF_getprop(oba->obio_node, "mac-address", enaddr,
    149  1.1  rkujawa 	    sizeof(enaddr)) != sizeof(enaddr)) {
    150  1.1  rkujawa 		aprint_error(": no MAC address\n");
    151  1.1  rkujawa 		return;
    152  1.1  rkujawa 	}
    153  1.1  rkujawa 	memcpy(sc->sc_enaddr, enaddr, ETHER_ADDR_LEN);
    154  1.1  rkujawa 
    155  1.1  rkujawa 	if (obio_decode_interrupt(oba->obio_node, 0, &sc->sc_irq, &ist))
    156  1.1  rkujawa 		sc->sc_ih = intr_establish(sc->sc_irq, ist, IPL_NET,
    157  1.1  rkujawa 		    fec_intr, sc);
    158  1.1  rkujawa 
    159  1.1  rkujawa 	aprint_normal(": MPC5200 FEC, address %s\n",
    160  1.1  rkujawa 	    ether_sprintf(sc->sc_enaddr));
    161  1.1  rkujawa 
    162  1.1  rkujawa 	/* Reset the controller and program the MII management clock. */
    163  1.1  rkujawa 	sc->sc_ipb_freq = mpc5200_cdm_get_ipb_freq();
    164  1.1  rkujawa 	fec_reset(sc);
    165  1.1  rkujawa 
    166  1.1  rkujawa 	/* MII / PHY. */
    167  1.1  rkujawa 	mii->mii_ifp = ifp;
    168  1.1  rkujawa 	mii->mii_readreg = fec_miibus_readreg;
    169  1.1  rkujawa 	mii->mii_writereg = fec_miibus_writereg;
    170  1.1  rkujawa 	mii->mii_statchg = fec_miibus_statchg;
    171  1.1  rkujawa 	sc->sc_ec.ec_mii = mii;
    172  1.1  rkujawa 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
    173  1.2  rkujawa 	/* MIIF_DOPAUSE: advertise 802.3 PAUSE so we can honour rx flow control. */
    174  1.2  rkujawa 	mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
    175  1.2  rkujawa 	    MIIF_DOPAUSE);
    176  1.1  rkujawa 	if (LIST_FIRST(&mii->mii_phys) == NULL) {
    177  1.1  rkujawa 		aprint_error_dev(self, "no PHY found\n");
    178  1.1  rkujawa 		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
    179  1.1  rkujawa 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL);
    180  1.1  rkujawa 	} else
    181  1.1  rkujawa 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
    182  1.1  rkujawa 
    183  1.2  rkujawa 	/* The controller accepts VLAN-sized frames (see fec_mac_setup()). */
    184  1.2  rkujawa 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
    185  1.2  rkujawa 
    186  1.1  rkujawa 	strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
    187  1.1  rkujawa 	ifp->if_softc = sc;
    188  1.1  rkujawa 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    189  1.1  rkujawa 	ifp->if_init = fec_init;
    190  1.1  rkujawa 	ifp->if_stop = fec_stop;
    191  1.1  rkujawa 	ifp->if_start = fec_start;
    192  1.1  rkujawa 	ifp->if_ioctl = fec_ioctl;
    193  1.1  rkujawa 	IFQ_SET_READY(&ifp->if_snd);
    194  1.1  rkujawa 
    195  1.1  rkujawa 	if_attach(ifp);
    196  1.1  rkujawa 	if_deferred_start_init(ifp, NULL);
    197  1.1  rkujawa 	ether_ifattach(ifp, sc->sc_enaddr);
    198  1.1  rkujawa }
    199  1.1  rkujawa 
    200  1.1  rkujawa /*
    201  1.1  rkujawa  * Soft-reset the controller and set the MII management clock divider so MDC
    202  1.1  rkujawa  * stays at or below 2.5 MHz, derived from the IPB clock.
    203  1.1  rkujawa  */
    204  1.1  rkujawa static void
    205  1.1  rkujawa fec_reset(struct fec_softc *sc)
    206  1.1  rkujawa {
    207  1.1  rkujawa 	uint32_t div;
    208  1.1  rkujawa 	int i;
    209  1.1  rkujawa 
    210  1.1  rkujawa 	FEC_WRITE(sc, FEC_ECNTRL, FEC_ECNTRL_RESET);
    211  1.1  rkujawa 	for (i = 0; i < 1000; i++) {
    212  1.1  rkujawa 		if ((FEC_READ(sc, FEC_ECNTRL) & FEC_ECNTRL_RESET) == 0)
    213  1.1  rkujawa 			break;
    214  1.1  rkujawa 		DELAY(10);
    215  1.1  rkujawa 	}
    216  1.1  rkujawa 	FEC_WRITE(sc, FEC_IMASK, 0);			/* mask all events */
    217  1.1  rkujawa 	FEC_WRITE(sc, FEC_IEVENT, 0xffffffff);		/* clear events	 */
    218  1.1  rkujawa 
    219  1.1  rkujawa 	div = howmany(sc->sc_ipb_freq, 2 * FEC_MII_MAX_CLK);
    220  1.1  rkujawa 	if (div > 0x3f)
    221  1.1  rkujawa 		div = 0x3f;
    222  1.1  rkujawa 	FEC_WRITE(sc, FEC_MII_SPEED, FEC_MII_SPEED_DIV(div));
    223  1.1  rkujawa }
    224  1.1  rkujawa 
    225  1.1  rkujawa static int
    226  1.1  rkujawa fec_mii_wait(struct fec_softc *sc)
    227  1.1  rkujawa {
    228  1.1  rkujawa 	int i;
    229  1.1  rkujawa 
    230  1.1  rkujawa 	for (i = 0; i < FEC_PHY_TIMEOUT; i++) {
    231  1.1  rkujawa 		if (FEC_READ(sc, FEC_IEVENT) & FEC_INT_MII) {
    232  1.1  rkujawa 			FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
    233  1.1  rkujawa 			return 0;
    234  1.1  rkujawa 		}
    235  1.1  rkujawa 		DELAY(10);
    236  1.1  rkujawa 	}
    237  1.1  rkujawa 	return ETIMEDOUT;
    238  1.1  rkujawa }
    239  1.1  rkujawa 
    240  1.1  rkujawa static int
    241  1.1  rkujawa fec_miibus_readreg(device_t self, int phy, int reg, uint16_t *val)
    242  1.1  rkujawa {
    243  1.1  rkujawa 	struct fec_softc *sc = device_private(self);
    244  1.1  rkujawa 
    245  1.1  rkujawa 	FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
    246  1.1  rkujawa 	FEC_WRITE(sc, FEC_MII_DATA, FEC_MII_READ(phy, reg));
    247  1.1  rkujawa 	if (fec_mii_wait(sc) != 0)
    248  1.1  rkujawa 		return ETIMEDOUT;
    249  1.1  rkujawa 
    250  1.1  rkujawa 	*val = FEC_READ(sc, FEC_MII_DATA) & FEC_MII_DATA_MASK;
    251  1.1  rkujawa 	return 0;
    252  1.1  rkujawa }
    253  1.1  rkujawa 
    254  1.1  rkujawa static int
    255  1.1  rkujawa fec_miibus_writereg(device_t self, int phy, int reg, uint16_t val)
    256  1.1  rkujawa {
    257  1.1  rkujawa 	struct fec_softc *sc = device_private(self);
    258  1.1  rkujawa 
    259  1.1  rkujawa 	FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
    260  1.1  rkujawa 	FEC_WRITE(sc, FEC_MII_DATA, FEC_MII_WRITE(phy, reg, val));
    261  1.1  rkujawa 	return fec_mii_wait(sc);
    262  1.1  rkujawa }
    263  1.1  rkujawa 
    264  1.1  rkujawa static void
    265  1.1  rkujawa fec_miibus_statchg(struct ifnet *ifp)
    266  1.1  rkujawa {
    267  1.1  rkujawa 	struct fec_softc *sc = ifp->if_softc;
    268  1.2  rkujawa 	uint32_t xcr, rcr;
    269  1.1  rkujawa 
    270  1.1  rkujawa 	xcr = FEC_READ(sc, FEC_X_CNTRL);
    271  1.1  rkujawa 	if (sc->sc_mii.mii_media_active & IFM_FDX)
    272  1.1  rkujawa 		xcr |= FEC_X_CNTRL_FDEN;
    273  1.1  rkujawa 	else
    274  1.1  rkujawa 		xcr &= ~FEC_X_CNTRL_FDEN;
    275  1.1  rkujawa 	FEC_WRITE(sc, FEC_X_CNTRL, xcr);
    276  1.2  rkujawa 
    277  1.2  rkujawa 	rcr = FEC_READ(sc, FEC_R_CNTRL);
    278  1.2  rkujawa 	if (sc->sc_mii.mii_media_active & IFM_ETH_RXPAUSE)
    279  1.2  rkujawa 		rcr |= FEC_R_CNTRL_FCE;
    280  1.2  rkujawa 	else
    281  1.2  rkujawa 		rcr &= ~FEC_R_CNTRL_FCE;
    282  1.2  rkujawa 	FEC_WRITE(sc, FEC_R_CNTRL, rcr);
    283  1.1  rkujawa }
    284  1.1  rkujawa 
    285  1.1  rkujawa static void
    286  1.1  rkujawa fec_tick(void *arg)
    287  1.1  rkujawa {
    288  1.1  rkujawa 	struct fec_softc *sc = arg;
    289  1.1  rkujawa 	int s;
    290  1.1  rkujawa 
    291  1.1  rkujawa 	s = splnet();
    292  1.1  rkujawa 	mii_tick(&sc->sc_mii);
    293  1.2  rkujawa 	if (sc->sc_if.if_flags & IFF_RUNNING)
    294  1.2  rkujawa 		fec_mib_sync(sc, false);	/* fold hw counters into if_stats */
    295  1.1  rkujawa 	splx(s);
    296  1.1  rkujawa 
    297  1.1  rkujawa 	/*
    298  1.1  rkujawa 	 * Meh. Under load the receive FIFO can overrun, work it around.
    299  1.1  rkujawa 	 */
    300  1.1  rkujawa 	if ((sc->sc_if.if_flags & IFF_RUNNING) &&
    301  1.1  rkujawa 	    (FEC_READ(sc, FEC_ECNTRL) & FEC_ECNTRL_ETHER_EN) == 0) {
    302  1.1  rkujawa 		if_statinc(&sc->sc_if, if_ierrors);
    303  1.1  rkujawa 		aprint_error_dev(sc->sc_dev,
    304  1.1  rkujawa 		    "ETHER_EN cleared, resetting\n");
    305  1.1  rkujawa 		s = splnet();
    306  1.1  rkujawa 		(void)fec_init(&sc->sc_if);	/* reschedules the callout */
    307  1.1  rkujawa 		splx(s);
    308  1.1  rkujawa 		return;
    309  1.1  rkujawa 	}
    310  1.1  rkujawa 
    311  1.1  rkujawa 	callout_schedule(&sc->sc_tick_ch, hz);
    312  1.1  rkujawa }
    313  1.1  rkujawa 
    314  1.1  rkujawa /* Program the station address and receive/transmit MAC control. */
    315  1.1  rkujawa static void
    316  1.1  rkujawa fec_mac_setup(struct fec_softc *sc)
    317  1.1  rkujawa {
    318  1.1  rkujawa 	FEC_WRITE(sc, FEC_PADDR1,
    319  1.1  rkujawa 	    (sc->sc_enaddr[0] << 24) | (sc->sc_enaddr[1] << 16) |
    320  1.1  rkujawa 	    (sc->sc_enaddr[2] << 8) | sc->sc_enaddr[3]);
    321  1.1  rkujawa 	FEC_WRITE(sc, FEC_PADDR2,
    322  1.1  rkujawa 	    (sc->sc_enaddr[4] << 24) | (sc->sc_enaddr[5] << 16) | 0x8808);
    323  1.1  rkujawa 	FEC_WRITE(sc, FEC_IADDR1, 0);
    324  1.1  rkujawa 	FEC_WRITE(sc, FEC_IADDR2, 0);
    325  1.1  rkujawa 	/*
    326  1.2  rkujawa 	 * Allow VLAN-tagged frames (ETHERCAP_VLAN_MTU)
    327  1.1  rkujawa 	 */
    328  1.1  rkujawa 	FEC_WRITE(sc, FEC_R_CNTRL,
    329  1.2  rkujawa 	    FEC_R_CNTRL_MAX_FL(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN) |
    330  1.2  rkujawa 	    FEC_R_CNTRL_MII_MODE);
    331  1.1  rkujawa 	FEC_WRITE(sc, FEC_X_CNTRL, FEC_X_CNTRL_FDEN);
    332  1.1  rkujawa 
    333  1.1  rkujawa 	/*
    334  1.1  rkujawa 	 * Enable frame mode on both FIFOs
    335  1.1  rkujawa 	 */
    336  1.1  rkujawa 	FEC_WRITE(sc, FEC_RESET_CNTRL, FEC_RESET_CNTRL_FIFO_EN);
    337  1.1  rkujawa 
    338  1.1  rkujawa 	FEC_WRITE(sc, FEC_RFIFO_CONTROL, FEC_FIFO_CTRL_INIT);
    339  1.1  rkujawa 	FEC_WRITE(sc, FEC_TFIFO_CONTROL, FEC_FIFO_CTRL_INIT);
    340  1.1  rkujawa 
    341  1.1  rkujawa 	/*
    342  1.1  rkujawa 	 * The transmit FIFO requests data from BestComm only while it holds
    343  1.1  rkujawa 	 * fewer than "alarm" bytes!
    344  1.1  rkujawa 	 */
    345  1.1  rkujawa 	FEC_WRITE(sc, FEC_TFIFO_ALARM, 0x80);
    346  1.1  rkujawa }
    347  1.1  rkujawa 
    348  1.2  rkujawa /*
    349  1.2  rkujawa  * Program the receive address filter
    350  1.2  rkujawa  */
    351  1.2  rkujawa static void
    352  1.2  rkujawa fec_set_filter(struct fec_softc *sc)
    353  1.2  rkujawa {
    354  1.2  rkujawa 	struct ethercom *ec = &sc->sc_ec;
    355  1.2  rkujawa 	struct ifnet *ifp = &sc->sc_if;
    356  1.2  rkujawa 	struct ether_multi *enm;
    357  1.2  rkujawa 	struct ether_multistep step;
    358  1.2  rkujawa 	uint32_t gaddr[2] = { 0, 0 };
    359  1.2  rkujawa 	uint32_t rcr;
    360  1.2  rkujawa 	u_int h;
    361  1.2  rkujawa 
    362  1.2  rkujawa 	rcr = FEC_READ(sc, FEC_R_CNTRL) & ~FEC_R_CNTRL_PROM;
    363  1.2  rkujawa 
    364  1.2  rkujawa 	if (ifp->if_flags & IFF_PROMISC) {
    365  1.2  rkujawa 		rcr |= FEC_R_CNTRL_PROM;
    366  1.2  rkujawa 		gaddr[0] = gaddr[1] = 0xffffffff;
    367  1.2  rkujawa 		goto done;
    368  1.2  rkujawa 	}
    369  1.2  rkujawa 
    370  1.2  rkujawa 	ETHER_LOCK(ec);
    371  1.2  rkujawa 	ec->ec_flags &= ~ETHER_F_ALLMULTI;
    372  1.2  rkujawa 	ETHER_FIRST_MULTI(step, ec, enm);
    373  1.2  rkujawa 	while (enm != NULL) {
    374  1.2  rkujawa 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
    375  1.2  rkujawa 		    ETHER_ADDR_LEN) != 0) {
    376  1.2  rkujawa 			/*
    377  1.2  rkujawa 			 * A range of addresses
    378  1.2  rkujawa 			 */
    379  1.2  rkujawa 			ec->ec_flags |= ETHER_F_ALLMULTI;
    380  1.2  rkujawa 			gaddr[0] = gaddr[1] = 0xffffffff;
    381  1.2  rkujawa 			break;
    382  1.2  rkujawa 		}
    383  1.2  rkujawa 		h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
    384  1.2  rkujawa 		gaddr[h >> 5] |= 1U << (h & 0x1f);
    385  1.2  rkujawa 		ETHER_NEXT_MULTI(step, enm);
    386  1.2  rkujawa 	}
    387  1.2  rkujawa 	ETHER_UNLOCK(ec);
    388  1.2  rkujawa 
    389  1.2  rkujawa done:
    390  1.2  rkujawa 	FEC_WRITE(sc, FEC_GADDR1, gaddr[1]);	/* buckets 32..63 */
    391  1.2  rkujawa 	FEC_WRITE(sc, FEC_GADDR2, gaddr[0]);	/* buckets  0..31 */
    392  1.2  rkujawa 	FEC_WRITE(sc, FEC_R_CNTRL, rcr);
    393  1.2  rkujawa }
    394  1.2  rkujawa 
    395  1.2  rkujawa /*
    396  1.2  rkujawa  * On-chip counters we dump into the interface stats.
    397  1.2  rkujawa  */
    398  1.2  rkujawa static const struct fec_mibcnt {
    399  1.2  rkujawa 	bus_size_t	reg;
    400  1.2  rkujawa 	if_stat_t	stat;
    401  1.2  rkujawa } fec_mibtab[] = {
    402  1.2  rkujawa 	{ FEC_RMON_T_COL,    if_collisions },
    403  1.2  rkujawa 	{ FEC_IEEE_T_LCOL,   if_oerrors },
    404  1.2  rkujawa 	{ FEC_IEEE_T_EXCOL,  if_oerrors },
    405  1.2  rkujawa 	{ FEC_IEEE_T_MACERR, if_oerrors },	/* Tx FIFO underrun	*/
    406  1.2  rkujawa 	{ FEC_IEEE_R_DROP,   if_iqdrops },
    407  1.2  rkujawa 	{ FEC_IEEE_R_CRC,    if_ierrors },
    408  1.2  rkujawa 	{ FEC_IEEE_R_ALIGN,  if_ierrors },
    409  1.2  rkujawa 	{ FEC_IEEE_R_MACERR, if_iqdrops },	/* Rx FIFO overflow	*/
    410  1.2  rkujawa };
    411  1.2  rkujawa __CTASSERT(__arraycount(fec_mibtab) == FEC_NMIB);
    412  1.2  rkujawa 
    413  1.2  rkujawa /*
    414  1.2  rkujawa  * Harvest the on-chip MIB counters.
    415  1.2  rkujawa  */
    416  1.2  rkujawa static void
    417  1.2  rkujawa fec_mib_sync(struct fec_softc *sc, bool prime)
    418  1.2  rkujawa {
    419  1.2  rkujawa 	struct ifnet *ifp = &sc->sc_if;
    420  1.2  rkujawa 	net_stat_ref_t nsr;
    421  1.2  rkujawa 	u_int i;
    422  1.2  rkujawa 
    423  1.2  rkujawa 	if (prime) {
    424  1.2  rkujawa 		for (i = 0; i < FEC_NMIB; i++)
    425  1.2  rkujawa 			sc->sc_mib_prev[i] = FEC_READ(sc, fec_mibtab[i].reg);
    426  1.2  rkujawa 		return;
    427  1.2  rkujawa 	}
    428  1.2  rkujawa 
    429  1.2  rkujawa 	nsr = IF_STAT_GETREF(ifp);
    430  1.2  rkujawa 	for (i = 0; i < FEC_NMIB; i++) {
    431  1.2  rkujawa 		uint32_t cur = FEC_READ(sc, fec_mibtab[i].reg);
    432  1.2  rkujawa 		uint32_t delta = cur - sc->sc_mib_prev[i];	/* wraps mod 2^32 */
    433  1.2  rkujawa 
    434  1.2  rkujawa 		if (delta != 0)
    435  1.2  rkujawa 			if_statadd_ref(ifp, nsr, fec_mibtab[i].stat, delta);
    436  1.2  rkujawa 		sc->sc_mib_prev[i] = cur;
    437  1.2  rkujawa 	}
    438  1.2  rkujawa 	IF_STAT_PUTREF(ifp);
    439  1.2  rkujawa }
    440  1.2  rkujawa 
    441  1.1  rkujawa /* Allocate a cluster for receive descriptor idx and hand it to the engine. */
    442  1.1  rkujawa static int
    443  1.1  rkujawa fec_newbuf(struct fec_softc *sc, u_int idx)
    444  1.1  rkujawa {
    445  1.1  rkujawa 	struct mbuf *m;
    446  1.1  rkujawa 	int error;
    447  1.1  rkujawa 
    448  1.1  rkujawa 	MGETHDR(m, M_DONTWAIT, MT_DATA);
    449  1.1  rkujawa 	if (m == NULL)
    450  1.1  rkujawa 		return ENOBUFS;
    451  1.1  rkujawa 	MCLGET(m, M_DONTWAIT);
    452  1.1  rkujawa 	if ((m->m_flags & M_EXT) == 0) {
    453  1.1  rkujawa 		m_freem(m);
    454  1.1  rkujawa 		return ENOBUFS;
    455  1.1  rkujawa 	}
    456  1.1  rkujawa 	m->m_len = m->m_pkthdr.len = MCLBYTES;
    457  1.1  rkujawa 	error = bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_rxmap[idx], m,
    458  1.1  rkujawa 	    BUS_DMA_NOWAIT | BUS_DMA_READ);
    459  1.1  rkujawa 	if (error) {
    460  1.1  rkujawa 		m_freem(m);
    461  1.1  rkujawa 		return error;
    462  1.1  rkujawa 	}
    463  1.1  rkujawa 	bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0, MCLBYTES,
    464  1.1  rkujawa 	    BUS_DMASYNC_PREREAD);
    465  1.1  rkujawa 	sc->sc_rxmbuf[idx] = m;
    466  1.1  rkujawa 	bestcomm_bd_post(&sc->sc_rxring, idx,
    467  1.1  rkujawa 	    sc->sc_rxmap[idx]->dm_segs[0].ds_addr, MCLBYTES, 0);
    468  1.1  rkujawa 	return 0;
    469  1.1  rkujawa }
    470  1.1  rkujawa 
    471  1.1  rkujawa static int
    472  1.1  rkujawa fec_init(struct ifnet *ifp)
    473  1.1  rkujawa {
    474  1.1  rkujawa 	struct fec_softc *sc = ifp->if_softc;
    475  1.1  rkujawa 	u_int i;
    476  1.1  rkujawa 	int error;
    477  1.2  rkujawa 	bool link_up;
    478  1.2  rkujawa 
    479  1.2  rkujawa 	link_up = (sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0;
    480  1.1  rkujawa 
    481  1.1  rkujawa 	fec_stop(ifp, 0);
    482  1.1  rkujawa 
    483  1.1  rkujawa 	if (!bestcomm_available()) {
    484  1.1  rkujawa 		aprint_error_ifnet(ifp, "BestComm SDMA not available\n");
    485  1.1  rkujawa 		return ENXIO;
    486  1.1  rkujawa 	}
    487  1.1  rkujawa 
    488  1.1  rkujawa 	fec_reset(sc);
    489  1.1  rkujawa 	fec_mac_setup(sc);
    490  1.2  rkujawa 	fec_set_filter(sc);
    491  1.2  rkujawa 
    492  1.2  rkujawa 	/*
    493  1.2  rkujawa 	 * Enable the on-chip MIB counter block
    494  1.2  rkujawa 	 */
    495  1.2  rkujawa 	FEC_WRITE(sc, FEC_MIB_CONTROL, 0);
    496  1.2  rkujawa 	fec_mib_sync(sc, true);
    497  1.1  rkujawa 
    498  1.1  rkujawa 	if (bestcomm_bd_setup(&sc->sc_rxring, FEC_RX_TASK, &fec_rx_layout,
    499  1.1  rkujawa 	    sc->sc_pa + FEC_RFIFO_DATA, FEC_NRXDESC, MCLBYTES, 4,
    500  1.1  rkujawa 	    FEC_RX_INITIATOR, 6) != 0 ||
    501  1.1  rkujawa 	    bestcomm_bd_setup(&sc->sc_txring, FEC_TX_TASK, &fec_tx_layout,
    502  1.1  rkujawa 	    sc->sc_pa + FEC_TFIFO_DATA, FEC_NTXDESC, MCLBYTES, 4,
    503  1.1  rkujawa 	    FEC_TX_INITIATOR, 5) != 0) {
    504  1.1  rkujawa 		aprint_error_ifnet(ifp, "cannot set up SDMA rings\n");
    505  1.2  rkujawa 		error = ENOMEM;
    506  1.2  rkujawa 		goto fail;
    507  1.1  rkujawa 	}
    508  1.1  rkujawa 
    509  1.1  rkujawa 	for (i = 0; i < FEC_NRXDESC; i++) {
    510  1.1  rkujawa 		if (sc->sc_rxmap[i] == NULL &&
    511  1.1  rkujawa 		    bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
    512  1.2  rkujawa 		    BUS_DMA_NOWAIT, &sc->sc_rxmap[i]) != 0) {
    513  1.2  rkujawa 			error = ENOMEM;
    514  1.2  rkujawa 			goto fail;
    515  1.2  rkujawa 		}
    516  1.1  rkujawa 		if ((error = fec_newbuf(sc, i)) != 0)
    517  1.2  rkujawa 			goto fail;
    518  1.1  rkujawa 	}
    519  1.1  rkujawa 	for (i = 0; i < FEC_NTXDESC; i++) {
    520  1.1  rkujawa 		if (sc->sc_txmap[i] == NULL &&
    521  1.1  rkujawa 		    bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
    522  1.2  rkujawa 		    BUS_DMA_NOWAIT, &sc->sc_txmap[i]) != 0) {
    523  1.2  rkujawa 			error = ENOMEM;
    524  1.2  rkujawa 			goto fail;
    525  1.2  rkujawa 		}
    526  1.1  rkujawa 	}
    527  1.1  rkujawa 	sc->sc_rxptr = 0;
    528  1.1  rkujawa 	sc->sc_txnext = sc->sc_txdirty = sc->sc_txbusy = 0;
    529  1.1  rkujawa 
    530  1.1  rkujawa 	/* Hook the BestComm task-completion interrupts (via the SIU cascade). */
    531  1.1  rkujawa 	sc->sc_rxih = intr_establish(bestcomm_task_irq(FEC_RX_TASK), IST_LEVEL,
    532  1.1  rkujawa 	    IPL_NET, fec_rxintr, sc);
    533  1.1  rkujawa 	sc->sc_txih = intr_establish(bestcomm_task_irq(FEC_TX_TASK), IST_LEVEL,
    534  1.1  rkujawa 	    IPL_NET, fec_txintr, sc);
    535  1.1  rkujawa 
    536  1.1  rkujawa 	/*
    537  1.1  rkujawa 	 * Bring the link up before enabling the controller.
    538  1.1  rkujawa 	 */
    539  1.1  rkujawa 	mii_mediachg(&sc->sc_mii);
    540  1.2  rkujawa 	if (!link_up) {
    541  1.2  rkujawa 		for (i = 0; i < 500; i++) {
    542  1.2  rkujawa 			mii_pollstat(&sc->sc_mii);
    543  1.2  rkujawa 			if (sc->sc_mii.mii_media_status & IFM_ACTIVE)
    544  1.2  rkujawa 				break;
    545  1.2  rkujawa 			DELAY(10000);
    546  1.2  rkujawa 		}
    547  1.1  rkujawa 	}
    548  1.1  rkujawa 
    549  1.1  rkujawa 	FEC_WRITE(sc, FEC_ECNTRL, FEC_ECNTRL_ETHER_EN);
    550  1.1  rkujawa 	bestcomm_task_start(FEC_RX_TASK);
    551  1.1  rkujawa 	bestcomm_task_start(FEC_TX_TASK);
    552  1.1  rkujawa 
    553  1.1  rkujawa 	ifp->if_flags |= IFF_RUNNING;
    554  1.1  rkujawa 	ifp->if_flags &= ~IFF_OACTIVE;
    555  1.1  rkujawa 
    556  1.1  rkujawa 	callout_schedule(&sc->sc_tick_ch, hz);
    557  1.1  rkujawa 	return 0;
    558  1.2  rkujawa 
    559  1.2  rkujawa fail:
    560  1.2  rkujawa 	/* Unwind any partial setup so we leave a clean, fully-stopped state. */
    561  1.2  rkujawa 	fec_stop(ifp, 1);
    562  1.2  rkujawa 	return error;
    563  1.1  rkujawa }
    564  1.1  rkujawa 
    565  1.1  rkujawa static void
    566  1.1  rkujawa fec_stop(struct ifnet *ifp, int disable)
    567  1.1  rkujawa {
    568  1.1  rkujawa 	struct fec_softc *sc = ifp->if_softc;
    569  1.1  rkujawa 	u_int i;
    570  1.1  rkujawa 
    571  1.1  rkujawa 	callout_stop(&sc->sc_tick_ch);
    572  1.1  rkujawa 
    573  1.2  rkujawa 	/*
    574  1.2  rkujawa 	 * Stop the SDMA tasks and release their buffer-descriptor rings back
    575  1.2  rkujawa 	 * to the on-chip SRAM pool.
    576  1.2  rkujawa 	 */
    577  1.2  rkujawa 	bestcomm_bd_teardown(&sc->sc_rxring);
    578  1.2  rkujawa 	bestcomm_bd_teardown(&sc->sc_txring);
    579  1.2  rkujawa 
    580  1.1  rkujawa 	FEC_WRITE(sc, FEC_ECNTRL, 0);
    581  1.1  rkujawa 
    582  1.1  rkujawa 	if (sc->sc_rxih != NULL) {
    583  1.1  rkujawa 		intr_disestablish(sc->sc_rxih);
    584  1.1  rkujawa 		sc->sc_rxih = NULL;
    585  1.1  rkujawa 	}
    586  1.1  rkujawa 	if (sc->sc_txih != NULL) {
    587  1.1  rkujawa 		intr_disestablish(sc->sc_txih);
    588  1.1  rkujawa 		sc->sc_txih = NULL;
    589  1.1  rkujawa 	}
    590  1.1  rkujawa 
    591  1.1  rkujawa 	mii_down(&sc->sc_mii);
    592  1.1  rkujawa 
    593  1.1  rkujawa 	for (i = 0; i < FEC_NRXDESC; i++) {
    594  1.1  rkujawa 		if (sc->sc_rxmbuf[i] != NULL) {
    595  1.1  rkujawa 			bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]);
    596  1.1  rkujawa 			m_freem(sc->sc_rxmbuf[i]);
    597  1.1  rkujawa 			sc->sc_rxmbuf[i] = NULL;
    598  1.1  rkujawa 		}
    599  1.1  rkujawa 	}
    600  1.1  rkujawa 	for (i = 0; i < FEC_NTXDESC; i++) {
    601  1.1  rkujawa 		if (sc->sc_txmbuf[i] != NULL) {
    602  1.1  rkujawa 			bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
    603  1.1  rkujawa 			m_freem(sc->sc_txmbuf[i]);
    604  1.1  rkujawa 			sc->sc_txmbuf[i] = NULL;
    605  1.1  rkujawa 		}
    606  1.1  rkujawa 	}
    607  1.1  rkujawa 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
    608  1.1  rkujawa }
    609  1.1  rkujawa 
    610  1.1  rkujawa static void
    611  1.1  rkujawa fec_start(struct ifnet *ifp)
    612  1.1  rkujawa {
    613  1.1  rkujawa 	struct fec_softc *sc = ifp->if_softc;
    614  1.1  rkujawa 	struct mbuf *m, *mn;
    615  1.1  rkujawa 	u_int idx;
    616  1.1  rkujawa 	int error, posted = 0;
    617  1.1  rkujawa 
    618  1.1  rkujawa 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
    619  1.1  rkujawa 		return;
    620  1.1  rkujawa 
    621  1.1  rkujawa 	while (sc->sc_txbusy < FEC_NTXDESC) {
    622  1.1  rkujawa 		IFQ_POLL(&ifp->if_snd, m);
    623  1.1  rkujawa 		if (m == NULL)
    624  1.1  rkujawa 			break;
    625  1.1  rkujawa 		idx = sc->sc_txnext;
    626  1.1  rkujawa 
    627  1.1  rkujawa 		error = bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_txmap[idx], m,
    628  1.1  rkujawa 		    BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    629  1.1  rkujawa 		if (error == EFBIG) {
    630  1.1  rkujawa 			/* The buffer descriptor holds one segment; collapse. */
    631  1.1  rkujawa 			mn = m_defrag(m, M_DONTWAIT);
    632  1.1  rkujawa 			if (mn != NULL) {
    633  1.1  rkujawa 				m = mn;
    634  1.1  rkujawa 				error = bus_dmamap_load_mbuf(sc->sc_dmat,
    635  1.1  rkujawa 				    sc->sc_txmap[idx], m,
    636  1.1  rkujawa 				    BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    637  1.1  rkujawa 			}
    638  1.1  rkujawa 		}
    639  1.1  rkujawa 		IFQ_DEQUEUE(&ifp->if_snd, m);
    640  1.1  rkujawa 		if (error) {
    641  1.1  rkujawa 			m_freem(m);
    642  1.1  rkujawa 			if_statinc(ifp, if_oerrors);
    643  1.1  rkujawa 			continue;
    644  1.1  rkujawa 		}
    645  1.1  rkujawa 
    646  1.1  rkujawa 		bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[idx], 0,
    647  1.1  rkujawa 		    m->m_pkthdr.len, BUS_DMASYNC_PREWRITE);
    648  1.1  rkujawa 		bpf_mtap(ifp, m, BPF_D_OUT);
    649  1.1  rkujawa 		sc->sc_txmbuf[idx] = m;
    650  1.1  rkujawa 		bestcomm_bd_post(&sc->sc_txring, idx,
    651  1.1  rkujawa 		    sc->sc_txmap[idx]->dm_segs[0].ds_addr, m->m_pkthdr.len,
    652  1.1  rkujawa 		    BESTCOMM_BD_FLAG_LAST | BESTCOMM_BD_FLAG_INT);
    653  1.1  rkujawa 		sc->sc_txnext = (idx + 1) % FEC_NTXDESC;
    654  1.1  rkujawa 		sc->sc_txbusy++;
    655  1.1  rkujawa 		posted = 1;
    656  1.1  rkujawa 	}
    657  1.1  rkujawa 
    658  1.1  rkujawa 	/*
    659  1.1  rkujawa 	 * (Re-)enable the transmit task.
    660  1.1  rkujawa 	 */
    661  1.1  rkujawa 	if (posted)
    662  1.1  rkujawa 		bestcomm_task_start(FEC_TX_TASK);
    663  1.1  rkujawa 
    664  1.1  rkujawa 	if (sc->sc_txbusy == FEC_NTXDESC)
    665  1.1  rkujawa 		ifp->if_flags |= IFF_OACTIVE;
    666  1.1  rkujawa }
    667  1.1  rkujawa 
    668  1.1  rkujawa /* BestComm FEC_RX task completion: hand received frames up, refill the ring. */
    669  1.1  rkujawa static int
    670  1.1  rkujawa fec_rxintr(void *arg)
    671  1.1  rkujawa {
    672  1.1  rkujawa 	struct fec_softc *sc = arg;
    673  1.1  rkujawa 	struct ifnet *ifp = &sc->sc_if;
    674  1.1  rkujawa 	struct mbuf *m;
    675  1.1  rkujawa 	uint32_t st;
    676  1.1  rkujawa 	u_int idx;
    677  1.1  rkujawa 	int len, handled = 0;
    678  1.1  rkujawa 
    679  1.1  rkujawa 	for (;;) {
    680  1.1  rkujawa 		idx = sc->sc_rxptr;
    681  1.1  rkujawa 		st = bestcomm_bd_status(&sc->sc_rxring, idx);
    682  1.1  rkujawa 		if (st & BESTCOMM_BD_READY)
    683  1.1  rkujawa 			break;
    684  1.1  rkujawa 		handled = 1;
    685  1.1  rkujawa 
    686  1.1  rkujawa 		bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0, MCLBYTES,
    687  1.1  rkujawa 		    BUS_DMASYNC_POSTREAD);
    688  1.1  rkujawa 		bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]);
    689  1.1  rkujawa 		m = sc->sc_rxmbuf[idx];
    690  1.1  rkujawa 		sc->sc_rxmbuf[idx] = NULL;
    691  1.1  rkujawa 
    692  1.1  rkujawa 		len = st & BESTCOMM_BD_LEN_MASK;
    693  1.1  rkujawa 		if (len > ETHER_CRC_LEN)
    694  1.1  rkujawa 			len -= ETHER_CRC_LEN;	/* strip FCS */
    695  1.1  rkujawa 
    696  1.1  rkujawa 		if (fec_newbuf(sc, idx) != 0) {
    697  1.1  rkujawa 			/* No replacement: recycle this buffer, drop the frame. */
    698  1.1  rkujawa 			sc->sc_rxmbuf[idx] = m;
    699  1.1  rkujawa 			(void)bus_dmamap_load_mbuf(sc->sc_dmat,
    700  1.1  rkujawa 			    sc->sc_rxmap[idx], m, BUS_DMA_NOWAIT | BUS_DMA_READ);
    701  1.1  rkujawa 			bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0,
    702  1.1  rkujawa 			    MCLBYTES, BUS_DMASYNC_PREREAD);
    703  1.1  rkujawa 			bestcomm_bd_post(&sc->sc_rxring, idx,
    704  1.1  rkujawa 			    sc->sc_rxmap[idx]->dm_segs[0].ds_addr, MCLBYTES, 0);
    705  1.1  rkujawa 			if_statinc(ifp, if_ierrors);
    706  1.1  rkujawa 		} else {
    707  1.1  rkujawa 			m_set_rcvif(m, ifp);
    708  1.1  rkujawa 			m->m_pkthdr.len = m->m_len = len;
    709  1.1  rkujawa 			if_percpuq_enqueue(ifp->if_percpuq, m);
    710  1.1  rkujawa 		}
    711  1.1  rkujawa 		sc->sc_rxptr = (idx + 1) % FEC_NRXDESC;
    712  1.1  rkujawa 	}
    713  1.1  rkujawa 
    714  1.1  rkujawa 	return handled;
    715  1.1  rkujawa }
    716  1.1  rkujawa 
    717  1.1  rkujawa /* BestComm FEC_TX task completion: reap transmitted frames. */
    718  1.1  rkujawa static int
    719  1.1  rkujawa fec_txintr(void *arg)
    720  1.1  rkujawa {
    721  1.1  rkujawa 	struct fec_softc *sc = arg;
    722  1.1  rkujawa 	struct ifnet *ifp = &sc->sc_if;
    723  1.1  rkujawa 	uint32_t st;
    724  1.1  rkujawa 	u_int idx;
    725  1.1  rkujawa 	int handled = 0;
    726  1.1  rkujawa 
    727  1.1  rkujawa 	while (sc->sc_txbusy > 0) {
    728  1.1  rkujawa 		idx = sc->sc_txdirty;
    729  1.1  rkujawa 		st = bestcomm_bd_status(&sc->sc_txring, idx);
    730  1.1  rkujawa 		if (st & BESTCOMM_BD_READY)
    731  1.1  rkujawa 			break;
    732  1.1  rkujawa 		handled = 1;
    733  1.1  rkujawa 
    734  1.1  rkujawa 		bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[idx], 0,
    735  1.1  rkujawa 		    sc->sc_txmbuf[idx]->m_pkthdr.len, BUS_DMASYNC_POSTWRITE);
    736  1.1  rkujawa 		bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[idx]);
    737  1.1  rkujawa 		m_freem(sc->sc_txmbuf[idx]);
    738  1.1  rkujawa 		sc->sc_txmbuf[idx] = NULL;
    739  1.1  rkujawa 		if_statinc(ifp, if_opackets);
    740  1.1  rkujawa 
    741  1.1  rkujawa 		sc->sc_txdirty = (idx + 1) % FEC_NTXDESC;
    742  1.1  rkujawa 		sc->sc_txbusy--;
    743  1.1  rkujawa 	}
    744  1.1  rkujawa 	if (handled) {
    745  1.1  rkujawa 		ifp->if_flags &= ~IFF_OACTIVE;
    746  1.1  rkujawa 		if_schedule_deferred_start(ifp);
    747  1.1  rkujawa 	}
    748  1.1  rkujawa 	return handled;
    749  1.1  rkujawa }
    750  1.1  rkujawa 
    751  1.1  rkujawa static int
    752  1.1  rkujawa fec_ioctl(struct ifnet *ifp, u_long cmd, void *data)
    753  1.1  rkujawa {
    754  1.2  rkujawa 	struct fec_softc *sc = ifp->if_softc;
    755  1.1  rkujawa 	int s, error;
    756  1.1  rkujawa 
    757  1.1  rkujawa 	s = splnet();
    758  1.1  rkujawa 	error = ether_ioctl(ifp, cmd, data);
    759  1.1  rkujawa 	if (error == ENETRESET) {
    760  1.1  rkujawa 		/*
    761  1.2  rkujawa 		 * The multicast list or the promiscuous flag changed.
    762  1.1  rkujawa 		 */
    763  1.2  rkujawa 		if (ifp->if_flags & IFF_RUNNING)
    764  1.2  rkujawa 			fec_set_filter(sc);
    765  1.1  rkujawa 		error = 0;
    766  1.1  rkujawa 	}
    767  1.1  rkujawa 	splx(s);
    768  1.1  rkujawa 	return error;
    769  1.1  rkujawa }
    770  1.1  rkujawa 
    771  1.1  rkujawa static int
    772  1.1  rkujawa fec_intr(void *arg)
    773  1.1  rkujawa {
    774  1.1  rkujawa 	struct fec_softc *sc = arg;
    775  1.1  rkujawa 	uint32_t ievent;
    776  1.1  rkujawa 
    777  1.1  rkujawa 	ievent = FEC_READ(sc, FEC_IEVENT);
    778  1.1  rkujawa 	FEC_WRITE(sc, FEC_IEVENT, ievent);	/* acknowledge */
    779  1.1  rkujawa 	/* Frame rx/tx is serviced by the BestComm task-completion handlers. */
    780  1.1  rkujawa 	return ievent != 0;
    781  1.1  rkujawa }
    782