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