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