smc90cx6.c revision 1.3 1 /* $NetBSD: smc90cx6.c,v 1.3 1995/03/02 09:12:27 chopps Exp $ */
2
3 /*
4 * Copyright (c) 1994, 1995 Ignatios Souvatzis
5 * Copyright (c) 1994 Timo Rossi
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Timo Rossi
19 * This product includes software developed by Ignatios Souvatzis
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * Driver for the Commodore Busines Machines arcnet card
37 * written by Ignatios Souvatzis <is (at) beverly.rhein.de>,
38 * somewhat based on Amiga if_ed.c
39 */
40
41 #define BAHASMCOPY /**/
42 #define BAHSOFTCOPY /**/
43 /* #define BAHTIMINGS /**/
44 /* #define BAH_DEBUG 3 /**/
45
46 #include "bpfilter.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/mbuf.h>
51 #include <sys/buf.h>
52 #include <sys/device.h>
53 #include <sys/protosw.h>
54 #include <sys/socket.h>
55 #include <sys/syslog.h>
56 #include <sys/ioctl.h>
57 #include <sys/errno.h>
58
59 #include <net/if.h>
60 #include <net/if_dl.h>
61 #include <net/if_types.h>
62 #include <net/netisr.h>
63
64 #ifdef INET
65 #include <netinet/in.h>
66 #include <netinet/in_systm.h>
67 #include <netinet/in_var.h>
68 #include <netinet/ip.h>
69 #include <netinet/if_ether.h>
70 #include <netinet/if_arc.h>
71 #endif
72
73 #if NBPFILTER > 0
74 #include <net/bpf.h>
75 #include <net/bpfdesc.h>
76 #endif
77
78 #include <sys/kernel.h>
79 #include <machine/cpu.h>
80 #include <machine/mtpr.h>
81
82 #include <amiga/amiga/device.h>
83 #include <amiga/amiga/isr.h>
84 #include <amiga/dev/zbusvar.h>
85 #include <amiga/dev/if_bahreg.h>
86
87 /* these should be elsewhere */
88
89 #define ARC_MIN_LEN 1
90 #define ARC_MIN_FORBID_LEN 254
91 #define ARC_MAX_FORBID_LEN 256
92 #define ARC_MAX_LEN 508
93 #define ARC_ADDR_LEN 1
94
95 #define MIN(a,b) ((b)<0?(a):min((a),(b)))
96
97 /*
98 * This currently uses 2 bufs for tx, 2 for rx
99 *
100 * New rx protocol:
101 *
102 * rx has a fillcount variable. If fillcount > (NRXBUF-1),
103 * rx can be switched off from rx hard int.
104 * Else rx is restarted on the other receiver.
105 * rx soft int counts down. if it is == (NRXBUF-1), it restarts
106 * the receiver.
107 * To ensure packet ordering (we need that for 1201 later), we have a counter
108 * which is incremented modulo 256 on each receive and a per buffer
109 * variable, which is set to the counter on filling. The soft int can
110 * compare both values to determine the older packet.
111 *
112 * Transmit direction:
113 *
114 * bah_start checks tx_fillcount
115 * case 2: return
116 *
117 * else fill tx_act ^ 1 && inc tx_fillcount
118 *
119 * check tx_fillcount again.
120 * case 2: set IFF_OACTIVE to stop arc_output from filling us.
121 * case 1: start tx
122 *
123 * tint clears IFF_OCATIVE, decrements and checks tx_fillcount
124 * case 1: start tx on tx_act ^ 1, softcall bah_start
125 * case 0: softcall bah_start
126 *
127 * #define fill(i) get mbuf && copy mbuf to chip(i)
128 */
129
130 /*
131 * Arcnet software status per interface
132 *
133 */
134 struct bah_softc {
135 struct device sc_dev;
136 struct arccom sc_arccom; /* Common arcnet structures */
137 struct isr sc_isr;
138 struct a2060 *sc_base;
139 u_long sc_recontime; /* seconds only, I'm lazy */
140 u_long sc_reconcount; /* for the above */
141 u_long sc_reconcount_excessive; /* for the above */
142 #define ARC_EXCESSIVE_RECONS 20
143 #define ARC_EXCESSIVE_RECONS_REWARN 400
144 u_char sc_bufstat[4]; /* use for packet no for rx */
145 u_char sc_intmask;
146 u_char sc_rx_packetno;
147 u_char sc_rx_act; /* 2..3 */
148 u_char sc_tx_act; /* 0..1 */
149 u_char sc_rx_fillcount;
150 u_char sc_tx_fillcount;
151 u_char sc_broadcast[2]; /* is it a broadcast packet? */
152 u_char sc_retransmits[2]; /* unused at the moment */
153 #ifdef BAHTIMINGS
154 struct {
155 int mincopyin;
156 int maxcopyin; /* divided by byte count */
157 int mincopyout;
158 int maxcopyout;
159 int minsend;
160 int maxsend;
161 int lasttxstart_mics;
162 struct timeval lasttxstart_tv;
163
164 } sc_stats;
165 #endif
166 #if NBPFILTER > 0
167 caddr_t sc_bpf;
168 #endif
169 /* Add other fields as needed... -- IS */
170 };
171
172 /* prototypes */
173
174 int bahmatch __P((struct device *, struct cfdata *, void *));
175 void bahattach __P((struct device *, struct device *, void *));
176 void bah_ini __P((struct bah_softc *));
177 void bah_reset __P((struct bah_softc *));
178 void bah_stop __P((struct bah_softc *));
179 int bah_start __P((struct ifnet *));
180 int bahintr __P((struct bah_softc *sc));
181 int bah_ioctl __P((struct ifnet *, unsigned long, caddr_t));
182 void movepout __P((u_char *from, u_char volatile *to, int len));
183 void movepin __P((u_char volatile *from, u_char *to, int len));
184 void bah_srint __P((struct bah_softc *sc, void *dummy));
185 void callstart __P((struct bah_softc *sc, void *dummy));
186
187 #ifdef BAHTIMINGS
188 int clkread();
189 #endif
190
191 struct cfdriver bahcd = {
192 NULL, "bah", (cfmatch_t)bahmatch, bahattach, DV_IFNET,
193 sizeof(struct bah_softc),
194 };
195
196 int
197 bahmatch(pdp, cfp, auxp)
198 struct device *pdp;
199 struct cfdata *cfp;
200 void *auxp;
201 {
202 struct zbus_args *zap;
203
204 zap = auxp;
205
206 if ((zap->manid == 514 || zap->manid == 1053) && zap->prodid == 9)
207 return (1);
208 return (0);
209 }
210
211 void
212 bahattach(pdp, dp, auxp)
213 struct device *pdp, *dp;
214 void *auxp;
215 {
216 struct zbus_args *zap;
217 struct bah_softc *sc;
218 struct ifnet *ifp;
219 int i, s, linkaddress;
220
221 zap = auxp;
222 sc = (struct bah_softc *)dp;
223 ifp = &sc->sc_arccom.ac_if;
224
225 #if (defined(BAH_DEBUG) && (BAH_DEBUG > 2))
226 printf("\nbah%ld: attach(0x%x, 0x%x, 0x%x)\n",
227 sc->sc_dev.dv_unit, pdp, dp, auxp);
228 #endif
229 s = splhigh();
230 sc->sc_base = zap->va;
231
232 /*
233 * read the arcnet address from the board
234 */
235
236 sc->sc_base->kick1 = 0x0;
237 sc->sc_base->kick2 = 0x0;
238 DELAY(120);
239
240 sc->sc_base->kick1 = 0xFF;
241 sc->sc_base->kick2 = 0xFF;
242 do {
243 DELAY(120);
244 } while (!(sc->sc_base->status & ARC_POR));
245
246 linkaddress = sc->sc_base->dipswitches;
247
248 #ifdef BAHTIMINGS
249 printf(": link addr 0x%02x(%ld), with timer\n",
250 linkaddress, linkaddress);
251 #else
252 printf(": link addr 0x%02x(%ld)\n", linkaddress, linkaddress);
253 #endif
254
255 sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches;
256
257 /* clear the int mask... */
258
259 sc->sc_base->status = sc->sc_intmask = 0;
260
261 sc->sc_base->command = ARC_CONF(CONF_LONG);
262 sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
263 sc->sc_recontime = sc->sc_reconcount = 0;
264
265 /* and reenable kernel int level */
266 splx(s);
267
268 /*
269 * set interface to stopped condition (reset)
270 *
271 */
272 bah_stop(sc);
273
274 ifp->if_unit = sc->sc_dev.dv_unit;
275 ifp->if_name = bahcd.cd_name;
276 ifp->if_output = arc_output;
277 ifp->if_start = bah_start;
278 ifp->if_ioctl = bah_ioctl;
279 /* might need later: ifp->if_watchdog = bah_watchdog */
280
281 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX |
282 IFF_NOTRAILERS | IFF_NOARP;
283
284 ifp->if_mtu = ARCMTU;
285
286 #if NBPFILTER > 0
287 bpfattach(&sc->sc_bpf, ifp, DLT_ARCNET, ARC_HDRLEN);
288 #endif
289
290 if_attach(ifp);
291 arc_ifattach(ifp);
292
293 sc->sc_isr.isr_intr = bahintr;
294 sc->sc_isr.isr_arg = sc;
295 sc->sc_isr.isr_ipl = 2;
296 add_isr(&sc->sc_isr);
297 }
298
299 /*
300 * Initialize device
301 *
302 */
303 void
304 bah_init(sc)
305 struct bah_softc *sc;
306 {
307 struct ifnet *ifp;
308 int s;
309
310 ifp = &sc->sc_arccom.ac_if;
311
312 /* Address not known. */
313 if (ifp->if_addrlist == 0)
314 return;
315
316 if ((ifp->if_flags & IFF_RUNNING) == 0) {
317 s = splimp();
318 ifp->if_flags |= IFF_RUNNING;
319 bah_reset(sc);
320 (void)bah_start(ifp);
321 splx(s);
322 }
323 }
324
325 /*
326 * Reset the interface...
327 *
328 * this assumes that it is called inside a critical section...
329 *
330 */
331 void
332 bah_reset(sc)
333 struct bah_softc *sc;
334 {
335 struct ifnet *ifp;
336 int i, s;
337
338 ifp = &sc->sc_arccom.ac_if;
339
340 #ifdef BAH_DEBUG
341 printf("bah%ld: reset\n", ifp->if_unit);
342 #endif
343 /* stop hardware in case it still runs */
344
345 sc->sc_base->kick1 = 0;
346 sc->sc_base->kick2 = 0;
347 DELAY(120);
348
349 /* and restart it */
350 sc->sc_base->kick1 = 0xFF;
351 sc->sc_base->kick2 = 0xFF;
352
353 do {
354 DELAY(120);
355 } while (!(sc->sc_base->status & ARC_POR));
356
357 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
358 printf("bah%ld: reset: card reset, status=0x%02x\n",
359 ifp->if_unit,
360 sc->sc_base->status);
361 #endif
362 /* POR is NMI, but we need it below: */
363 sc->sc_intmask = ARC_RECON|ARC_POR;
364 sc->sc_base->status = sc->sc_intmask;
365 sc->sc_base->command = ARC_CONF(CONF_LONG);
366
367 #ifdef BAH_DEBUG
368 printf("bah%ld: reset: chip configured, status=0x%02x\n",
369 ifp->if_unit,
370 sc->sc_base->status);
371 #endif
372
373 sc->sc_base->command = ARC_CLR(CLR_POR|CLR_RECONFIG);
374
375 #ifdef BAH_DEBUG
376 printf("bah%ld: reset: bits cleared, status=0x%02x\n",
377 ifp->if_unit,
378 sc->sc_base->status);
379 #endif
380
381 sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
382
383 /* start receiver */
384
385 sc->sc_intmask |= ARC_RI;
386
387 sc->sc_bufstat[2] =
388 sc->sc_bufstat[3] =
389 sc->sc_rx_packetno =
390 sc->sc_rx_fillcount = 0;
391
392 sc->sc_rx_act = 2;
393
394 sc->sc_base->command = ARC_RXBC(2);
395 sc->sc_base->status = sc->sc_intmask;
396
397 #ifdef BAH_DEBUG
398 printf("bah%ld: reset: started receiver, status=0x%02x\n",
399 ifp->if_unit,
400 sc->sc_base->status);
401 #endif
402
403 /* and init transmitter status */
404 sc->sc_tx_act = 0;
405 sc->sc_tx_fillcount = 0;
406
407 ifp->if_flags |= IFF_RUNNING;
408 ifp->if_flags &= ~IFF_OACTIVE;
409
410 #ifdef BAHTIMINGS
411 bzero((caddr_t)&(sc->sc_stats),sizeof(sc->sc_stats));
412 sc->sc_stats.mincopyin =
413 sc->sc_stats.mincopyout =
414 sc->sc_stats.minsend = 999999L;
415
416 #endif
417
418 bah_start(ifp);
419 }
420
421 /*
422 * Take interface offline
423 */
424 void
425 bah_stop(sc)
426 struct bah_softc *sc;
427 {
428 int s;
429
430 /* Stop the interrupts */
431 sc->sc_base->status = 0;
432
433 /* Stop the interface */
434 sc->sc_base->kick1 = 0;
435 sc->sc_base->kick2 = 0;
436
437 #ifdef BAHTIMINGS
438 log(LOG_DEBUG,"%s%ld\
439 To board: %6ld .. %6ld ns/byte\nFrom board: %6ld .. %6ld ns/byte\n\
440 Send time: %6ld .. %6ld mics\n",
441 sc->sc_arccom.ac_if.if_name,
442 sc->sc_arccom.ac_if.if_unit,
443 sc->sc_stats.mincopyout,sc->sc_stats.maxcopyout,
444 sc->sc_stats.mincopyin, sc->sc_stats.maxcopyin,
445 sc->sc_stats.minsend, sc->sc_stats.maxsend);
446
447 sc->sc_stats.minsend =
448 sc->sc_stats.mincopyout =
449 sc->sc_stats.mincopyin = 999999L;
450 sc->sc_stats.maxsend =
451 sc->sc_stats.maxcopyout =
452 sc->sc_stats.maxcopyin = 0L;
453 #endif
454
455 }
456
457 inline void
458 movepout(from,to,len)
459 u_char *from;
460 volatile u_char *to;
461 int len;
462 {
463 #ifdef BAHASMCOPY
464 u_short shortd;
465 u_long longd,longd1,longd2,longd3,longd4;
466
467 if ((len>3) && ((int)from)&3) {
468 switch (((int)from) & 3) {
469 case 3:
470 *to = *from++;
471 to+=2;--len;
472 break;
473 case 1:
474 *to = *from++;
475 to += 2; --len;
476 case 2:
477 shortd = *((u_short *)from)++;
478 asm("movepw %0,%1@(0)" : : "d"(shortd), "a"(to));
479 to += 4; len -= 2;
480 break;
481 default:
482 }
483
484 while (len>=32) {
485 longd1 = *((u_long *)from)++;
486 longd2 = *((u_long *)from)++;
487 longd3 = *((u_long *)from)++;
488 longd4 = *((u_long *)from)++;
489 asm("movepl %0,%1@(0)" : : "d"(longd1), "a"(to));
490 asm("movepl %0,%1@(8)" : : "d"(longd2), "a"(to));
491 asm("movepl %0,%1@(16)" : : "d"(longd3), "a"(to));
492 asm("movepl %0,%1@(24)" : : "d"(longd4), "a"(to));
493
494 longd1 = *((u_long *)from)++;
495 longd2 = *((u_long *)from)++;
496 longd3 = *((u_long *)from)++;
497 longd4 = *((u_long *)from)++;
498 asm("movepl %0,%1@(32)" : : "d"(longd1), "a"(to));
499 asm("movepl %0,%1@(40)" : : "d"(longd2), "a"(to));
500 asm("movepl %0,%1@(48)" : : "d"(longd3), "a"(to));
501 asm("movepl %0,%1@(56)" : : "d"(longd4), "a"(to));
502
503 to += 64; len -= 32;
504 }
505 while (len>0) {
506 longd = *((u_long *)from)++;
507 asm("movepl %0,%1@(0)" : : "d"(longd), "a"(to));
508 to += 8; len -= 4;
509 }
510 }
511 #endif
512 while (len>0) {
513 *to = *from++;
514 to+=2;
515 --len;
516 }
517 }
518
519 /*
520 * Start output on interface. Get another datagram to send
521 * off the interface queue, and copy it to the
522 * interface becore starting the output
523 *
524 * this assumes that it is called inside a critical section...
525 * XXX hm... does it still?
526 *
527 */
528 int
529 bah_start(ifp)
530 struct ifnet *ifp;
531 {
532 struct bah_softc *sc;
533 struct mbuf *m,*mp;
534 volatile u_char *bah_ram_ptr;
535 int i, len, tlen, offset, s, buffer;
536
537 #ifdef BAHTIMINGS
538 int copystart,lencopy,perbyte;
539 #endif
540
541 sc = bahcd.cd_devs[ifp->if_unit];
542
543 #if defined(BAH_DEBUG) && (BAH_DEBUG > 3)
544 printf("bah%ld: start(0x%x)\n",
545 ifp->if_unit, ifp);
546 #endif
547
548 if((ifp->if_flags & IFF_RUNNING) == 0)
549 return (0);
550
551 s = splimp();
552
553 if (sc->sc_tx_fillcount >= 2) {
554 splx(s);
555 return (0);
556 }
557
558 IF_DEQUEUE(&ifp->if_snd, m);
559 buffer = sc->sc_tx_act ^ 1;
560
561 splx(s);
562
563 if (m == 0)
564 return (0);
565
566 #if NBPFILTER > 0
567 /*
568 * If bpf is listening on this interface, let it
569 * see the packet before we commit it to the wire
570 *
571 * (can't give the copy in A2060 card RAM to bpf, because
572 * that RAM is just accessed as on every other byte)
573 */
574
575 if (sc->sc_bpf)
576 bpf_mtap(sc->sc_bpf, m);
577 #endif
578 /* we need the data length beforehand */
579
580 for (mp = m,tlen=0;mp;mp=mp->m_next)
581 tlen += mp->m_len;
582
583 #ifdef BAH_DEBUG
584 m = m_pullup(m,3); /* gcc does structure padding */
585 printf("bah%ld: start: filling %ld from %ld to %ld type %ld\n",
586 ifp->if_unit,
587 buffer,
588 mtod(m, u_char *)[0],
589 mtod(m, u_char *)[1],
590 mtod(m, u_char *)[2]);
591 #else
592 m = m_pullup(m,2);
593 #endif
594 bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
595
596 /* write the addresses to RAM and throw them away */
597
598 /*
599 * Hardware does this: Yet Another Microsecond Saved.
600 * (btw, timing code says usually 2 microseconds)
601 * bah_ram_ptr[0*2] = mtod(m, u_char *)[0];
602 */
603
604 bah_ram_ptr[1*2] = mtod(m, u_char *)[1];
605 m_adj(m,2);
606
607 /* correct total length for that */
608 tlen -= 2;
609 if (tlen < ARC_MIN_FORBID_LEN) {
610 offset = 256-tlen;
611 bah_ram_ptr[2*2] = offset;
612 } else {
613 if (tlen <= ARC_MAX_FORBID_LEN)
614 offset = 512-3-tlen;
615 else {
616 if (tlen > ARC_MAX_LEN)
617 tlen = ARC_MAX_LEN;
618 offset = 512-tlen;
619 }
620
621 bah_ram_ptr[2*2] = 0;
622 bah_ram_ptr[3*2] = offset;
623 }
624 bah_ram_ptr += offset*2;
625
626 /* lets loop again through the mbuf chain */
627
628 for (mp=m;mp;mp=mp->m_next) {
629 if (len = mp->m_len) { /* YAMS */
630 #ifdef BAHTIMINGS
631 lencopy = len;
632 copystart = clkread();
633 #endif
634 movepout(mtod(mp, caddr_t),bah_ram_ptr,len);
635
636 #ifdef BAHTIMINGS
637 perbyte = 1000*(clkread() - copystart) / lencopy;
638 sc->sc_stats.mincopyout =
639 MIN(sc->sc_stats.mincopyout,perbyte);
640 sc->sc_stats.maxcopyout =
641 max(sc->sc_stats.maxcopyout,perbyte);
642 #endif
643 bah_ram_ptr += len*2;
644 }
645 }
646
647 sc->sc_broadcast[buffer] = (m->m_flags & M_BCAST) != 0;
648 sc->sc_retransmits[buffer] =
649 m->m_flags & M_BCAST ? 1 : 5;
650
651 /* actually transmit the packet */
652 s = splimp();
653
654 if (++sc->sc_tx_fillcount > 1) {
655 /*
656 * We are filled up to the rim. No more bufs for the moment,
657 * please.
658 */
659 ifp->if_flags |= IFF_OACTIVE;
660 } else {
661 #ifdef BAH_DEBUG
662 printf("bah%ld: start: starting transmitter on buffer %d\n",
663 ifp->if_unit, buffer);
664 #endif
665 /* Transmitter was off, start it */
666 sc->sc_tx_act = buffer;
667
668 /*
669 * We still can accept another buf, so don't:
670 * ifp->if_flags |= IFF_OACTIVE;
671 */
672 sc->sc_intmask |= ARC_TA;
673 sc->sc_base->command = ARC_TX(buffer);
674 sc->sc_base->status = sc->sc_intmask;
675
676 #ifdef BAHTIMINGS
677 bcopy((caddr_t)&time,
678 (caddr_t)&(sc->sc_stats.lasttxstart_tv),
679 sizeof(struct timeval));
680
681 sc->sc_stats.lasttxstart_mics = clkread();
682 #endif
683 }
684 splx(s);
685 m_freem(m);
686
687 /*
688 * We dont really need a transmit timeout timer, do we?
689 * XXX (sighing deeply) yes, after 10 times reading the docs,
690 * I realized that in the case the receiver NAKs the buffer request,
691 * the hardware retries till shutdown.
692 * TODO: Insert some reasonable transmit timeout timer.
693 */
694 return (1);
695 }
696
697 void
698 callstart(sc, dummy)
699 struct bah_softc *sc;
700 void *dummy;
701 {
702 (void)bah_start(&sc->sc_arccom.ac_if);
703 }
704
705 inline void
706 movepin(from,to,len)
707 volatile u_char *from;
708 u_char *to;
709 int len;
710 {
711 #ifdef BAHASMCOPY
712 unsigned long longd, longd1, longd2, longd3, longd4;
713 ushort shortd;
714
715 if ((len>3) && (((int)to) & 3)) {
716 switch(((int)to) & 3) {
717 case 3: *to++ = *from;
718 from+=2; --len;
719 break;
720 case 1: *to++ = *from;
721 from+=2; --len;
722 case 2: asm ("movepw %1@(0),%0": "=d" (shortd) : "a" (from));
723 *((ushort *)to)++ = shortd;
724 from += 4; len -= 2;
725 break;
726 default:
727 }
728
729 while (len>=32) {
730 asm("movepl %1@(0),%0" : "=d"(longd1) : "a" (from));
731 asm("movepl %1@(8),%0" : "=d"(longd2) : "a" (from));
732 asm("movepl %1@(16),%0" : "=d"(longd3) : "a" (from));
733 asm("movepl %1@(24),%0" : "=d"(longd4) : "a" (from));
734 *((unsigned long *)to)++ = longd1;
735 *((unsigned long *)to)++ = longd2;
736 *((unsigned long *)to)++ = longd3;
737 *((unsigned long *)to)++ = longd4;
738
739 asm("movepl %1@(32),%0" : "=d"(longd1) : "a" (from));
740 asm("movepl %1@(40),%0" : "=d"(longd2) : "a" (from));
741 asm("movepl %1@(48),%0" : "=d"(longd3) : "a" (from));
742 asm("movepl %1@(56),%0" : "=d"(longd4) : "a" (from));
743 *((unsigned long *)to)++ = longd1;
744 *((unsigned long *)to)++ = longd2;
745 *((unsigned long *)to)++ = longd3;
746 *((unsigned long *)to)++ = longd4;
747
748 from += 64; len -= 32;
749 }
750 while (len>0) {
751 asm("movepl %1@(0),%0" : "=d"(longd) : "a" (from));
752 *((unsigned long *)to)++ = longd;
753 from += 8; len -= 4;
754 }
755
756 }
757 #endif /* BAHASMCOPY */
758 while (len>0) {
759 *to++ = *from;
760 from+=2;
761 --len;
762 }
763
764 }
765
766 /*
767 * Arcnet interface receiver soft interrupt:
768 * get the stuff out of any filled buffer we find.
769 */
770 void
771 bah_srint(sc,dummy)
772 struct bah_softc *sc;
773 void *dummy;
774 {
775 int buffer, buffer1, len, len1, amount, offset, s, i;
776 u_char volatile *bah_ram_ptr;
777 struct mbuf *m, *dst, *head;
778 struct arc_header *ah;
779
780 head = 0;
781
782 #ifdef BAHTIMINGS
783 int copystart,lencopy,perbyte;
784 #endif
785
786 s = splimp();
787 if (sc->sc_rx_fillcount <= 1)
788 buffer = sc->sc_rx_act ^ 1;
789 else {
790
791 i = ((unsigned)(sc->sc_bufstat[2] - sc->sc_bufstat[3])) % 256;
792 if (i < 64)
793 buffer = 3;
794 else if (i > 192)
795 buffer = 2;
796 else {
797 log(LOG_WARNING,
798 "bah%ld: rx srint: which is older, %ld or %ld?\
799 (filled %ld)\n",
800 sc->sc_bufstat[2],sc->sc_bufstat[3],
801 sc->sc_rx_fillcount);
802 splx(s);
803 return;
804 }
805 }
806 splx(s);
807
808 /* Allocate header mbuf */
809 MGETHDR(m, M_DONTWAIT, MT_DATA);
810
811 if (m == 0) {
812 /*
813 * in case s.th. goes wrong with mem, drop it
814 * to make sure the receiver can be started again
815 * count it as input error (we dont have any other
816 * detectable)
817 */
818 sc->sc_arccom.ac_if.if_ierrors++;
819 goto cleanup;
820 }
821
822 m->m_pkthdr.rcvif = &sc->sc_arccom.ac_if;
823 m->m_len = 0;
824
825 /*
826 * Align so that IP packet will be longword aligned. Here we
827 * assume that m_data of new packet is longword aligned.
828 * When implementing RFC1201, we might have to change it to 2,
829 * (2*sizeof(ulong) - ARC_HDRLEN - sizeof(splitflag) - sizeof(pckid))
830 * possibly packet type dependent.
831 */
832
833 m->m_data += 1; /* sizeof(ulong) - ARC_HDRLEN */
834
835 head = m;
836
837 ah = mtod(head, struct arc_header *);
838 bah_ram_ptr = sc->sc_base->buffers + buffer*512*2;
839
840 ah->arc_shost = bah_ram_ptr[0*2];
841 ah->arc_dhost = bah_ram_ptr[1*2];
842 offset = bah_ram_ptr[2*2];
843 if (offset)
844 len = 256 - offset;
845 else {
846 offset = bah_ram_ptr[3*2];
847 len = 512 - offset;
848 }
849 m->m_pkthdr.len = len+2; /* whole packet length */
850 m->m_len += 2; /* mbuf filled with ARCnet addresses */
851 bah_ram_ptr += offset*2; /* ram buffer continues there */
852
853 while (len > 0) {
854
855 len1 = len;
856 amount = M_TRAILINGSPACE(m);
857
858 if (amount == 0) {
859 dst = m;
860 MGET(m, M_DONTWAIT, MT_DATA);
861
862 if (m == 0) {
863 sc->sc_arccom.ac_if.if_ierrors++;
864 goto cleanup;
865 }
866
867 if (len1 >= MINCLSIZE)
868 MCLGET(m, M_DONTWAIT);
869
870 m->m_len = 0;
871 dst->m_next = m;
872 amount = M_TRAILINGSPACE(m);
873 }
874
875 if (amount < len1)
876 len1 = amount;
877
878 #ifdef BAHTIMINGS
879 lencopy = len;
880 copystart = clkread();
881 #endif
882
883 movepin(bah_ram_ptr,mtod(m, u_char *) + m->m_len, len1);
884
885 #ifdef BAHTIMINGS
886 perbyte = 1000*(clkread() - copystart) / lencopy;
887 sc->sc_stats.mincopyin = MIN(sc->sc_stats.mincopyin,perbyte);
888 sc->sc_stats.maxcopyin = max(sc->sc_stats.maxcopyin,perbyte);
889 #endif
890
891 m->m_len += len1;
892 bah_ram_ptr += len1*2;
893 len -= len1;
894 }
895
896 #if NBPFILTER > 0
897 if (sc->sc_bpf) {
898 bpf_mtap(sc->sc_bpf, head);
899 }
900 #endif
901
902 m_adj(head, 3); /* gcc does structure padding */
903 arc_input(&sc->sc_arccom.ac_if, ah, head);
904
905 /* arc_input has freed it, we dont need to... */
906
907 head = NULL;
908 sc->sc_arccom.ac_if.if_ipackets++;
909
910 cleanup:
911
912 if(head == NULL)
913 m_freem(head);
914
915 s = splimp();
916
917 if (--sc->sc_rx_fillcount == 1) {
918
919 /* was off, restart it on buffer just emptied */
920 sc->sc_rx_act = buffer;
921 sc->sc_intmask |= ARC_RI;
922
923 /* this also clears the RI flag interupt: */
924 sc->sc_base->command = ARC_RXBC(buffer);
925 sc->sc_base->status = sc->sc_intmask;
926
927 #ifdef BAH_DEBUG
928 printf("bah%ld: srint: restarted rx on buf %ld\n",
929 sc->sc_arccom.ac_if.if_unit, buffer);
930 #endif
931 }
932 splx(s);
933 }
934
935 inline static void
936 bah_tint(sc)
937 struct bah_softc *sc;
938 {
939 int buffer;
940 u_char volatile *bah_ram_ptr;
941 int isr;
942 int clknow;
943
944 buffer = sc->sc_tx_act;
945 isr = sc->sc_base->status;
946
947 /* XXX insert retransmit code etc. here. For now just: */
948
949 if (!(isr & ARC_TMA) && !(sc->sc_broadcast[buffer]))
950 sc->sc_arccom.ac_if.if_oerrors++;
951 else
952 sc->sc_arccom.ac_if.if_opackets++;
953
954 #ifdef BAHTIMINGS
955 clknow = clkread();
956
957 sc->sc_stats.minsend = MIN(sc->sc_stats.minsend,
958 clknow - sc->sc_stats.lasttxstart_mics);
959
960 sc->sc_stats.maxsend = max(sc->sc_stats.maxsend,
961 clknow - sc->sc_stats.lasttxstart_mics);
962 #endif
963
964 /* We know we can accept another buffer at this point. */
965 sc->sc_arccom.ac_if.if_flags &= ~IFF_OACTIVE;
966
967 if (--sc->sc_tx_fillcount > 0) {
968
969 /*
970 * start tx on other buffer.
971 * This also clears the int flag
972 */
973 buffer ^= 1;
974 sc->sc_tx_act = buffer;
975
976 /*
977 * already given:
978 * sc->sc_intmask |= ARC_TA;
979 * sc->sc_base->status = sc->sc_intmask;
980 */
981 sc->sc_base->command = ARC_TX(buffer);
982
983 #ifdef BAHTIMINGS
984 bcopy((caddr_t)&time,
985 (caddr_t)&(sc->sc_stats.lasttxstart_tv),
986 sizeof(struct timeval));
987
988 sc->sc_stats.lasttxstart_mics = clkread();
989 #endif
990
991 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
992 printf("bah%ld: tint: starting tx on buffer %d,\
993 status 0x%02x\n",
994 sc->sc_arccom.ac_if.if_unit,
995 buffer,sc->sc_base->status);
996 #endif
997 } else {
998 /* have to disable TX interrupt */
999 sc->sc_intmask &= ~ARC_TA;
1000 sc->sc_base->status = sc->sc_intmask;
1001
1002 #ifdef BAH_DEBUG
1003 printf("bah%ld: tint: no more buffers to send,\
1004 status 0x%02x\n",
1005 sc->sc_arccom.ac_if.if_unit,
1006 sc->sc_base->status);
1007 #endif
1008 }
1009
1010 #ifdef BAHSOFTCOPY
1011 /* schedule soft int to fill a new buffer for us */
1012 add_sicallback(callstart, sc, NULL);
1013 #else
1014 /* call it directly */
1015 callstart(sc, NULL);
1016 #endif
1017 }
1018
1019 /*
1020 * Our interrupt routine
1021 */
1022 int
1023 bahintr(sc)
1024 struct bah_softc *sc;
1025 {
1026 u_char isr;
1027 int buffer;
1028 int unit;
1029 u_long newsec;
1030
1031 isr = sc->sc_base->status;
1032 if (!(isr & sc->sc_intmask))
1033 return (0);
1034
1035 #if defined(BAH_DEBUG) && (BAH_DEBUG>1)
1036 printf("bah%ld: intr: status 0x%02x, intmask 0x%02x\n",
1037 sc->sc_arccom.ac_if.if_unit,
1038 isr, sc->sc_intmask);
1039 #endif
1040
1041 if (isr & ARC_POR) {
1042 sc->sc_arccom.ac_anaddr = sc->sc_base->dipswitches;
1043 sc->sc_base->command = ARC_CLR(CLR_POR);
1044 log(LOG_WARNING,
1045 "%s%ld: intr: got spurious power on reset int\n",
1046 sc->sc_arccom.ac_if.if_name,
1047 sc->sc_arccom.ac_if.if_unit);
1048 }
1049
1050 if (isr & ARC_RECON) {
1051 /*
1052 * we dont need to:
1053 * sc->sc_base->command = ARC_CONF(CONF_LONG);
1054 */
1055 sc->sc_base->command = ARC_CLR(CLR_RECONFIG);
1056 sc->sc_arccom.ac_if.if_collisions++;
1057 /*
1058 * if more than 2 seconds per reconfig, reset time and counter.
1059 * else
1060 * if more than ARC_EXCESSIVE_RECONFIGS reconfigs since last burst, complain
1061 * and set treshold for warnings to ARC_EXCESSIVE_RECONS_REWARN.
1062 * This allows for, e.g., new stations on the cable, or cable switching as long
1063 * as it is over after (normally) 16 seconds.
1064 * XXX Todo: check timeout bits in status word and double time if necessary.
1065 */
1066
1067 newsec = time.tv_sec;
1068 if (newsec - sc->sc_recontime > 2*sc->sc_reconcount) {
1069 sc->sc_recontime = newsec;
1070 sc->sc_reconcount = 0;
1071 sc->sc_reconcount_excessive = ARC_EXCESSIVE_RECONS;
1072 } else if (++sc->sc_reconcount > sc->sc_reconcount_excessive) {
1073 sc->sc_reconcount_excessive =
1074 ARC_EXCESSIVE_RECONS_REWARN;
1075 log(LOG_WARNING,
1076 "%s%d: excessive token losses, cable problem?\n",
1077 sc->sc_arccom.ac_if.if_name,
1078 sc->sc_arccom.ac_if.if_unit);
1079 sc->sc_recontime = newsec;
1080 sc->sc_reconcount = 0;
1081 }
1082 }
1083
1084 if (isr & ARC_RI) {
1085
1086 #if defined(BAH_DEBUG) && (BAH_DEBUG > 1)
1087 printf("bah%ld: intr: hard rint, act %ld 2:%ld 3:%ld\n",
1088 sc->sc_arccom.ac_if.if_unit,
1089 sc->sc_rx_act,sc->sc_bufstat[2],sc->sc_bufstat[3]);
1090 #endif
1091
1092 buffer = sc->sc_rx_act;
1093 sc->sc_rx_packetno = (sc->sc_rx_packetno+1)%256;
1094 sc->sc_bufstat[buffer] = sc->sc_rx_packetno;
1095
1096 if (++sc->sc_rx_fillcount > 1) {
1097 sc->sc_intmask &= ~ARC_RI;
1098 sc->sc_base->status = sc->sc_intmask;
1099 } else {
1100
1101 buffer ^= 1;
1102 sc->sc_rx_act = buffer;
1103
1104 /*
1105 * Start receiver on other receive buffer.
1106 * This also clears the RI interupt flag.
1107 */
1108 sc->sc_base->command = ARC_RXBC(buffer);
1109 /* we are in the RX intr, so mask is ok for RX */
1110
1111 #ifdef BAH_DEBUG
1112 printf("bah%ld: started rx for buffer %ld,\
1113 status 0x%02x\n",
1114 sc->sc_arccom.ac_if.if_unit,sc->sc_rx_act,
1115 sc->sc_base->status);
1116 #endif
1117 }
1118
1119 #ifdef BAHSOFTCOPY
1120 /* this one starts a soft int to copy out of the hw */
1121 add_sicallback(bah_srint,sc,NULL);
1122 #else
1123 /* this one does the copy here */
1124 bah_srint(sc,NULL);
1125 #endif
1126 }
1127
1128 if (isr & sc->sc_intmask & ARC_TA)
1129 bah_tint(sc);
1130
1131 return (1);
1132 }
1133
1134 /*
1135 * Process an ioctl request.
1136 * This code needs some work - it looks pretty ugly.
1137 */
1138 int
1139 bah_ioctl(ifp, command, data)
1140 register struct ifnet *ifp;
1141 unsigned long command;
1142 caddr_t data;
1143 {
1144 struct bah_softc *sc;
1145 register struct ifaddr *ifa;
1146 int s, error;
1147
1148 error = 0;
1149 sc = bahcd.cd_devs[ifp->if_unit];
1150 ifa = (struct ifaddr *)data;
1151 s = splimp();
1152
1153 #if defined(BAH_DEBUG) && (BAH_DEBUG > 2)
1154 printf("bah%ld: ioctl() called, cmd = 0x%x\n",
1155 sc->sc_arccom.ac_if.if_unit, command);
1156 #endif
1157
1158 switch(command) {
1159 case SIOCSIFADDR:
1160 ifp->if_flags |= IFF_UP;
1161 switch(ifa->ifa_addr->sa_family) {
1162 #ifdef INET
1163 case AF_INET:
1164 bah_init(sc); /* before arpwhohas */
1165 ((struct arccom *)ifp)->ac_ipaddr =
1166 IA_SIN(ifa)->sin_addr;
1167 /* arpwhohas((struct arccom *)ifp,
1168 &IA_SIN(ifa)->sin_addr);*/
1169 break;
1170 #endif
1171 default:
1172 bah_init(sc);
1173 break;
1174 }
1175
1176 case SIOCSIFFLAGS:
1177 if ((ifp->if_flags & IFF_UP) == 0 &&
1178 (ifp->if_flags & IFF_RUNNING) != 0) {
1179
1180 /*
1181 * If interface is marked down and it is running,
1182 * then stop it.
1183 */
1184
1185 bah_stop(sc);
1186 ifp->if_flags &= ~IFF_RUNNING;
1187
1188 } else if((ifp->if_flags & IFF_UP) != 0 &&
1189 (ifp->if_flags & IFF_RUNNING) == 0) {
1190
1191 /*
1192 * If interface is marked up and it is stopped, then
1193 * start it.
1194 */
1195
1196 bah_init(sc);
1197 }
1198 break;
1199
1200 /* Multicast not supported */
1201 default:
1202 error = EINVAL;
1203 }
1204
1205 (void)splx(s);
1206 return (error);
1207 }
1208