No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / acorn26 / ioc / if_eca.c
blob90dcd64e967cc5bd88f451fe8b3cec88dc75a78d
1 /* $NetBSD: if_eca.c,v 1.10 2009/01/07 20:56:40 bjh21 Exp $ */
3 /*-
4 * Copyright (c) 2001 Ben Harris
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/param.h>
32 __KERNEL_RCSID(0, "$NetBSD: if_eca.c,v 1.10 2009/01/07 20:56:40 bjh21 Exp $");
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <sys/socket.h>
37 #include <sys/syslog.h>
38 #include <sys/systm.h>
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_eco.h>
44 #include <machine/bus.h>
45 #include <machine/fiq.h>
46 #include <machine/intr.h>
47 #include <machine/machdep.h>
49 #include <arch/acorn26/iobus/iocvar.h>
51 #include <dev/ic/mc6854reg.h>
52 #include <arch/acorn26/ioc/if_ecavar.h>
54 static int eca_match(device_t, cfdata_t, void *);
55 static void eca_attach(device_t, device_t, void *);
57 static int eca_init(struct ifnet *);
58 static void eca_stop(struct ifnet *ifp, int disable);
60 static int eca_claimwire(struct ifnet *);
61 static void eca_txframe(struct ifnet *, struct mbuf *);
63 static void eca_tx_downgrade(void);
64 static void eca_txdone(void *);
66 static int eca_init_rxbuf(struct eca_softc *sc, int flags);
67 static void eca_init_rx_soft(struct eca_softc *sc);
68 static void eca_init_rx_hard(struct eca_softc *sc);
69 static void eca_init_rx(struct eca_softc *sc);
71 static void eca_rx_downgrade(void);
72 static void eca_gotframe(void *);
74 struct eca_softc *eca_fiqowner;
76 CFATTACH_DECL_NEW(eca, sizeof(struct eca_softc),
77 eca_match, eca_attach, NULL, NULL);
79 static int
80 eca_match(device_t parent, cfdata_t cf, void *aux)
82 struct ioc_attach_args *ioc = aux;
84 /* Econet never uses LOOP mode. */
85 if ((bus_space_read_1(ioc->ioc_sync_t, ioc->ioc_sync_h, MC6854_SR1) &
86 MC6854_SR1_LOOP) != 0)
87 return 0;
89 return 1;
92 static void
93 eca_attach(device_t parent, device_t self, void *aux)
95 struct eca_softc *sc = device_private(self);
96 struct ioc_attach_args *ioc = aux;
97 struct ifnet *ifp = &sc->sc_ec.ec_if;
98 u_int8_t myaddr[ECO_ADDR_LEN];
100 sc->sc_dev = self;
101 sc->sc_iot = ioc->ioc_sync_t;
102 sc->sc_ioh = ioc->ioc_sync_h;
104 myaddr[0] = cmos_read(0x40);
105 myaddr[1] = 0;
107 aprint_normal(": station %s", eco_sprintf(myaddr));
108 /* It's traditional to print the clock state at boot. */
109 if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MC6854_SR2) &
110 MC6854_SR2_NDCD))
111 printf(", no clock");
113 /* Initialise ifnet structure. */
115 strcpy(ifp->if_xname, device_xname(sc->sc_dev));
116 ifp->if_softc = sc;
117 ifp->if_init = eca_init;
118 ifp->if_stop = eca_stop;
119 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
120 IFQ_SET_READY(&ifp->if_snd);
121 sc->sc_ec.ec_claimwire = eca_claimwire;
122 sc->sc_ec.ec_txframe = eca_txframe;
124 sc->sc_rx_soft = softint_establish(IPL_SOFTNET, eca_gotframe, sc);
125 sc->sc_tx_soft = softint_establish(IPL_SOFTNET, eca_txdone, sc);
126 if (sc->sc_rx_soft == NULL || sc->sc_tx_soft == NULL) {
127 aprint_error_dev(sc->sc_dev,
128 "failed to establish software interrupt\n");
129 return;
132 if_attach(ifp);
133 eco_ifattach(ifp, myaddr);
135 sc->sc_fiqhandler.fh_func = eca_fiqhandler;
136 sc->sc_fiqhandler.fh_size = eca_efiqhandler - eca_fiqhandler;
137 sc->sc_fiqhandler.fh_flags = 0;
138 sc->sc_fiqhandler.fh_regs = &sc->sc_fiqstate.efs_rx_fiqregs;
140 aprint_normal("\n");
143 static int
144 eca_init(struct ifnet *ifp)
146 struct eca_softc *sc = ifp->if_softc;
147 bus_space_tag_t iot = sc->sc_iot;
148 bus_space_handle_t ioh = sc->sc_ioh;
149 int sr1, sr2;
150 int err;
152 if ((err = eco_init(ifp)) != 0)
153 return err;
155 /* Claim the FIQ early, in case we don't get it. */
156 if ((err = fiq_claim(&sc->sc_fiqhandler)) != 0)
157 return err;
159 if (sc->sc_rcvmbuf == NULL) {
160 err = eca_init_rxbuf(sc, M_WAIT);
161 if (err != 0)
162 return err;
165 sc->sc_transmitting = 0;
167 /* Interrupts disabled, no DMA, hold Tx and Rx in reset. */
168 sc->sc_cr1 = MC6854_CR1_RX_RS | MC6854_CR1_TX_RS;
169 /* 1-byte transfers, mark idle. */
170 sc->sc_cr2 = 0;
171 /* Nothing exciting. */
172 sc->sc_cr3 = 0;
173 /* single flag, 8 data bits, NRZ */
174 sc->sc_cr4 = MC6854_CR4_TX_WL_8BITS | MC6854_CR4_RX_WL_8BITS;
176 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
177 bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
178 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1 | MC6854_CR1_AC);
179 bus_space_write_1(iot, ioh, MC6854_CR3, sc->sc_cr3);
180 bus_space_write_1(iot, ioh, MC6854_CR4, sc->sc_cr4);
181 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
183 /* Everything's set up. Take chip out of reset. */
184 sc->sc_cr1 &= ~(MC6854_CR1_RX_RS | MC6854_CR1_TX_RS);
185 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
187 /* Read and clear status registers. */
188 sr1 = bus_space_read_1(iot, ioh, MC6854_SR1);
189 sr2 = bus_space_read_1(iot, ioh, MC6854_SR2);
190 bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2 |
191 MC6854_CR2_CLR_RX_ST | MC6854_CR2_CLR_TX_ST);
193 /* Set up FIQ registers and enable FIQs */
194 eca_init_rx(sc);
196 ifp->if_flags |= IFF_RUNNING;
198 return 0;
202 * Check if the network's idle, and if it is, start flag-filling.
204 static int
205 eca_claimwire(struct ifnet *ifp)
207 struct eca_softc *sc = ifp->if_softc;
208 bus_space_tag_t iot = sc->sc_iot;
209 bus_space_handle_t ioh = sc->sc_ioh;
211 KASSERT(sc->sc_ec.ec_state == ECO_IDLE);
212 if (bus_space_read_1(iot, ioh, MC6854_SR2) & MC6854_SR2_RX_IDLE) {
213 /* Start flag fill. */
214 sc->sc_cr2 |= MC6854_CR2_RTS | MC6854_CR2_F_M_IDLE;
215 bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
216 return 0;
218 return EBUSY;
221 static void
222 eca_txframe(struct ifnet *ifp, struct mbuf *m)
224 struct eca_softc *sc = ifp->if_softc;
225 bus_space_tag_t iot = sc->sc_iot;
226 bus_space_handle_t ioh = sc->sc_ioh;
227 struct fiqregs fr;
229 ioc_fiq_setmask(0);
230 /* Start flag-filling while we work out what to do next. */
231 sc->sc_cr2 |= MC6854_CR2_RTS | MC6854_CR2_F_M_IDLE;
232 bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
233 sc->sc_fiqstate.efs_fiqhandler = eca_fiqhandler_tx;
234 sc->sc_transmitting = 1;
235 sc->sc_txmbuf = m;
236 fr.fr_r8 = (register_t)sc->sc_ioh;
237 fr.fr_r9 = (register_t)sc->sc_txmbuf->m_data;
238 fr.fr_r10 = (register_t)sc->sc_txmbuf->m_len;
239 fr.fr_r11 = (register_t)&sc->sc_fiqstate;
240 fiq_setregs(&fr);
241 sc->sc_fiqstate.efs_tx_curmbuf = sc->sc_txmbuf;
242 fiq_downgrade_handler = eca_tx_downgrade;
243 /* Read and clear Tx status. */
244 bus_space_read_1(iot, ioh, MC6854_SR1);
245 bus_space_write_1(iot, ioh, MC6854_CR2,
246 sc->sc_cr2 | MC6854_CR2_CLR_TX_ST);
247 sc->sc_cr1 = MC6854_CR1_TIE;
248 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1 |
249 MC6854_CR1_DISCONTINUE);
250 ioc_fiq_setmask(IOC_FIQ_BIT(FIQ_EFIQ));
253 static void
254 eca_tx_downgrade(void)
256 struct eca_softc *sc = eca_fiqowner;
257 bus_space_tag_t iot = sc->sc_iot;
258 bus_space_handle_t ioh = sc->sc_ioh;
259 int sr1;
260 char buf[128];
262 KASSERT(sc->sc_transmitting);
263 sc->sc_cr2 = 0;
264 if (__predict_true(sc->sc_fiqstate.efs_tx_curmbuf == NULL)) {
265 /* Entire frame got transmitted. */
266 } else {
267 sr1 = bus_space_read_1(iot, ioh, MC6854_SR1);
268 if (sr1 & MC6854_SR1_TXU)
269 log(LOG_ERR, "%s: Tx underrun\n",
270 device_xname(sc->sc_dev));
271 else if (sr1 & MC6854_SR1_NCTS)
272 log(LOG_WARNING, "%s: collision\n",
273 device_xname(sc->sc_dev));
274 else {
275 log(LOG_ERR, "%s: incomplete transmission\n",
276 device_xname(sc->sc_dev));
277 snprintb(buf, 128, MC6854_SR1_BITS, sr1);
278 log(LOG_ERR, "%s: SR1 = %s\n",
279 device_xname(sc->sc_dev), buf);
281 bus_space_write_1(iot, ioh, MC6854_CR2,
282 sc->sc_cr2 | MC6854_CR2_CLR_TX_ST);
284 sc->sc_txmbuf = NULL;
286 /* Code from eca_init_rx_hard(). */
287 sc->sc_cr1 = MC6854_CR1_RIE;
288 fiq_downgrade_handler = eca_rx_downgrade;
289 sc->sc_transmitting = 0;
290 eca_fiqowner = sc;
291 ioc_fiq_setmask(IOC_FIQ_BIT(FIQ_EFIQ));
292 /* End code from eca_init_rx_hard(). */
294 softint_schedule(sc->sc_tx_soft);
298 * Low-priority soft interrupt taken after a frame's been transmitted.
300 static void
301 eca_txdone(void *arg)
303 struct eca_softc *sc = arg;
304 struct ifnet *ifp = &sc->sc_ec.ec_if;
306 m_freem(sc->sc_txmbuf);
307 sc->sc_txmbuf = NULL;
308 ifp->if_flags &= ~IFF_OACTIVE;
309 ifp->if_start(ifp);
313 * Set up the Rx buffer for the interface.
314 * flags is M_WAIT or M_DONTWAIT. Returns an errno or 0 for success.
316 static int
317 eca_init_rxbuf(struct eca_softc *sc, int flags)
319 struct mbuf *m, *n;
320 size_t totlen;
323 * The Rx buffer takes the form of a chain of mbufs, set up as
324 * if they contain data already. The FIQ handler is
325 * responsible for filling the marked space, and indicating
326 * how much it's put in there.
329 totlen = 0;
330 m = n = NULL;
331 while (totlen < sc->sc_ec.ec_if.if_mtu + ECO_HDR_LEN) {
332 MGETHDR(m, flags, MT_DATA);
333 if (m == NULL)
334 return ENOBUFS;
335 MCLGET(m, flags);
336 if ((m->m_flags & M_EXT) == 0) {
337 m_freem(m);
338 return ENOBUFS;
340 /* XXX may want to tweak for payload alignment here. */
341 m->m_len = m->m_ext.ext_size;
342 m->m_next = n;
343 totlen += m->m_len;
344 n = m;
347 sc->sc_rcvmbuf = m;
348 return 0;
352 * Set up the software state necessary for reception, but don't
353 * actually start receoption. Pushing the state into the hardware is
354 * left to eca_init_rx_hard() the Tx FIQ handler.
356 void
357 eca_init_rx_soft(struct eca_softc *sc)
359 struct ifnet *ifp = &sc->sc_ec.ec_if;
360 struct fiqregs *fr = &sc->sc_fiqstate.efs_rx_fiqregs;
362 memset(fr, 0, sizeof(*fr));
363 fr->fr_r8 = (register_t)sc->sc_ioh;
364 fr->fr_r9 = (register_t)sc->sc_rcvmbuf->m_data;
365 fr->fr_r10 = (register_t)ECO_ADDR_LEN;
366 fr->fr_r11 = (register_t)&sc->sc_fiqstate;
367 sc->sc_fiqstate.efs_rx_curmbuf = sc->sc_rcvmbuf;
368 sc->sc_fiqstate.efs_rx_flags = 0;
369 sc->sc_fiqstate.efs_rx_myaddr = CLLADDR(ifp->if_sadl)[0];
373 * Copy state set up by eca_init_rx_soft into the hardware, and reset
374 * the FIQ handler as appropriate.
376 * This code is functionally duplicated across the Tx FIQ handler and
377 * eca_tx_downgrade(). Keep them in sync!
379 void
380 eca_init_rx_hard(struct eca_softc *sc)
382 bus_space_tag_t iot = sc->sc_iot;
383 bus_space_handle_t ioh = sc->sc_ioh;
384 struct fiqregs *fr = &sc->sc_fiqstate.efs_rx_fiqregs;
386 sc->sc_fiqstate.efs_fiqhandler = eca_fiqhandler_rx;
387 sc->sc_transmitting = 0;
388 sc->sc_cr1 = MC6854_CR1_RIE;
389 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
390 fiq_setregs(fr);
391 fiq_downgrade_handler = eca_rx_downgrade;
392 eca_fiqowner = sc;
393 ioc_fiq_setmask(IOC_FIQ_BIT(FIQ_EFIQ));
397 * Set up the chip and FIQ handler for reception. Assumes the Rx buffer is
398 * set up already by eca_init_rxbuf().
400 void
401 eca_init_rx(struct eca_softc *sc)
404 eca_init_rx_soft(sc);
405 eca_init_rx_hard(sc);
408 static void
409 eca_stop(struct ifnet *ifp, int disable)
411 struct eca_softc *sc = ifp->if_softc;
412 bus_space_tag_t iot = sc->sc_iot;
413 bus_space_handle_t ioh = sc->sc_ioh;
415 ifp->if_flags &= ~IFF_RUNNING;
417 eco_stop(ifp, disable);
419 /* Interrupts disabled, no DMA, hold Tx and Rx in reset. */
420 sc->sc_cr1 = MC6854_CR1_RX_RS | MC6854_CR1_TX_RS;
421 bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
423 ioc_fiq_setmask(0);
424 fiq_downgrade_handler = NULL;
425 eca_fiqowner = NULL;
426 fiq_release(&sc->sc_fiqhandler);
427 if (sc->sc_rcvmbuf != NULL) {
428 m_freem(sc->sc_rcvmbuf);
429 sc->sc_rcvmbuf = NULL;
434 * This is a FIQ downgrade handler, and as such is entered at IPL_HIGH with
435 * FIQs disabled (but still owned by us).
437 static void
438 eca_rx_downgrade(void)
440 struct eca_softc *sc = eca_fiqowner;
442 sc->sc_sr2 = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MC6854_SR2);
443 softint_schedule(sc->sc_rx_soft);
447 * eca_gotframe() is called if there's something interesting on
448 * reception. The receiver is turned off now -- it's up to us to
449 * start it again.
451 static void
452 eca_gotframe(void *arg)
454 struct eca_softc *sc = arg;
455 struct ifnet *ifp = &sc->sc_ec.ec_if;
456 bus_space_tag_t iot = sc->sc_iot;
457 bus_space_handle_t ioh = sc->sc_ioh;
458 struct fiqregs fr;
459 int sr2;
460 struct mbuf *m, *mtail, *n, *reply;
462 reply = NULL;
463 sr2 = sc->sc_sr2;
465 /* 1: Is there a valid frame waiting? */
466 if ((sr2 & MC6854_SR2_FV) && !(sr2 & MC6854_SR2_OVRN) &&
467 sc->sc_fiqstate.efs_rx_curmbuf != NULL) {
468 fiq_getregs(&fr);
469 m = sc->sc_rcvmbuf;
470 mtail = sc->sc_fiqstate.efs_rx_curmbuf;
472 * Before we process this buffer, make sure we can get
473 * a new one.
475 if (eca_init_rxbuf(sc, M_DONTWAIT) == 0) {
476 ifp->if_ipackets++; /* XXX packet vs frame? */
477 /* Trim the tail of the mbuf chain. */
478 mtail->m_len =
479 (char *)(fr.fr_r9) - mtod(mtail, char *);
480 m_freem(mtail->m_next);
481 mtail->m_next = NULL;
482 /* Set up the header of the chain. */
483 m->m_pkthdr.rcvif = ifp;
484 m->m_pkthdr.len = 0;
485 for (n = m; n != NULL; n = n->m_next)
486 m->m_pkthdr.len += n->m_len;
487 reply = eco_inputframe(ifp, m);
488 } else
489 ifp->if_iqdrops++;
492 /* 2: Are there any errors waiting? */
493 if (sr2 & MC6854_SR2_OVRN) {
494 fiq_getregs(&fr);
495 mtail = sc->sc_fiqstate.efs_rx_curmbuf;
496 log(LOG_ERR, "%s: Rx overrun (state = %d, len = %ld)\n",
497 device_xname(sc->sc_dev), sc->sc_ec.ec_state,
498 (char *)(fr.fr_r9) - mtod(mtail, char *));
499 ifp->if_ierrors++;
501 /* Discard the rest of the frame. */
502 if (!sc->sc_transmitting)
503 bus_space_write_1(iot, ioh, MC6854_CR1,
504 sc->sc_cr1 | MC6854_CR1_DISCONTINUE);
505 } else if (sr2 & MC6854_SR2_RXABT) {
506 log(LOG_NOTICE, "%s: Rx abort\n", device_xname(sc->sc_dev));
507 ifp->if_ierrors++;
508 } else if (sr2 & MC6854_SR2_ERR) {
509 log(LOG_NOTICE, "%s: CRC error\n", device_xname(sc->sc_dev));
510 ifp->if_ierrors++;
513 if (__predict_false(sr2 & MC6854_SR2_NDCD)) {
514 log(LOG_ERR, "%s: No clock\n", device_xname(sc->sc_dev));
515 ifp->if_ierrors++;
517 if (sc->sc_fiqstate.efs_rx_curmbuf == NULL) {
518 log(LOG_NOTICE, "%s: Oversized frame\n",
519 device_xname(sc->sc_dev));
520 ifp->if_ierrors++;
521 /* Discard the rest of the frame. */
522 if (!sc->sc_transmitting)
523 bus_space_write_1(iot, ioh, MC6854_CR1,
524 sc->sc_cr1 | MC6854_CR1_DISCONTINUE);
528 bus_space_write_1(iot, ioh, MC6854_CR2,
529 sc->sc_cr2 | MC6854_CR2_CLR_RX_ST);
531 if (reply) {
532 KASSERT(sc->sc_fiqstate.efs_rx_flags & ERXF_FLAGFILL);
533 eca_init_rx_soft(sc);
534 eca_txframe(ifp, reply);
535 } else {
536 /* KASSERT(!sc->sc_transmitting); */
537 if (sc->sc_fiqstate.efs_rx_flags & ERXF_FLAGFILL)
538 /* Stop flag-filling: we have nothing to send. */
539 bus_space_write_1(iot, ioh, MC6854_CR2,
540 sc->sc_cr2);
541 /* Set the ADLC up to receive the next frame. */
542 eca_init_rx(sc);
543 /* 3: Is the network idle now? */
544 if (sr2 & MC6854_SR2_RX_IDLE)
545 eco_inputidle(ifp);