xref: /trueos/sys/dev/cm/smc90cx6.c (revision b972b67ed72b5687a023c92602aaef64163b2f59)
1 /*	$NetBSD: smc90cx6.c,v 1.38 2001/07/07 15:57:53 thorpej Exp $ */
2 
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5 
6 /*-
7  * Copyright (c) 1994, 1995, 1998 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Ignatios Souvatzis.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * Chip core driver for the SMC90c26 / SMC90c56 (and SMC90c66 in '56
37  * compatibility mode) boards
38  */
39 
40 /* #define CMSOFTCOPY */
41 #define CMRETRANSMIT /**/
42 /* #define CM_DEBUG */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/sockio.h>
47 #include <sys/mbuf.h>
48 #include <sys/module.h>
49 #include <sys/kernel.h>
50 #include <sys/socket.h>
51 #include <sys/syslog.h>
52 #include <sys/bus.h>
53 
54 #include <machine/bus.h>
55 #include <sys/rman.h>
56 #include <machine/resource.h>
57 
58 #include <net/if.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
61 #include <net/if_arc.h>
62 
63 #include <dev/cm/smc90cx6reg.h>
64 #include <dev/cm/smc90cx6var.h>
65 
66 MODULE_DEPEND(if_cm, arcnet, 1, 1, 1);
67 
68 /* these should be elsewhere */
69 
70 #define ARC_MIN_LEN 1
71 #define ARC_MIN_FORBID_LEN 254
72 #define ARC_MAX_FORBID_LEN 256
73 #define ARC_MAX_LEN 508
74 #define ARC_ADDR_LEN 1
75 
76 /* for watchdog timer. This should be more than enough. */
77 #define ARCTIMEOUT (5*IFNET_SLOWHZ)
78 
79 devclass_t cm_devclass;
80 
81 /*
82  * This currently uses 2 bufs for tx, 2 for rx
83  *
84  * New rx protocol:
85  *
86  * rx has a fillcount variable. If fillcount > (NRXBUF-1),
87  * rx can be switched off from rx hard int.
88  * Else rx is restarted on the other receiver.
89  * rx soft int counts down. if it is == (NRXBUF-1), it restarts
90  * the receiver.
91  * To ensure packet ordering (we need that for 1201 later), we have a counter
92  * which is incremented modulo 256 on each receive and a per buffer
93  * variable, which is set to the counter on filling. The soft int can
94  * compare both values to determine the older packet.
95  *
96  * Transmit direction:
97  *
98  * cm_start checks tx_fillcount
99  * case 2: return
100  *
101  * else fill tx_act ^ 1 && inc tx_fillcount
102  *
103  * check tx_fillcount again.
104  * case 2: set IFF_DRV_OACTIVE to stop arc_output from filling us.
105  * case 1: start tx
106  *
107  * tint clears IFF_OACTIVE, decrements and checks tx_fillcount
108  * case 1: start tx on tx_act ^ 1, softcall cm_start
109  * case 0: softcall cm_start
110  *
111  * #define fill(i) get mbuf && copy mbuf to chip(i)
112  */
113 
114 void	cm_init(void *);
115 static void cm_init_locked(struct cm_softc *);
116 static void cm_reset_locked(struct cm_softc *);
117 void	cm_start(struct ifnet *);
118 void	cm_start_locked(struct ifnet *);
119 int	cm_ioctl(struct ifnet *, unsigned long, caddr_t);
120 void	cm_watchdog(void *);
121 void	cm_srint_locked(void *vsc);
122 static	void cm_tint_locked(struct cm_softc *, int);
123 void	cm_reconwatch_locked(void *);
124 
125 /*
126  * Release all resources
127  */
128 void
cm_release_resources(dev)129 cm_release_resources(dev)
130 	device_t dev;
131 {
132 	struct cm_softc *sc = device_get_softc(dev);
133 
134 	if (sc->port_res != NULL) {
135 		bus_release_resource(dev, SYS_RES_IOPORT,
136 				     0, sc->port_res);
137 		sc->port_res = NULL;
138 	}
139 	if (sc->mem_res != NULL) {
140 		bus_release_resource(dev, SYS_RES_MEMORY,
141 				     0, sc->mem_res);
142 		sc->mem_res = NULL;
143 	}
144 	if (sc->irq_res != NULL) {
145 		bus_release_resource(dev, SYS_RES_IRQ,
146 				     0, sc->irq_res);
147 		sc->irq_res = NULL;
148 	}
149 }
150 
151 int
cm_attach(dev)152 cm_attach(dev)
153 	device_t dev;
154 {
155 	struct cm_softc *sc = device_get_softc(dev);
156 	struct ifnet *ifp;
157 	u_int8_t linkaddress;
158 
159 	ifp = sc->sc_ifp = if_alloc(IFT_ARCNET);
160 	if (ifp == NULL)
161 		return (ENOSPC);
162 
163 	/*
164 	 * read the arcnet address from the board
165 	 */
166 	GETREG(CMRESET);
167 	do {
168 		DELAY(200);
169 	} while (!(GETREG(CMSTAT) & CM_POR));
170 	linkaddress = GETMEM(CMMACOFF);
171 
172 	/* clear the int mask... */
173 	sc->sc_intmask = 0;
174 	PUTREG(CMSTAT, 0);
175 
176 	PUTREG(CMCMD, CM_CONF(CONF_LONG));
177 	PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG));
178 	sc->sc_recontime = sc->sc_reconcount = 0;
179 
180 	/*
181 	 * set interface to stopped condition (reset)
182 	 */
183 	cm_stop_locked(sc);
184 
185 	ifp->if_softc = sc;
186 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
187 	ifp->if_output = arc_output;
188 	ifp->if_start = cm_start;
189 	ifp->if_ioctl = cm_ioctl;
190 	ifp->if_init = cm_init;
191 	/* XXX IFQ_SET_READY(&ifp->if_snd); */
192 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
193 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
194 
195 	arc_ifattach(ifp, linkaddress);
196 
197 #ifdef CMSOFTCOPY
198 	sc->sc_rxcookie = softintr_establish(IPL_SOFTNET, cm_srint, sc);
199 	sc->sc_txcookie = softintr_establish(IPL_SOFTNET,
200 		(void (*)(void *))cm_start, ifp);
201 #endif
202 
203 	callout_init_mtx(&sc->sc_recon_ch, &sc->sc_mtx, 0);
204 	callout_init_mtx(&sc->sc_watchdog_timer, &sc->sc_mtx, 0);
205 
206 	if_printf(ifp, "link addr 0x%02x (%d)\n", linkaddress, linkaddress);
207 	return 0;
208 }
209 
210 /*
211  * Initialize device
212  *
213  */
214 void
cm_init(xsc)215 cm_init(xsc)
216 	void *xsc;
217 {
218 	struct cm_softc *sc = (struct cm_softc *)xsc;
219 
220 	CM_LOCK(sc);
221 	cm_init_locked(sc);
222 	CM_UNLOCK(sc);
223 }
224 
225 static void
cm_init_locked(struct cm_softc * sc)226 cm_init_locked(struct cm_softc *sc)
227 {
228 	struct ifnet *ifp = sc->sc_ifp;
229 
230 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
231 		ifp->if_drv_flags |= IFF_DRV_RUNNING;
232 		cm_reset_locked(sc);
233 	}
234 }
235 
236 /*
237  * Reset the interface...
238  *
239  * Assumes that it is called with sc_mtx held
240  */
241 void
cm_reset_locked(sc)242 cm_reset_locked(sc)
243 	struct cm_softc *sc;
244 {
245 	struct ifnet *ifp;
246 	int linkaddress;
247 
248 	ifp = sc->sc_ifp;
249 
250 #ifdef CM_DEBUG
251 	if_printf(ifp, "reset\n");
252 #endif
253 	/* stop and restart hardware */
254 
255 	GETREG(CMRESET);
256 	do {
257 		DELAY(200);
258 	} while (!(GETREG(CMSTAT) & CM_POR));
259 
260 	linkaddress = GETMEM(CMMACOFF);
261 
262 #if defined(CM_DEBUG) && (CM_DEBUG > 2)
263 	if_printf(ifp, "reset: card reset, link addr = 0x%02x (%d)\n",
264 	    linkaddress, linkaddress);
265 #endif
266 
267 	/* tell the routing level about the (possibly changed) link address */
268 	arc_storelladdr(ifp, linkaddress);
269 	arc_frag_init(ifp);
270 
271 	/* POR is NMI, but we need it below: */
272 	sc->sc_intmask = CM_RECON|CM_POR;
273 	PUTREG(CMSTAT, sc->sc_intmask);
274 	PUTREG(CMCMD, CM_CONF(CONF_LONG));
275 
276 #ifdef CM_DEBUG
277 	if_printf(ifp, "reset: chip configured, status=0x%02x\n",
278 	    GETREG(CMSTAT));
279 #endif
280 	PUTREG(CMCMD, CM_CLR(CLR_POR|CLR_RECONFIG));
281 
282 #ifdef CM_DEBUG
283 	if_printf(ifp, "reset: bits cleared, status=0x%02x\n",
284 	     GETREG(CMSTAT));
285 #endif
286 
287 	sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
288 
289 	/* start receiver */
290 
291 	sc->sc_intmask  |= CM_RI;
292 	sc->sc_rx_fillcount = 0;
293 	sc->sc_rx_act = 2;
294 
295 	PUTREG(CMCMD, CM_RXBC(2));
296 	PUTREG(CMSTAT, sc->sc_intmask);
297 
298 #ifdef CM_DEBUG
299 	if_printf(ifp, "reset: started receiver, status=0x%02x\n",
300 	    GETREG(CMSTAT));
301 #endif
302 
303 	/* and init transmitter status */
304 	sc->sc_tx_act = 0;
305 	sc->sc_tx_fillcount = 0;
306 
307 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
308 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
309 
310 	callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc);
311 	cm_start_locked(ifp);
312 }
313 
314 /*
315  * Take interface offline
316  */
317 void
cm_stop_locked(sc)318 cm_stop_locked(sc)
319 	struct cm_softc *sc;
320 {
321 	/* Stop the interrupts */
322 	PUTREG(CMSTAT, 0);
323 
324 	/* Stop the interface */
325 	GETREG(CMRESET);
326 
327 	/* Stop watchdog timer */
328 	callout_stop(&sc->sc_watchdog_timer);
329 	sc->sc_timer = 0;
330 }
331 
332 void
cm_start(struct ifnet * ifp)333 cm_start(struct ifnet *ifp)
334 {
335 	struct cm_softc *sc = ifp->if_softc;
336 
337 	CM_LOCK(sc);
338 	cm_start_locked(ifp);
339 	CM_UNLOCK(sc);
340 }
341 
342 /*
343  * Start output on interface. Get another datagram to send
344  * off the interface queue, and copy it to the
345  * interface becore starting the output
346  *
347  * Assumes that sc_mtx is held
348  */
349 void
cm_start_locked(ifp)350 cm_start_locked(ifp)
351 	struct ifnet *ifp;
352 {
353 	struct cm_softc *sc = ifp->if_softc;
354 	struct mbuf *m, *mp;
355 
356 	int cm_ram_ptr;
357 	int len, tlen, offset, buffer;
358 #ifdef CMTIMINGS
359 	u_long copystart, lencopy, perbyte;
360 #endif
361 
362 #if defined(CM_DEBUG) && (CM_DEBUG > 3)
363 	if_printf(ifp, "start(%p)\n", ifp);
364 #endif
365 
366 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
367 		return;
368 
369 	if (sc->sc_tx_fillcount >= 2)
370 		return;
371 
372 	m = arc_frag_next(ifp);
373 	buffer = sc->sc_tx_act ^ 1;
374 
375 	if (m == 0)
376 		return;
377 
378 #ifdef CM_DEBUG
379 	if (m->m_len < ARC_HDRLEN)
380 		m = m_pullup(m, ARC_HDRLEN);/* gcc does structure padding */
381 	if_printf(ifp, "start: filling %d from %d to %d type %d\n",
382 	    buffer, mtod(m, u_char *)[0],
383 	    mtod(m, u_char *)[1], mtod(m, u_char *)[2]);
384 #else
385 	if (m->m_len < 2)
386 		m = m_pullup(m, 2);
387 #endif
388 	cm_ram_ptr = buffer * 512;
389 
390 	if (m == 0)
391 		return;
392 
393 	/* write the addresses to RAM and throw them away */
394 
395 	/*
396 	 * Hardware does this: Yet Another Microsecond Saved.
397 	 * (btw, timing code says usually 2 microseconds)
398 	 * PUTMEM(cm_ram_ptr + 0, mtod(m, u_char *)[0]);
399 	 */
400 
401 	PUTMEM(cm_ram_ptr + 1, mtod(m, u_char *)[1]);
402 	m_adj(m, 2);
403 
404 	/* get total length left at this point */
405 	tlen = m->m_pkthdr.len;
406 	if (tlen < ARC_MIN_FORBID_LEN) {
407 		offset = 256 - tlen;
408 		PUTMEM(cm_ram_ptr + 2, offset);
409 	} else {
410 		PUTMEM(cm_ram_ptr + 2, 0);
411 		if (tlen <= ARC_MAX_FORBID_LEN)
412 			offset = 255;		/* !!! */
413 		else {
414 			if (tlen > ARC_MAX_LEN)
415 				tlen = ARC_MAX_LEN;
416 			offset = 512 - tlen;
417 		}
418 		PUTMEM(cm_ram_ptr + 3, offset);
419 
420 	}
421 	cm_ram_ptr += offset;
422 
423 	/* lets loop through the mbuf chain */
424 
425 	for (mp = m; mp; mp = mp->m_next) {
426 		if ((len = mp->m_len)) {		/* YAMS */
427 			bus_space_write_region_1(
428 			    rman_get_bustag(sc->mem_res),
429 			    rman_get_bushandle(sc->mem_res),
430 			    cm_ram_ptr, mtod(mp, caddr_t), len);
431 
432 			cm_ram_ptr += len;
433 		}
434 	}
435 
436 	sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
437 	sc->sc_retransmits[buffer] = (m->m_flags & M_BCAST) ? 1 : 5;
438 
439 	if (++sc->sc_tx_fillcount > 1) {
440 		/*
441 		 * We are filled up to the rim. No more bufs for the moment,
442 		 * please.
443 		 */
444 		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
445 	} else {
446 #ifdef CM_DEBUG
447 		if_printf(ifp, "start: starting transmitter on buffer %d\n",
448 		    buffer);
449 #endif
450 		/* Transmitter was off, start it */
451 		sc->sc_tx_act = buffer;
452 
453 		/*
454 		 * We still can accept another buf, so don't:
455 		 * ifp->if_drv_flags |= IFF_DRV_OACTIVE;
456 		 */
457 		sc->sc_intmask |= CM_TA;
458 		PUTREG(CMCMD, CM_TX(buffer));
459 		PUTREG(CMSTAT, sc->sc_intmask);
460 
461 		sc->sc_timer = ARCTIMEOUT;
462 	}
463 	m_freem(m);
464 
465 	/*
466 	 * After 10 times reading the docs, I realized
467 	 * that in the case the receiver NAKs the buffer request,
468 	 * the hardware retries till shutdown.
469 	 * This is integrated now in the code above.
470 	 */
471 }
472 
473 #ifdef CMSOFTCOPY
474 void
cm_srint(void * vsc)475 cm_srint(void *vsc)
476 {
477 	struct cm_softc *sc = (struct cm_softc *)vsc;
478 
479 	CM_LOCK(sc);
480 	cm_srint_locked(vsc);
481 	CM_UNLOCK(sc);
482 }
483 #endif
484 
485 /*
486  * Arcnet interface receiver soft interrupt:
487  * get the stuff out of any filled buffer we find.
488  */
489 void
cm_srint_locked(vsc)490 cm_srint_locked(vsc)
491 	void *vsc;
492 {
493 	struct cm_softc *sc = (struct cm_softc *)vsc;
494 	int buffer, len, offset, type;
495 	int cm_ram_ptr;
496 	struct mbuf *m;
497 	struct arc_header *ah;
498 	struct ifnet *ifp;
499 
500 	ifp = sc->sc_ifp;
501 
502 	buffer = sc->sc_rx_act ^ 1;
503 
504 	/* Allocate header mbuf */
505 	MGETHDR(m, M_NOWAIT, MT_DATA);
506 
507 	if (m == 0) {
508 		/*
509 		 * in case s.th. goes wrong with mem, drop it
510 		 * to make sure the receiver can be started again
511 		 * count it as input error (we dont have any other
512 		 * detectable)
513 		 */
514 		ifp->if_ierrors++;
515 		goto cleanup;
516 	}
517 
518 	m->m_pkthdr.rcvif = ifp;
519 
520 	/*
521 	 * Align so that IP packet will be longword aligned. Here we
522 	 * assume that m_data of new packet is longword aligned.
523 	 * When implementing PHDS, we might have to change it to 2,
524 	 * (2*sizeof(ulong) - CM_HDRNEWLEN)), packet type dependent.
525 	 */
526 
527 	cm_ram_ptr = buffer * 512;
528 	offset = GETMEM(cm_ram_ptr + 2);
529 	if (offset)
530 		len = 256 - offset;
531 	else {
532 		offset = GETMEM(cm_ram_ptr + 3);
533 		len = 512 - offset;
534 	}
535 
536 	/*
537 	 * first +2 bytes for align fixup below
538 	 * second +2 bytes are for src/dst addresses
539 	 */
540 	if ((len + 2 + 2) > MHLEN) {
541 		/* attach an mbuf cluster */
542 		MCLGET(m, M_NOWAIT);
543 
544 		/* Insist on getting a cluster */
545 		if ((m->m_flags & M_EXT) == 0) {
546 			ifp->if_ierrors++;
547 			goto cleanup;
548 		}
549 	}
550 
551 	if (m == 0) {
552 		ifp->if_ierrors++;
553 		goto cleanup;
554 	}
555 
556 	type = GETMEM(cm_ram_ptr + offset);
557 	m->m_data += 1 + arc_isphds(type);
558 	/* mbuf filled with ARCnet addresses */
559 	m->m_pkthdr.len = m->m_len = len + 2;
560 
561 	ah = mtod(m, struct arc_header *);
562 	ah->arc_shost = GETMEM(cm_ram_ptr + 0);
563 	ah->arc_dhost = GETMEM(cm_ram_ptr + 1);
564 
565 	bus_space_read_region_1(
566 	    rman_get_bustag(sc->mem_res), rman_get_bushandle(sc->mem_res),
567 	    cm_ram_ptr + offset, mtod(m, u_char *) + 2, len);
568 
569 	CM_UNLOCK(sc);
570 	arc_input(ifp, m);
571 	CM_LOCK(sc);
572 
573 	m = NULL;
574 	ifp->if_ipackets++;
575 
576 cleanup:
577 
578 	if (m != NULL)
579 		m_freem(m);
580 
581 	/* mark buffer as invalid by source id 0 */
582 	PUTMEM(buffer << 9, 0);
583 	if (--sc->sc_rx_fillcount == 2 - 1) {
584 
585 		/* was off, restart it on buffer just emptied */
586 		sc->sc_rx_act = buffer;
587 		sc->sc_intmask |= CM_RI;
588 
589 		/* this also clears the RI flag interrupt: */
590 		PUTREG(CMCMD, CM_RXBC(buffer));
591 		PUTREG(CMSTAT, sc->sc_intmask);
592 
593 #ifdef CM_DEBUG
594 		if_printf(ifp, "srint: restarted rx on buf %d\n", buffer);
595 #endif
596 	}
597 }
598 
599 static inline void
cm_tint_locked(sc,isr)600 cm_tint_locked(sc, isr)
601 	struct cm_softc *sc;
602 	int isr;
603 {
604 	struct ifnet *ifp;
605 
606 	int buffer;
607 #ifdef CMTIMINGS
608 	int clknow;
609 #endif
610 
611 	ifp = sc->sc_ifp;
612 	buffer = sc->sc_tx_act;
613 
614 	/*
615 	 * retransmit code:
616 	 * Normal situtations first for fast path:
617 	 * If acknowledgement received ok or broadcast, we're ok.
618 	 * else if
619 	 */
620 
621 	if (isr & CM_TMA || sc->sc_broadcast[buffer])
622 		ifp->if_opackets++;
623 #ifdef CMRETRANSMIT
624 	else if (ifp->if_flags & IFF_LINK2 && sc->sc_timer > 0
625 	    && --sc->sc_retransmits[buffer] > 0) {
626 		/* retransmit same buffer */
627 		PUTREG(CMCMD, CM_TX(buffer));
628 		return;
629 	}
630 #endif
631 	else
632 		ifp->if_oerrors++;
633 
634 
635 	/* We know we can accept another buffer at this point. */
636 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
637 
638 	if (--sc->sc_tx_fillcount > 0) {
639 
640 		/*
641 		 * start tx on other buffer.
642 		 * This also clears the int flag
643 		 */
644 		buffer ^= 1;
645 		sc->sc_tx_act = buffer;
646 
647 		/*
648 		 * already given:
649 		 * sc->sc_intmask |= CM_TA;
650 		 * PUTREG(CMSTAT, sc->sc_intmask);
651 		 */
652 		PUTREG(CMCMD, CM_TX(buffer));
653 		/* init watchdog timer */
654 		sc->sc_timer = ARCTIMEOUT;
655 
656 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
657 		if_printf(ifp,
658 		    "tint: starting tx on buffer %d, status 0x%02x\n",
659 		    buffer, GETREG(CMSTAT));
660 #endif
661 	} else {
662 		/* have to disable TX interrupt */
663 		sc->sc_intmask &= ~CM_TA;
664 		PUTREG(CMSTAT, sc->sc_intmask);
665 		/* ... and watchdog timer */
666 		sc->sc_timer = 0;
667 
668 #ifdef CM_DEBUG
669 		if_printf(ifp, "tint: no more buffers to send, status 0x%02x\n",
670 		    GETREG(CMSTAT));
671 #endif
672 	}
673 
674 	/* XXXX TODO */
675 #ifdef CMSOFTCOPY
676 	/* schedule soft int to fill a new buffer for us */
677 	softintr_schedule(sc->sc_txcookie);
678 #else
679 	/* call it directly */
680 	cm_start_locked(ifp);
681 #endif
682 }
683 
684 /*
685  * Our interrupt routine
686  */
687 void
cmintr(arg)688 cmintr(arg)
689 	void *arg;
690 {
691 	struct cm_softc *sc = arg;
692 	struct ifnet *ifp = sc->sc_ifp;
693 
694 	u_char isr, maskedisr;
695 	int buffer;
696 	u_long newsec;
697 
698 	CM_LOCK(sc);
699 
700 	isr = GETREG(CMSTAT);
701 	maskedisr = isr & sc->sc_intmask;
702 	if (!maskedisr || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
703 		CM_UNLOCK(sc);
704 		return;
705 	}
706 
707 	do {
708 
709 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
710 		if_printf(ifp, "intr: status 0x%02x, intmask 0x%02x\n",
711 		    isr, sc->sc_intmask);
712 #endif
713 
714 		if (maskedisr & CM_POR) {
715 			/*
716 			 * XXX We should never see this. Don't bother to store
717 			 * the address.
718 			 * sc->sc_ifp->if_l2com->ac_anaddr = GETMEM(CMMACOFF);
719 			 */
720 			PUTREG(CMCMD, CM_CLR(CLR_POR));
721 			log(LOG_WARNING,
722 			    "%s: intr: got spurious power on reset int\n",
723 			    ifp->if_xname);
724 		}
725 
726 		if (maskedisr & CM_RECON) {
727 			/*
728 			 * we dont need to:
729 			 * PUTREG(CMCMD, CM_CONF(CONF_LONG));
730 			 */
731 			PUTREG(CMCMD, CM_CLR(CLR_RECONFIG));
732 			ifp->if_collisions++;
733 
734 			/*
735 			 * If less than 2 seconds per reconfig:
736 			 *	If ARC_EXCESSIVE_RECONFIGS
737 			 *	since last burst, complain and set treshold for
738 			 *	warnings to ARC_EXCESSIVE_RECONS_REWARN.
739 			 *
740 			 * This allows for, e.g., new stations on the cable, or
741 			 * cable switching as long as it is over after
742 			 * (normally) 16 seconds.
743 			 *
744 			 * XXX TODO: check timeout bits in status word and
745 			 * double time if necessary.
746 			 */
747 
748 			callout_stop(&sc->sc_recon_ch);
749 			newsec = time_second;
750 			if ((newsec - sc->sc_recontime <= 2) &&
751 			    (++sc->sc_reconcount == ARC_EXCESSIVE_RECONS)) {
752 				log(LOG_WARNING,
753 				    "%s: excessive token losses, "
754 				    "cable problem?\n",
755 				    ifp->if_xname);
756 			}
757 			sc->sc_recontime = newsec;
758 			callout_reset(&sc->sc_recon_ch, 15 * hz,
759 			    cm_reconwatch_locked, (void *)sc);
760 		}
761 
762 		if (maskedisr & CM_RI) {
763 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
764 			if_printf(ifp, "intr: hard rint, act %d\n",
765 			    sc->sc_rx_act);
766 #endif
767 
768 			buffer = sc->sc_rx_act;
769 			/* look if buffer is marked invalid: */
770 			if (GETMEM(buffer * 512) == 0) {
771 				/*
772 				 * invalid marked buffer (or illegally
773 				 * configured sender)
774 				 */
775 				log(LOG_WARNING,
776 				    "%s: spurious RX interrupt or sender 0 "
777 				    " (ignored)\n", ifp->if_xname);
778 				/*
779 				 * restart receiver on same buffer.
780 				 * XXX maybe better reset interface?
781 				 */
782 				PUTREG(CMCMD, CM_RXBC(buffer));
783 			} else {
784 				if (++sc->sc_rx_fillcount > 1) {
785 					sc->sc_intmask &= ~CM_RI;
786 					PUTREG(CMSTAT, sc->sc_intmask);
787 				} else {
788 					buffer ^= 1;
789 					sc->sc_rx_act = buffer;
790 
791 					/*
792 					 * Start receiver on other receive
793 					 * buffer. This also clears the RI
794 					 * interrupt flag.
795 					 */
796 					PUTREG(CMCMD, CM_RXBC(buffer));
797 					/* in RX intr, so mask is ok for RX */
798 
799 #ifdef CM_DEBUG
800 					if_printf(ifp, "strt rx for buf %d, "
801 					    "stat 0x%02x\n",
802 					    sc->sc_rx_act, GETREG(CMSTAT));
803 #endif
804 				}
805 
806 #ifdef CMSOFTCOPY
807 				/*
808 				 * this one starts a soft int to copy out
809 				 * of the hw
810 				 */
811 				softintr_schedule(sc->sc_rxcookie);
812 #else
813 				/* this one does the copy here */
814 				cm_srint_locked(sc);
815 #endif
816 			}
817 		}
818 		if (maskedisr & CM_TA) {
819 			cm_tint_locked(sc, isr);
820 		}
821 		isr = GETREG(CMSTAT);
822 		maskedisr = isr & sc->sc_intmask;
823 	} while (maskedisr);
824 #if defined(CM_DEBUG) && (CM_DEBUG > 1)
825 	if_printf(ifp, "intr (exit): status 0x%02x, intmask 0x%02x\n",
826 	    isr, sc->sc_intmask);
827 #endif
828 	CM_UNLOCK(sc);
829 }
830 
831 void
cm_reconwatch_locked(arg)832 cm_reconwatch_locked(arg)
833 	void *arg;
834 {
835 	struct cm_softc *sc = arg;
836 	struct ifnet *ifp = sc->sc_ifp;
837 
838 	if (sc->sc_reconcount >= ARC_EXCESSIVE_RECONS) {
839 		sc->sc_reconcount = 0;
840 		log(LOG_WARNING, "%s: token valid again.\n",
841 		    ifp->if_xname);
842 	}
843 	sc->sc_reconcount = 0;
844 }
845 
846 
847 /*
848  * Process an ioctl request.
849  * This code needs some work - it looks pretty ugly.
850  */
851 int
cm_ioctl(ifp,command,data)852 cm_ioctl(ifp, command, data)
853 	struct ifnet *ifp;
854 	u_long command;
855 	caddr_t data;
856 {
857 	struct cm_softc *sc;
858 	int error;
859 
860 	error = 0;
861 	sc = ifp->if_softc;
862 
863 #if defined(CM_DEBUG) && (CM_DEBUG > 2)
864 	if_printf(ifp, "ioctl() called, cmd = 0x%lx\n", command);
865 #endif
866 
867 	switch (command) {
868 	case SIOCSIFADDR:
869 	case SIOCGIFADDR:
870 	case SIOCADDMULTI:
871 	case SIOCDELMULTI:
872 	case SIOCSIFMTU:
873 		error = arc_ioctl(ifp, command, data);
874 		break;
875 
876 	case SIOCSIFFLAGS:
877 		CM_LOCK(sc);
878 		if ((ifp->if_flags & IFF_UP) == 0 &&
879 		    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
880 			/*
881 			 * If interface is marked down and it is running,
882 			 * then stop it.
883 			 */
884 			cm_stop_locked(sc);
885 			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
886 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
887 			   (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
888 			/*
889 			 * If interface is marked up and it is stopped, then
890 			 * start it.
891 			 */
892 			cm_init_locked(sc);
893 		}
894 		CM_UNLOCK(sc);
895 		break;
896 
897 	default:
898 		error = EINVAL;
899 		break;
900 	}
901 
902 	return (error);
903 }
904 
905 /*
906  * watchdog routine for transmitter.
907  *
908  * We need this, because else a receiver whose hardware is alive, but whose
909  * software has not enabled the Receiver, would make our hardware wait forever
910  * Discovered this after 20 times reading the docs.
911  *
912  * Only thing we do is disable transmitter. We'll get a transmit timeout,
913  * and the int handler will have to decide not to retransmit (in case
914  * retransmission is implemented).
915  */
916 void
cm_watchdog(void * arg)917 cm_watchdog(void *arg)
918 {
919 	struct cm_softc *sc;
920 
921 	sc = arg;
922 	callout_reset(&sc->sc_watchdog_timer, hz, cm_watchdog, sc);
923 	if (sc->sc_timer == 0 || --sc->sc_timer > 0)
924 		return;
925 	PUTREG(CMCMD, CM_TXDIS);
926 }
927