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