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