fec.c revision 1.2 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