fec.c revision 1.1 1 1.1 rkujawa /* $NetBSD: fec.c,v 1.1 2026/06/27 13:28:34 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.1 rkujawa __KERNEL_RCSID(0, "$NetBSD: fec.c,v 1.1 2026/06/27 13:28:34 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.1 rkujawa static int fec_newbuf(struct fec_softc *, u_int);
93 1.1 rkujawa static int fec_intr(void *);
94 1.1 rkujawa static int fec_rxintr(void *);
95 1.1 rkujawa static int fec_txintr(void *);
96 1.1 rkujawa
97 1.1 rkujawa CFATTACH_DECL_NEW(fec, sizeof(struct fec_softc),
98 1.1 rkujawa fec_match, fec_attach, NULL, NULL);
99 1.1 rkujawa
100 1.1 rkujawa static int
101 1.1 rkujawa fec_match(device_t parent, cfdata_t cf, void *aux)
102 1.1 rkujawa {
103 1.1 rkujawa struct obio_attach_args *oba = aux;
104 1.1 rkujawa char compat[40];
105 1.1 rkujawa int len;
106 1.1 rkujawa
107 1.1 rkujawa if (strcmp(oba->obio_name, "ethernet") == 0)
108 1.1 rkujawa return 1;
109 1.1 rkujawa
110 1.1 rkujawa len = OF_getprop(oba->obio_node, "compatible", compat, sizeof(compat));
111 1.1 rkujawa if (len > 0 &&
112 1.1 rkujawa (strcmp(compat, "mpc5200-fec") == 0 ||
113 1.1 rkujawa strcmp(compat, "mpc5200b-fec") == 0))
114 1.1 rkujawa return 1;
115 1.1 rkujawa
116 1.1 rkujawa return 0;
117 1.1 rkujawa }
118 1.1 rkujawa
119 1.1 rkujawa static void
120 1.1 rkujawa fec_attach(device_t parent, device_t self, void *aux)
121 1.1 rkujawa {
122 1.1 rkujawa struct fec_softc *sc = device_private(self);
123 1.1 rkujawa struct obio_attach_args *oba = aux;
124 1.1 rkujawa struct ifnet *ifp = &sc->sc_if;
125 1.1 rkujawa struct mii_data *mii = &sc->sc_mii;
126 1.1 rkujawa uint8_t enaddr[ETHER_ADDR_LEN];
127 1.1 rkujawa bus_size_t size;
128 1.1 rkujawa int ist;
129 1.1 rkujawa
130 1.1 rkujawa sc->sc_dev = self;
131 1.1 rkujawa sc->sc_iot = oba->obio_bst;
132 1.1 rkujawa sc->sc_dmat = oba->obio_dmat;
133 1.1 rkujawa sc->sc_pa = oba->obio_addr;
134 1.1 rkujawa callout_init(&sc->sc_tick_ch, 0);
135 1.1 rkujawa callout_setfunc(&sc->sc_tick_ch, fec_tick, sc);
136 1.1 rkujawa
137 1.1 rkujawa size = oba->obio_size != 0 ? oba->obio_size : FEC_REG_SIZE;
138 1.1 rkujawa if (bus_space_map(sc->sc_iot, oba->obio_addr, size, 0,
139 1.1 rkujawa &sc->sc_ioh) != 0) {
140 1.1 rkujawa aprint_error(": can't map registers\n");
141 1.1 rkujawa return;
142 1.1 rkujawa }
143 1.1 rkujawa
144 1.1 rkujawa if (OF_getprop(oba->obio_node, "local-mac-address", enaddr,
145 1.1 rkujawa sizeof(enaddr)) != sizeof(enaddr) &&
146 1.1 rkujawa OF_getprop(oba->obio_node, "mac-address", enaddr,
147 1.1 rkujawa sizeof(enaddr)) != sizeof(enaddr)) {
148 1.1 rkujawa aprint_error(": no MAC address\n");
149 1.1 rkujawa return;
150 1.1 rkujawa }
151 1.1 rkujawa memcpy(sc->sc_enaddr, enaddr, ETHER_ADDR_LEN);
152 1.1 rkujawa
153 1.1 rkujawa if (obio_decode_interrupt(oba->obio_node, 0, &sc->sc_irq, &ist))
154 1.1 rkujawa sc->sc_ih = intr_establish(sc->sc_irq, ist, IPL_NET,
155 1.1 rkujawa fec_intr, sc);
156 1.1 rkujawa
157 1.1 rkujawa aprint_normal(": MPC5200 FEC, address %s\n",
158 1.1 rkujawa ether_sprintf(sc->sc_enaddr));
159 1.1 rkujawa
160 1.1 rkujawa /* Reset the controller and program the MII management clock. */
161 1.1 rkujawa sc->sc_ipb_freq = mpc5200_cdm_get_ipb_freq();
162 1.1 rkujawa fec_reset(sc);
163 1.1 rkujawa
164 1.1 rkujawa /* MII / PHY. */
165 1.1 rkujawa mii->mii_ifp = ifp;
166 1.1 rkujawa mii->mii_readreg = fec_miibus_readreg;
167 1.1 rkujawa mii->mii_writereg = fec_miibus_writereg;
168 1.1 rkujawa mii->mii_statchg = fec_miibus_statchg;
169 1.1 rkujawa sc->sc_ec.ec_mii = mii;
170 1.1 rkujawa ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
171 1.1 rkujawa mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
172 1.1 rkujawa if (LIST_FIRST(&mii->mii_phys) == NULL) {
173 1.1 rkujawa aprint_error_dev(self, "no PHY found\n");
174 1.1 rkujawa ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
175 1.1 rkujawa ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL);
176 1.1 rkujawa } else
177 1.1 rkujawa ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
178 1.1 rkujawa
179 1.1 rkujawa strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
180 1.1 rkujawa ifp->if_softc = sc;
181 1.1 rkujawa ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
182 1.1 rkujawa ifp->if_init = fec_init;
183 1.1 rkujawa ifp->if_stop = fec_stop;
184 1.1 rkujawa ifp->if_start = fec_start;
185 1.1 rkujawa ifp->if_ioctl = fec_ioctl;
186 1.1 rkujawa IFQ_SET_READY(&ifp->if_snd);
187 1.1 rkujawa
188 1.1 rkujawa if_attach(ifp);
189 1.1 rkujawa if_deferred_start_init(ifp, NULL);
190 1.1 rkujawa ether_ifattach(ifp, sc->sc_enaddr);
191 1.1 rkujawa }
192 1.1 rkujawa
193 1.1 rkujawa /*
194 1.1 rkujawa * Soft-reset the controller and set the MII management clock divider so MDC
195 1.1 rkujawa * stays at or below 2.5 MHz, derived from the IPB clock.
196 1.1 rkujawa */
197 1.1 rkujawa static void
198 1.1 rkujawa fec_reset(struct fec_softc *sc)
199 1.1 rkujawa {
200 1.1 rkujawa uint32_t div;
201 1.1 rkujawa int i;
202 1.1 rkujawa
203 1.1 rkujawa FEC_WRITE(sc, FEC_ECNTRL, FEC_ECNTRL_RESET);
204 1.1 rkujawa for (i = 0; i < 1000; i++) {
205 1.1 rkujawa if ((FEC_READ(sc, FEC_ECNTRL) & FEC_ECNTRL_RESET) == 0)
206 1.1 rkujawa break;
207 1.1 rkujawa DELAY(10);
208 1.1 rkujawa }
209 1.1 rkujawa FEC_WRITE(sc, FEC_IMASK, 0); /* mask all events */
210 1.1 rkujawa FEC_WRITE(sc, FEC_IEVENT, 0xffffffff); /* clear events */
211 1.1 rkujawa
212 1.1 rkujawa div = howmany(sc->sc_ipb_freq, 2 * FEC_MII_MAX_CLK);
213 1.1 rkujawa if (div > 0x3f)
214 1.1 rkujawa div = 0x3f;
215 1.1 rkujawa FEC_WRITE(sc, FEC_MII_SPEED, FEC_MII_SPEED_DIV(div));
216 1.1 rkujawa }
217 1.1 rkujawa
218 1.1 rkujawa static int
219 1.1 rkujawa fec_mii_wait(struct fec_softc *sc)
220 1.1 rkujawa {
221 1.1 rkujawa int i;
222 1.1 rkujawa
223 1.1 rkujawa for (i = 0; i < FEC_PHY_TIMEOUT; i++) {
224 1.1 rkujawa if (FEC_READ(sc, FEC_IEVENT) & FEC_INT_MII) {
225 1.1 rkujawa FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
226 1.1 rkujawa return 0;
227 1.1 rkujawa }
228 1.1 rkujawa DELAY(10);
229 1.1 rkujawa }
230 1.1 rkujawa return ETIMEDOUT;
231 1.1 rkujawa }
232 1.1 rkujawa
233 1.1 rkujawa static int
234 1.1 rkujawa fec_miibus_readreg(device_t self, int phy, int reg, uint16_t *val)
235 1.1 rkujawa {
236 1.1 rkujawa struct fec_softc *sc = device_private(self);
237 1.1 rkujawa
238 1.1 rkujawa FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
239 1.1 rkujawa FEC_WRITE(sc, FEC_MII_DATA, FEC_MII_READ(phy, reg));
240 1.1 rkujawa if (fec_mii_wait(sc) != 0)
241 1.1 rkujawa return ETIMEDOUT;
242 1.1 rkujawa
243 1.1 rkujawa *val = FEC_READ(sc, FEC_MII_DATA) & FEC_MII_DATA_MASK;
244 1.1 rkujawa return 0;
245 1.1 rkujawa }
246 1.1 rkujawa
247 1.1 rkujawa static int
248 1.1 rkujawa fec_miibus_writereg(device_t self, int phy, int reg, uint16_t val)
249 1.1 rkujawa {
250 1.1 rkujawa struct fec_softc *sc = device_private(self);
251 1.1 rkujawa
252 1.1 rkujawa FEC_WRITE(sc, FEC_IEVENT, FEC_INT_MII);
253 1.1 rkujawa FEC_WRITE(sc, FEC_MII_DATA, FEC_MII_WRITE(phy, reg, val));
254 1.1 rkujawa return fec_mii_wait(sc);
255 1.1 rkujawa }
256 1.1 rkujawa
257 1.1 rkujawa static void
258 1.1 rkujawa fec_miibus_statchg(struct ifnet *ifp)
259 1.1 rkujawa {
260 1.1 rkujawa struct fec_softc *sc = ifp->if_softc;
261 1.1 rkujawa uint32_t xcr;
262 1.1 rkujawa
263 1.1 rkujawa xcr = FEC_READ(sc, FEC_X_CNTRL);
264 1.1 rkujawa if (sc->sc_mii.mii_media_active & IFM_FDX)
265 1.1 rkujawa xcr |= FEC_X_CNTRL_FDEN;
266 1.1 rkujawa else
267 1.1 rkujawa xcr &= ~FEC_X_CNTRL_FDEN;
268 1.1 rkujawa FEC_WRITE(sc, FEC_X_CNTRL, xcr);
269 1.1 rkujawa }
270 1.1 rkujawa
271 1.1 rkujawa static void
272 1.1 rkujawa fec_tick(void *arg)
273 1.1 rkujawa {
274 1.1 rkujawa struct fec_softc *sc = arg;
275 1.1 rkujawa int s;
276 1.1 rkujawa
277 1.1 rkujawa s = splnet();
278 1.1 rkujawa mii_tick(&sc->sc_mii);
279 1.1 rkujawa splx(s);
280 1.1 rkujawa
281 1.1 rkujawa /*
282 1.1 rkujawa * Meh. Under load the receive FIFO can overrun, work it around.
283 1.1 rkujawa */
284 1.1 rkujawa if ((sc->sc_if.if_flags & IFF_RUNNING) &&
285 1.1 rkujawa (FEC_READ(sc, FEC_ECNTRL) & FEC_ECNTRL_ETHER_EN) == 0) {
286 1.1 rkujawa if_statinc(&sc->sc_if, if_ierrors);
287 1.1 rkujawa aprint_error_dev(sc->sc_dev,
288 1.1 rkujawa "ETHER_EN cleared, resetting\n");
289 1.1 rkujawa s = splnet();
290 1.1 rkujawa (void)fec_init(&sc->sc_if); /* reschedules the callout */
291 1.1 rkujawa splx(s);
292 1.1 rkujawa return;
293 1.1 rkujawa }
294 1.1 rkujawa
295 1.1 rkujawa callout_schedule(&sc->sc_tick_ch, hz);
296 1.1 rkujawa }
297 1.1 rkujawa
298 1.1 rkujawa /* Program the station address and receive/transmit MAC control. */
299 1.1 rkujawa static void
300 1.1 rkujawa fec_mac_setup(struct fec_softc *sc)
301 1.1 rkujawa {
302 1.1 rkujawa FEC_WRITE(sc, FEC_PADDR1,
303 1.1 rkujawa (sc->sc_enaddr[0] << 24) | (sc->sc_enaddr[1] << 16) |
304 1.1 rkujawa (sc->sc_enaddr[2] << 8) | sc->sc_enaddr[3]);
305 1.1 rkujawa FEC_WRITE(sc, FEC_PADDR2,
306 1.1 rkujawa (sc->sc_enaddr[4] << 24) | (sc->sc_enaddr[5] << 16) | 0x8808);
307 1.1 rkujawa FEC_WRITE(sc, FEC_IADDR1, 0);
308 1.1 rkujawa FEC_WRITE(sc, FEC_IADDR2, 0);
309 1.1 rkujawa /*
310 1.1 rkujawa * XXX: Accept all multicast groups via the hash filter.
311 1.1 rkujawa */
312 1.1 rkujawa FEC_WRITE(sc, FEC_GADDR1, 0xffffffff);
313 1.1 rkujawa FEC_WRITE(sc, FEC_GADDR2, 0xffffffff);
314 1.1 rkujawa FEC_WRITE(sc, FEC_R_CNTRL,
315 1.1 rkujawa FEC_R_CNTRL_MAX_FL(ETHER_MAX_LEN) | FEC_R_CNTRL_MII_MODE);
316 1.1 rkujawa FEC_WRITE(sc, FEC_X_CNTRL, FEC_X_CNTRL_FDEN);
317 1.1 rkujawa
318 1.1 rkujawa /*
319 1.1 rkujawa * Enable frame mode on both FIFOs
320 1.1 rkujawa */
321 1.1 rkujawa FEC_WRITE(sc, FEC_RESET_CNTRL, FEC_RESET_CNTRL_FIFO_EN);
322 1.1 rkujawa
323 1.1 rkujawa FEC_WRITE(sc, FEC_RFIFO_CONTROL, FEC_FIFO_CTRL_INIT);
324 1.1 rkujawa FEC_WRITE(sc, FEC_TFIFO_CONTROL, FEC_FIFO_CTRL_INIT);
325 1.1 rkujawa
326 1.1 rkujawa /*
327 1.1 rkujawa * The transmit FIFO requests data from BestComm only while it holds
328 1.1 rkujawa * fewer than "alarm" bytes!
329 1.1 rkujawa */
330 1.1 rkujawa FEC_WRITE(sc, FEC_TFIFO_ALARM, 0x80);
331 1.1 rkujawa }
332 1.1 rkujawa
333 1.1 rkujawa /* Allocate a cluster for receive descriptor idx and hand it to the engine. */
334 1.1 rkujawa static int
335 1.1 rkujawa fec_newbuf(struct fec_softc *sc, u_int idx)
336 1.1 rkujawa {
337 1.1 rkujawa struct mbuf *m;
338 1.1 rkujawa int error;
339 1.1 rkujawa
340 1.1 rkujawa MGETHDR(m, M_DONTWAIT, MT_DATA);
341 1.1 rkujawa if (m == NULL)
342 1.1 rkujawa return ENOBUFS;
343 1.1 rkujawa MCLGET(m, M_DONTWAIT);
344 1.1 rkujawa if ((m->m_flags & M_EXT) == 0) {
345 1.1 rkujawa m_freem(m);
346 1.1 rkujawa return ENOBUFS;
347 1.1 rkujawa }
348 1.1 rkujawa m->m_len = m->m_pkthdr.len = MCLBYTES;
349 1.1 rkujawa error = bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_rxmap[idx], m,
350 1.1 rkujawa BUS_DMA_NOWAIT | BUS_DMA_READ);
351 1.1 rkujawa if (error) {
352 1.1 rkujawa m_freem(m);
353 1.1 rkujawa return error;
354 1.1 rkujawa }
355 1.1 rkujawa bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0, MCLBYTES,
356 1.1 rkujawa BUS_DMASYNC_PREREAD);
357 1.1 rkujawa sc->sc_rxmbuf[idx] = m;
358 1.1 rkujawa bestcomm_bd_post(&sc->sc_rxring, idx,
359 1.1 rkujawa sc->sc_rxmap[idx]->dm_segs[0].ds_addr, MCLBYTES, 0);
360 1.1 rkujawa return 0;
361 1.1 rkujawa }
362 1.1 rkujawa
363 1.1 rkujawa static int
364 1.1 rkujawa fec_init(struct ifnet *ifp)
365 1.1 rkujawa {
366 1.1 rkujawa struct fec_softc *sc = ifp->if_softc;
367 1.1 rkujawa u_int i;
368 1.1 rkujawa int error;
369 1.1 rkujawa
370 1.1 rkujawa fec_stop(ifp, 0);
371 1.1 rkujawa
372 1.1 rkujawa if (!bestcomm_available()) {
373 1.1 rkujawa aprint_error_ifnet(ifp, "BestComm SDMA not available\n");
374 1.1 rkujawa return ENXIO;
375 1.1 rkujawa }
376 1.1 rkujawa
377 1.1 rkujawa fec_reset(sc);
378 1.1 rkujawa fec_mac_setup(sc);
379 1.1 rkujawa
380 1.1 rkujawa if (bestcomm_bd_setup(&sc->sc_rxring, FEC_RX_TASK, &fec_rx_layout,
381 1.1 rkujawa sc->sc_pa + FEC_RFIFO_DATA, FEC_NRXDESC, MCLBYTES, 4,
382 1.1 rkujawa FEC_RX_INITIATOR, 6) != 0 ||
383 1.1 rkujawa bestcomm_bd_setup(&sc->sc_txring, FEC_TX_TASK, &fec_tx_layout,
384 1.1 rkujawa sc->sc_pa + FEC_TFIFO_DATA, FEC_NTXDESC, MCLBYTES, 4,
385 1.1 rkujawa FEC_TX_INITIATOR, 5) != 0) {
386 1.1 rkujawa aprint_error_ifnet(ifp, "cannot set up SDMA rings\n");
387 1.1 rkujawa return ENOMEM;
388 1.1 rkujawa }
389 1.1 rkujawa
390 1.1 rkujawa for (i = 0; i < FEC_NRXDESC; i++) {
391 1.1 rkujawa if (sc->sc_rxmap[i] == NULL &&
392 1.1 rkujawa bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
393 1.1 rkujawa BUS_DMA_NOWAIT, &sc->sc_rxmap[i]) != 0)
394 1.1 rkujawa return ENOMEM;
395 1.1 rkujawa if ((error = fec_newbuf(sc, i)) != 0)
396 1.1 rkujawa return error;
397 1.1 rkujawa }
398 1.1 rkujawa for (i = 0; i < FEC_NTXDESC; i++) {
399 1.1 rkujawa if (sc->sc_txmap[i] == NULL &&
400 1.1 rkujawa bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
401 1.1 rkujawa BUS_DMA_NOWAIT, &sc->sc_txmap[i]) != 0)
402 1.1 rkujawa return ENOMEM;
403 1.1 rkujawa }
404 1.1 rkujawa sc->sc_rxptr = 0;
405 1.1 rkujawa sc->sc_txnext = sc->sc_txdirty = sc->sc_txbusy = 0;
406 1.1 rkujawa
407 1.1 rkujawa /* Hook the BestComm task-completion interrupts (via the SIU cascade). */
408 1.1 rkujawa sc->sc_rxih = intr_establish(bestcomm_task_irq(FEC_RX_TASK), IST_LEVEL,
409 1.1 rkujawa IPL_NET, fec_rxintr, sc);
410 1.1 rkujawa sc->sc_txih = intr_establish(bestcomm_task_irq(FEC_TX_TASK), IST_LEVEL,
411 1.1 rkujawa IPL_NET, fec_txintr, sc);
412 1.1 rkujawa
413 1.1 rkujawa /*
414 1.1 rkujawa * Bring the link up before enabling the controller.
415 1.1 rkujawa */
416 1.1 rkujawa mii_mediachg(&sc->sc_mii);
417 1.1 rkujawa for (i = 0; i < 500; i++) {
418 1.1 rkujawa mii_pollstat(&sc->sc_mii);
419 1.1 rkujawa if (sc->sc_mii.mii_media_status & IFM_ACTIVE)
420 1.1 rkujawa break;
421 1.1 rkujawa DELAY(10000);
422 1.1 rkujawa }
423 1.1 rkujawa
424 1.1 rkujawa FEC_WRITE(sc, FEC_ECNTRL, FEC_ECNTRL_ETHER_EN);
425 1.1 rkujawa bestcomm_task_start(FEC_RX_TASK);
426 1.1 rkujawa bestcomm_task_start(FEC_TX_TASK);
427 1.1 rkujawa
428 1.1 rkujawa ifp->if_flags |= IFF_RUNNING;
429 1.1 rkujawa ifp->if_flags &= ~IFF_OACTIVE;
430 1.1 rkujawa
431 1.1 rkujawa callout_schedule(&sc->sc_tick_ch, hz);
432 1.1 rkujawa return 0;
433 1.1 rkujawa }
434 1.1 rkujawa
435 1.1 rkujawa static void
436 1.1 rkujawa fec_stop(struct ifnet *ifp, int disable)
437 1.1 rkujawa {
438 1.1 rkujawa struct fec_softc *sc = ifp->if_softc;
439 1.1 rkujawa u_int i;
440 1.1 rkujawa
441 1.1 rkujawa callout_stop(&sc->sc_tick_ch);
442 1.1 rkujawa
443 1.1 rkujawa if (ifp->if_flags & IFF_RUNNING) {
444 1.1 rkujawa bestcomm_task_stop(FEC_RX_TASK);
445 1.1 rkujawa bestcomm_task_stop(FEC_TX_TASK);
446 1.1 rkujawa }
447 1.1 rkujawa FEC_WRITE(sc, FEC_ECNTRL, 0);
448 1.1 rkujawa
449 1.1 rkujawa if (sc->sc_rxih != NULL) {
450 1.1 rkujawa intr_disestablish(sc->sc_rxih);
451 1.1 rkujawa sc->sc_rxih = NULL;
452 1.1 rkujawa }
453 1.1 rkujawa if (sc->sc_txih != NULL) {
454 1.1 rkujawa intr_disestablish(sc->sc_txih);
455 1.1 rkujawa sc->sc_txih = NULL;
456 1.1 rkujawa }
457 1.1 rkujawa
458 1.1 rkujawa mii_down(&sc->sc_mii);
459 1.1 rkujawa
460 1.1 rkujawa for (i = 0; i < FEC_NRXDESC; i++) {
461 1.1 rkujawa if (sc->sc_rxmbuf[i] != NULL) {
462 1.1 rkujawa bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[i]);
463 1.1 rkujawa m_freem(sc->sc_rxmbuf[i]);
464 1.1 rkujawa sc->sc_rxmbuf[i] = NULL;
465 1.1 rkujawa }
466 1.1 rkujawa }
467 1.1 rkujawa for (i = 0; i < FEC_NTXDESC; i++) {
468 1.1 rkujawa if (sc->sc_txmbuf[i] != NULL) {
469 1.1 rkujawa bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[i]);
470 1.1 rkujawa m_freem(sc->sc_txmbuf[i]);
471 1.1 rkujawa sc->sc_txmbuf[i] = NULL;
472 1.1 rkujawa }
473 1.1 rkujawa }
474 1.1 rkujawa ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
475 1.1 rkujawa }
476 1.1 rkujawa
477 1.1 rkujawa static void
478 1.1 rkujawa fec_start(struct ifnet *ifp)
479 1.1 rkujawa {
480 1.1 rkujawa struct fec_softc *sc = ifp->if_softc;
481 1.1 rkujawa struct mbuf *m, *mn;
482 1.1 rkujawa u_int idx;
483 1.1 rkujawa int error, posted = 0;
484 1.1 rkujawa
485 1.1 rkujawa if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
486 1.1 rkujawa return;
487 1.1 rkujawa
488 1.1 rkujawa while (sc->sc_txbusy < FEC_NTXDESC) {
489 1.1 rkujawa IFQ_POLL(&ifp->if_snd, m);
490 1.1 rkujawa if (m == NULL)
491 1.1 rkujawa break;
492 1.1 rkujawa idx = sc->sc_txnext;
493 1.1 rkujawa
494 1.1 rkujawa error = bus_dmamap_load_mbuf(sc->sc_dmat, sc->sc_txmap[idx], m,
495 1.1 rkujawa BUS_DMA_NOWAIT | BUS_DMA_WRITE);
496 1.1 rkujawa if (error == EFBIG) {
497 1.1 rkujawa /* The buffer descriptor holds one segment; collapse. */
498 1.1 rkujawa mn = m_defrag(m, M_DONTWAIT);
499 1.1 rkujawa if (mn != NULL) {
500 1.1 rkujawa m = mn;
501 1.1 rkujawa error = bus_dmamap_load_mbuf(sc->sc_dmat,
502 1.1 rkujawa sc->sc_txmap[idx], m,
503 1.1 rkujawa BUS_DMA_NOWAIT | BUS_DMA_WRITE);
504 1.1 rkujawa }
505 1.1 rkujawa }
506 1.1 rkujawa IFQ_DEQUEUE(&ifp->if_snd, m);
507 1.1 rkujawa if (error) {
508 1.1 rkujawa m_freem(m);
509 1.1 rkujawa if_statinc(ifp, if_oerrors);
510 1.1 rkujawa continue;
511 1.1 rkujawa }
512 1.1 rkujawa
513 1.1 rkujawa bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[idx], 0,
514 1.1 rkujawa m->m_pkthdr.len, BUS_DMASYNC_PREWRITE);
515 1.1 rkujawa bpf_mtap(ifp, m, BPF_D_OUT);
516 1.1 rkujawa sc->sc_txmbuf[idx] = m;
517 1.1 rkujawa bestcomm_bd_post(&sc->sc_txring, idx,
518 1.1 rkujawa sc->sc_txmap[idx]->dm_segs[0].ds_addr, m->m_pkthdr.len,
519 1.1 rkujawa BESTCOMM_BD_FLAG_LAST | BESTCOMM_BD_FLAG_INT);
520 1.1 rkujawa sc->sc_txnext = (idx + 1) % FEC_NTXDESC;
521 1.1 rkujawa sc->sc_txbusy++;
522 1.1 rkujawa posted = 1;
523 1.1 rkujawa }
524 1.1 rkujawa
525 1.1 rkujawa /*
526 1.1 rkujawa * (Re-)enable the transmit task.
527 1.1 rkujawa */
528 1.1 rkujawa if (posted)
529 1.1 rkujawa bestcomm_task_start(FEC_TX_TASK);
530 1.1 rkujawa
531 1.1 rkujawa if (sc->sc_txbusy == FEC_NTXDESC)
532 1.1 rkujawa ifp->if_flags |= IFF_OACTIVE;
533 1.1 rkujawa }
534 1.1 rkujawa
535 1.1 rkujawa /* BestComm FEC_RX task completion: hand received frames up, refill the ring. */
536 1.1 rkujawa static int
537 1.1 rkujawa fec_rxintr(void *arg)
538 1.1 rkujawa {
539 1.1 rkujawa struct fec_softc *sc = arg;
540 1.1 rkujawa struct ifnet *ifp = &sc->sc_if;
541 1.1 rkujawa struct mbuf *m;
542 1.1 rkujawa uint32_t st;
543 1.1 rkujawa u_int idx;
544 1.1 rkujawa int len, handled = 0;
545 1.1 rkujawa
546 1.1 rkujawa for (;;) {
547 1.1 rkujawa idx = sc->sc_rxptr;
548 1.1 rkujawa st = bestcomm_bd_status(&sc->sc_rxring, idx);
549 1.1 rkujawa if (st & BESTCOMM_BD_READY)
550 1.1 rkujawa break;
551 1.1 rkujawa handled = 1;
552 1.1 rkujawa
553 1.1 rkujawa bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0, MCLBYTES,
554 1.1 rkujawa BUS_DMASYNC_POSTREAD);
555 1.1 rkujawa bus_dmamap_unload(sc->sc_dmat, sc->sc_rxmap[idx]);
556 1.1 rkujawa m = sc->sc_rxmbuf[idx];
557 1.1 rkujawa sc->sc_rxmbuf[idx] = NULL;
558 1.1 rkujawa
559 1.1 rkujawa len = st & BESTCOMM_BD_LEN_MASK;
560 1.1 rkujawa if (len > ETHER_CRC_LEN)
561 1.1 rkujawa len -= ETHER_CRC_LEN; /* strip FCS */
562 1.1 rkujawa
563 1.1 rkujawa if (fec_newbuf(sc, idx) != 0) {
564 1.1 rkujawa /* No replacement: recycle this buffer, drop the frame. */
565 1.1 rkujawa sc->sc_rxmbuf[idx] = m;
566 1.1 rkujawa (void)bus_dmamap_load_mbuf(sc->sc_dmat,
567 1.1 rkujawa sc->sc_rxmap[idx], m, BUS_DMA_NOWAIT | BUS_DMA_READ);
568 1.1 rkujawa bus_dmamap_sync(sc->sc_dmat, sc->sc_rxmap[idx], 0,
569 1.1 rkujawa MCLBYTES, BUS_DMASYNC_PREREAD);
570 1.1 rkujawa bestcomm_bd_post(&sc->sc_rxring, idx,
571 1.1 rkujawa sc->sc_rxmap[idx]->dm_segs[0].ds_addr, MCLBYTES, 0);
572 1.1 rkujawa if_statinc(ifp, if_ierrors);
573 1.1 rkujawa } else {
574 1.1 rkujawa m_set_rcvif(m, ifp);
575 1.1 rkujawa m->m_pkthdr.len = m->m_len = len;
576 1.1 rkujawa if_percpuq_enqueue(ifp->if_percpuq, m);
577 1.1 rkujawa }
578 1.1 rkujawa sc->sc_rxptr = (idx + 1) % FEC_NRXDESC;
579 1.1 rkujawa }
580 1.1 rkujawa
581 1.1 rkujawa return handled;
582 1.1 rkujawa }
583 1.1 rkujawa
584 1.1 rkujawa /* BestComm FEC_TX task completion: reap transmitted frames. */
585 1.1 rkujawa static int
586 1.1 rkujawa fec_txintr(void *arg)
587 1.1 rkujawa {
588 1.1 rkujawa struct fec_softc *sc = arg;
589 1.1 rkujawa struct ifnet *ifp = &sc->sc_if;
590 1.1 rkujawa uint32_t st;
591 1.1 rkujawa u_int idx;
592 1.1 rkujawa int handled = 0;
593 1.1 rkujawa
594 1.1 rkujawa while (sc->sc_txbusy > 0) {
595 1.1 rkujawa idx = sc->sc_txdirty;
596 1.1 rkujawa st = bestcomm_bd_status(&sc->sc_txring, idx);
597 1.1 rkujawa if (st & BESTCOMM_BD_READY)
598 1.1 rkujawa break;
599 1.1 rkujawa handled = 1;
600 1.1 rkujawa
601 1.1 rkujawa bus_dmamap_sync(sc->sc_dmat, sc->sc_txmap[idx], 0,
602 1.1 rkujawa sc->sc_txmbuf[idx]->m_pkthdr.len, BUS_DMASYNC_POSTWRITE);
603 1.1 rkujawa bus_dmamap_unload(sc->sc_dmat, sc->sc_txmap[idx]);
604 1.1 rkujawa m_freem(sc->sc_txmbuf[idx]);
605 1.1 rkujawa sc->sc_txmbuf[idx] = NULL;
606 1.1 rkujawa if_statinc(ifp, if_opackets);
607 1.1 rkujawa
608 1.1 rkujawa sc->sc_txdirty = (idx + 1) % FEC_NTXDESC;
609 1.1 rkujawa sc->sc_txbusy--;
610 1.1 rkujawa }
611 1.1 rkujawa if (handled) {
612 1.1 rkujawa ifp->if_flags &= ~IFF_OACTIVE;
613 1.1 rkujawa if_schedule_deferred_start(ifp);
614 1.1 rkujawa }
615 1.1 rkujawa return handled;
616 1.1 rkujawa }
617 1.1 rkujawa
618 1.1 rkujawa static int
619 1.1 rkujawa fec_ioctl(struct ifnet *ifp, u_long cmd, void *data)
620 1.1 rkujawa {
621 1.1 rkujawa int s, error;
622 1.1 rkujawa
623 1.1 rkujawa s = splnet();
624 1.1 rkujawa error = ether_ioctl(ifp, cmd, data);
625 1.1 rkujawa if (error == ENETRESET) {
626 1.1 rkujawa /*
627 1.1 rkujawa * XXX: Just acknowledge it.
628 1.1 rkujawa */
629 1.1 rkujawa error = 0;
630 1.1 rkujawa }
631 1.1 rkujawa splx(s);
632 1.1 rkujawa return error;
633 1.1 rkujawa }
634 1.1 rkujawa
635 1.1 rkujawa static int
636 1.1 rkujawa fec_intr(void *arg)
637 1.1 rkujawa {
638 1.1 rkujawa struct fec_softc *sc = arg;
639 1.1 rkujawa uint32_t ievent;
640 1.1 rkujawa
641 1.1 rkujawa ievent = FEC_READ(sc, FEC_IEVENT);
642 1.1 rkujawa FEC_WRITE(sc, FEC_IEVENT, ievent); /* acknowledge */
643 1.1 rkujawa /* Frame rx/tx is serviced by the BestComm task-completion handlers. */
644 1.1 rkujawa return ievent != 0;
645 1.1 rkujawa }
646