1 /* $NetBSD: if_eca.c,v 1.10 2009/01/07 20:56:40 bjh21 Exp $ */
4 * Copyright (c) 2001 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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>
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
);
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)
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
];
101 sc
->sc_iot
= ioc
->ioc_sync_t
;
102 sc
->sc_ioh
= ioc
->ioc_sync_h
;
104 myaddr
[0] = cmos_read(0x40);
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
) &
111 printf(", no clock");
113 /* Initialise ifnet structure. */
115 strcpy(ifp
->if_xname
, device_xname(sc
->sc_dev
));
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");
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
;
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
;
152 if ((err
= eco_init(ifp
)) != 0)
155 /* Claim the FIQ early, in case we don't get it. */
156 if ((err
= fiq_claim(&sc
->sc_fiqhandler
)) != 0)
159 if (sc
->sc_rcvmbuf
== NULL
) {
160 err
= eca_init_rxbuf(sc
, M_WAIT
);
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. */
171 /* Nothing exciting. */
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 */
196 ifp
->if_flags
|= IFF_RUNNING
;
202 * Check if the network's idle, and if it is, start flag-filling.
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
);
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
;
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;
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
;
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
));
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
;
262 KASSERT(sc
->sc_transmitting
);
264 if (__predict_true(sc
->sc_fiqstate
.efs_tx_curmbuf
== NULL
)) {
265 /* Entire frame got transmitted. */
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
));
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;
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.
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
;
313 * Set up the Rx buffer for the interface.
314 * flags is M_WAIT or M_DONTWAIT. Returns an errno or 0 for success.
317 eca_init_rxbuf(struct eca_softc
*sc
, int flags
)
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.
331 while (totlen
< sc
->sc_ec
.ec_if
.if_mtu
+ ECO_HDR_LEN
) {
332 MGETHDR(m
, flags
, MT_DATA
);
336 if ((m
->m_flags
& M_EXT
) == 0) {
340 /* XXX may want to tweak for payload alignment here. */
341 m
->m_len
= m
->m_ext
.ext_size
;
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.
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!
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
);
391 fiq_downgrade_handler
= eca_rx_downgrade
;
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().
401 eca_init_rx(struct eca_softc
*sc
)
404 eca_init_rx_soft(sc
);
405 eca_init_rx_hard(sc
);
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
);
424 fiq_downgrade_handler
= 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).
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
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
;
460 struct mbuf
*m
, *mtail
, *n
, *reply
;
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
) {
470 mtail
= sc
->sc_fiqstate
.efs_rx_curmbuf
;
472 * Before we process this buffer, make sure we can get
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. */
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
;
485 for (n
= m
; n
!= NULL
; n
= n
->m_next
)
486 m
->m_pkthdr
.len
+= n
->m_len
;
487 reply
= eco_inputframe(ifp
, m
);
492 /* 2: Are there any errors waiting? */
493 if (sr2
& MC6854_SR2_OVRN
) {
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 *));
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
));
508 } else if (sr2
& MC6854_SR2_ERR
) {
509 log(LOG_NOTICE
, "%s: CRC error\n", device_xname(sc
->sc_dev
));
513 if (__predict_false(sr2
& MC6854_SR2_NDCD
)) {
514 log(LOG_ERR
, "%s: No clock\n", device_xname(sc
->sc_dev
));
517 if (sc
->sc_fiqstate
.efs_rx_curmbuf
== NULL
) {
518 log(LOG_NOTICE
, "%s: Oversized frame\n",
519 device_xname(sc
->sc_dev
));
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
);
532 KASSERT(sc
->sc_fiqstate
.efs_rx_flags
& ERXF_FLAGFILL
);
533 eca_init_rx_soft(sc
);
534 eca_txframe(ifp
, reply
);
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
,
541 /* Set the ADLC up to receive the next frame. */
543 /* 3: Is the network idle now? */
544 if (sr2
& MC6854_SR2_RX_IDLE
)