if_qn.c revision 1.21 1 /* $NetBSD: if_qn.c,v 1.21 2002/01/26 13:40:56 aymeric Exp $ */
2
3 /*
4 * Copyright (c) 1995 Mika Kortelainen
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mika Kortelainen
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Thanks for Aspecs Oy (Finland) for the data book for the NIC used
33 * in this card and also many thanks for the Resource Management Force
34 * (QuickNet card manufacturer) and especially Daniel Koch for providing
35 * me with the necessary 'inside' information to write the driver.
36 *
37 * This is partly based on other code:
38 * - if_ed.c: basic function structure for Ethernet driver and now also
39 * qn_put() is done similarly, i.e. no extra packet buffers.
40 *
41 * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
42 * adapters.
43 *
44 * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
45 *
46 * Copyright (C) 1993, David Greenman. This software may be used,
47 * modified, copied, distributed, and sold, in both source and binary
48 * form provided that the above copyright and these terms are retained.
49 * Under no circumstances is the author responsible for the proper
50 * functioning of this software, nor does the author assume any
51 * responsibility for damages incurred with its use.
52 *
53 * - if_es.c: used as an example of -current driver
54 *
55 * Copyright (c) 1995 Michael L. Hitch
56 * All rights reserved.
57 *
58 * - if_fe.c: some ideas for error handling for qn_rint() which might
59 * have fixed those random lock ups, too.
60 *
61 * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
62 *
63 *
64 * TODO:
65 * - add multicast support
66 */
67
68 #include "qn.h"
69 #if NQN > 0
70
71 #define QN_DEBUG
72 #define QN_DEBUG1_no /* hides some old tests */
73 #define QN_CHECKS_no /* adds some checks (not needed in normal situations) */
74
75 #include "bpfilter.h"
76
77 /*
78 * Fujitsu MB86950 Ethernet Controller (as used in the QuickNet QN2000
79 * Ethernet card)
80 */
81
82 #include "opt_inet.h"
83 #include "opt_ns.h"
84
85 #include <sys/param.h>
86 #include <sys/systm.h>
87 #include <sys/mbuf.h>
88 #include <sys/buf.h>
89 #include <sys/device.h>
90 #include <sys/protosw.h>
91 #include <sys/socket.h>
92 #include <sys/syslog.h>
93 #include <sys/ioctl.h>
94 #include <sys/errno.h>
95
96 #include <net/if.h>
97 #include <net/if_dl.h>
98 #include <net/if_ether.h>
99
100 #ifdef INET
101 #include <netinet/in.h>
102 #include <netinet/in_systm.h>
103 #include <netinet/in_var.h>
104 #include <netinet/ip.h>
105 #include <netinet/if_inarp.h>
106 #endif
107
108 #ifdef NS
109 #include <netns/ns.h>
110 #include <netns/ns_if.h>
111 #endif
112
113 #include <machine/cpu.h>
114 #include <machine/mtpr.h>
115 #include <amiga/amiga/device.h>
116 #include <amiga/amiga/isr.h>
117 #include <amiga/dev/zbusvar.h>
118 #include <amiga/dev/if_qnreg.h>
119
120
121 #define NIC_R_MASK (R_INT_PKT_RDY | R_INT_ALG_ERR |\
122 R_INT_CRC_ERR | R_INT_OVR_FLO)
123 #define MAX_PACKETS 30 /* max number of packets read per interrupt */
124
125 /*
126 * Ethernet software status per interface
127 *
128 * Each interface is referenced by a network interface structure,
129 * qn_if, which the routing code uses to locate the interface.
130 * This structure contains the output queue for the interface, its address, ...
131 */
132 struct qn_softc {
133 struct device sc_dev;
134 struct isr sc_isr;
135 struct ethercom sc_ethercom; /* Common ethernet structures */
136 u_char volatile *sc_base;
137 u_char volatile *sc_nic_base;
138 u_short volatile *nic_fifo;
139 u_short volatile *nic_r_status;
140 u_short volatile *nic_t_status;
141 u_short volatile *nic_r_mask;
142 u_short volatile *nic_t_mask;
143 u_short volatile *nic_r_mode;
144 u_short volatile *nic_t_mode;
145 u_short volatile *nic_reset;
146 u_short volatile *nic_len;
147 u_char transmit_pending;
148 #if NBPFILTER > 0
149 caddr_t sc_bpf;
150 #endif
151 } qn_softc[NQN];
152
153 #if NBPFILTER > 0
154 #include <net/bpf.h>
155 #include <net/bpfdesc.h>
156 #endif
157
158
159 int qnmatch(struct device *, struct cfdata *, void *);
160 void qnattach(struct device *, struct device *, void *);
161 int qnintr(void *);
162 int qnioctl(struct ifnet *, u_long, caddr_t);
163 void qnstart(struct ifnet *);
164 void qnwatchdog(struct ifnet *);
165 void qnreset(struct qn_softc *);
166 void qninit(struct qn_softc *);
167 void qnstop(struct qn_softc *);
168 static u_short qn_put(u_short volatile *, struct mbuf *);
169 static void qn_rint(struct qn_softc *, u_short);
170 static void qn_flush(struct qn_softc *);
171 static void inline word_copy_from_card(u_short volatile *, u_short *, u_short);
172 static void inline word_copy_to_card(u_short *, u_short volatile *,
173 register u_short);
174 static void qn_get_packet(struct qn_softc *, u_short);
175 #ifdef QN_DEBUG1
176 static void qn_dump(struct qn_softc *);
177 #endif
178
179 struct cfattach qn_ca = {
180 sizeof(struct qn_softc), qnmatch, qnattach
181 };
182
183 int
184 qnmatch(struct device *parent, struct cfdata *cfp, void *aux)
185 {
186 struct zbus_args *zap;
187
188 zap = (struct zbus_args *)aux;
189
190 /* RMF QuickNet QN2000 EtherNet card */
191 if (zap->manid == 2011 && zap->prodid == 2)
192 return (1);
193
194 return (0);
195 }
196
197 /*
198 * Interface exists: make available by filling in network interface
199 * record. System will initialize the interface when it is ready
200 * to accept packets.
201 */
202 void
203 qnattach(struct device *parent, struct device *self, void *aux)
204 {
205 struct zbus_args *zap;
206 struct qn_softc *sc = (struct qn_softc *)self;
207 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
208 u_int8_t myaddr[ETHER_ADDR_LEN];
209
210 zap = (struct zbus_args *)aux;
211
212 sc->sc_base = zap->va;
213 sc->sc_nic_base = sc->sc_base + QUICKNET_NIC_BASE;
214 sc->nic_fifo = (u_short volatile *)(sc->sc_nic_base + NIC_BMPR0);
215 sc->nic_len = (u_short volatile *)(sc->sc_nic_base + NIC_BMPR2);
216 sc->nic_t_status = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR0);
217 sc->nic_r_status = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR2);
218 sc->nic_t_mask = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR1);
219 sc->nic_r_mask = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR3);
220 sc->nic_t_mode = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR4);
221 sc->nic_r_mode = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR5);
222 sc->nic_reset = (u_short volatile *)(sc->sc_nic_base + NIC_DLCR6);
223 sc->transmit_pending = 0;
224
225 /*
226 * The ethernet address of the board (1st three bytes are the vendor
227 * address, the rest is the serial number of the board).
228 */
229 myaddr[0] = 0x5c;
230 myaddr[1] = 0x5c;
231 myaddr[2] = 0x00;
232 myaddr[3] = (zap->serno >> 16) & 0xff;
233 myaddr[4] = (zap->serno >> 8) & 0xff;
234 myaddr[5] = zap->serno & 0xff;
235
236 /* set interface to stopped condition (reset) */
237 qnstop(sc);
238
239 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
240 ifp->if_softc = sc;
241 ifp->if_ioctl = qnioctl;
242 ifp->if_watchdog = qnwatchdog;
243 ifp->if_start = qnstart;
244 /* XXX IFF_MULTICAST */
245 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
246 ifp->if_mtu = ETHERMTU;
247
248 /* Attach the interface. */
249 if_attach(ifp);
250 ether_ifattach(ifp, myaddr);
251
252 #ifdef QN_DEBUG
253 printf(": hardware address %s\n", ether_sprintf(myaddr));
254 #endif
255
256 sc->sc_isr.isr_intr = qnintr;
257 sc->sc_isr.isr_arg = sc;
258 sc->sc_isr.isr_ipl = 2;
259 add_isr(&sc->sc_isr);
260 }
261
262 /*
263 * Initialize device
264 *
265 */
266 void
267 qninit(struct qn_softc *sc)
268 {
269 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
270 u_short i;
271 static int retry = 0;
272
273 *sc->nic_r_mask = NIC_R_MASK;
274 *sc->nic_t_mode = NO_LOOPBACK;
275
276 if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC) {
277 *sc->nic_r_mode = PROMISCUOUS_MODE;
278 log(LOG_INFO, "qn: Promiscuous mode (not tested)\n");
279 } else
280 *sc->nic_r_mode = NORMAL_MODE;
281
282 /* Set physical ethernet address. */
283 for (i = 0; i < ETHER_ADDR_LEN; i++)
284 *((u_short volatile *)(sc->sc_nic_base+
285 QNET_HARDWARE_ADDRESS+2*i)) =
286 ((((u_short)LLADDR(ifp->if_sadl)[i]) << 8) |
287 LLADDR(ifp->if_sadl)[i]);
288
289 ifp->if_flags |= IFF_RUNNING;
290 ifp->if_flags &= ~IFF_OACTIVE;
291 sc->transmit_pending = 0;
292
293 qn_flush(sc);
294
295 /* QuickNet magic. Done ONLY once, otherwise a lockup occurs. */
296 if (retry == 0) {
297 *((u_short volatile *)(sc->sc_nic_base + QNET_MAGIC)) = 0;
298 retry = 1;
299 }
300
301 /* Enable data link controller. */
302 *sc->nic_reset = ENABLE_DLC;
303
304 /* Attempt to start output, if any. */
305 qnstart(ifp);
306 }
307
308 /*
309 * Device timeout/watchdog routine. Entered if the device neglects to
310 * generate an interrupt after a transmit has been started on it.
311 */
312 void
313 qnwatchdog(struct ifnet *ifp)
314 {
315 struct qn_softc *sc = ifp->if_softc;
316
317 log(LOG_INFO, "qn: device timeout (watchdog)\n");
318 ++sc->sc_ethercom.ec_if.if_oerrors;
319
320 qnreset(sc);
321 }
322
323 /*
324 * Flush card's buffer RAM.
325 */
326 static void
327 qn_flush(struct qn_softc *sc)
328 {
329 #if 1
330 /* Read data until bus read error (i.e. buffer empty). */
331 while (!(*sc->nic_r_status & R_BUS_RD_ERR))
332 (void)(*sc->nic_fifo);
333 #else
334 /* Read data twice to clear some internal pipelines. */
335 (void)(*sc->nic_fifo);
336 (void)(*sc->nic_fifo);
337 #endif
338
339 /* Clear bus read error. */
340 *sc->nic_r_status = R_BUS_RD_ERR;
341 }
342
343 /*
344 * Reset the interface.
345 *
346 */
347 void
348 qnreset(struct qn_softc *sc)
349 {
350 int s;
351
352 s = splnet();
353 qnstop(sc);
354 qninit(sc);
355 splx(s);
356 }
357
358 /*
359 * Take interface offline.
360 */
361 void
362 qnstop(struct qn_softc *sc)
363 {
364
365 /* Stop the interface. */
366 *sc->nic_reset = DISABLE_DLC;
367 delay(200);
368 *sc->nic_t_status = CLEAR_T_ERR;
369 *sc->nic_t_mask = CLEAR_T_MASK;
370 *sc->nic_r_status = CLEAR_R_ERR;
371 *sc->nic_r_mask = CLEAR_R_MASK;
372
373 /* Turn DMA off */
374 *((u_short volatile *)(sc->sc_nic_base + NIC_BMPR4)) = 0;
375
376 /* Accept no packets. */
377 *sc->nic_r_mode = 0;
378 *sc->nic_t_mode = 0;
379
380 qn_flush(sc);
381 }
382
383 /*
384 * Start output on interface. Get another datagram to send
385 * off the interface queue, and copy it to the
386 * interface before starting the output.
387 *
388 * This assumes that it is called inside a critical section...
389 *
390 */
391 void
392 qnstart(struct ifnet *ifp)
393 {
394 struct qn_softc *sc = ifp->if_softc;
395 struct mbuf *m;
396 u_short len;
397 int timout = 60000;
398
399
400 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
401 return;
402
403 IF_DEQUEUE(&ifp->if_snd, m);
404 if (m == 0)
405 return;
406
407 #if NBPFILTER > 0
408 /*
409 * If bpf is listening on this interface, let it
410 * see the packet before we commit it to the wire
411 *
412 * (can't give the copy in QuickNet card RAM to bpf, because
413 * that RAM is not visible to the host but is read from FIFO)
414 *
415 */
416 if (sc->sc_bpf)
417 bpf_mtap(sc->sc_bpf, m);
418 #endif
419 len = qn_put(sc->nic_fifo, m);
420 m_freem(m);
421
422 /*
423 * Really transmit the packet.
424 */
425
426 /* Set packet length (byte-swapped). */
427 len = ((len >> 8) & 0x0007) | TRANSMIT_START | ((len & 0x00ff) << 8);
428 *sc->nic_len = len;
429
430 /* Wait for the packet to really leave. */
431 while (!(*sc->nic_t_status & T_TMT_OK) && --timout) {
432 if ((timout % 10000) == 0)
433 log(LOG_INFO, "qn: timout...\n");
434 }
435
436 if (timout == 0)
437 /* Maybe we should try to recover from this one? */
438 /* But now, let's just fall thru and hope the best... */
439 log(LOG_INFO, "qn: transmit timout (fatal?)\n");
440
441 sc->transmit_pending = 1;
442 *sc->nic_t_mask = INT_TMT_OK | INT_SIXTEEN_COL;
443
444 ifp->if_flags |= IFF_OACTIVE;
445 ifp->if_timer = 2;
446 }
447
448 /*
449 * Memory copy, copies word at a time
450 */
451 static void inline
452 word_copy_from_card(u_short volatile *card, u_short *b, u_short len)
453 {
454 register u_short l = len/2;
455
456 while (l--)
457 *b++ = *card;
458 }
459
460 static void inline
461 word_copy_to_card(u_short *a, u_short volatile *card, register u_short len)
462 {
463 /*register u_short l = len/2;*/
464
465 while (len--)
466 *card = *a++;
467 }
468
469 /*
470 * Copy packet from mbuf to the board memory
471 *
472 */
473 static u_short
474 qn_put(u_short volatile *addr, struct mbuf *m)
475 {
476 u_short *data;
477 u_char savebyte[2];
478 int len, len1, wantbyte;
479 u_short totlen;
480
481 totlen = wantbyte = 0;
482
483 for (; m != NULL; m = m->m_next) {
484 data = mtod(m, u_short *);
485 len = m->m_len;
486 if (len > 0) {
487 totlen += len;
488
489 /* Finish the last word. */
490 if (wantbyte) {
491 savebyte[1] = *((u_char *)data);
492 *addr = *((u_short *)savebyte);
493 ((u_char *)data)++;
494 len--;
495 wantbyte = 0;
496 }
497 /* Output contiguous words. */
498 if (len > 1) {
499 len1 = len/2;
500 word_copy_to_card(data, addr, len1);
501 data += len1;
502 len &= 1;
503 }
504 /* Save last byte, if necessary. */
505 if (len == 1) {
506 savebyte[0] = *((u_char *)data);
507 wantbyte = 1;
508 }
509 }
510 }
511
512 if (wantbyte) {
513 savebyte[1] = 0;
514 *addr = *((u_short *)savebyte);
515 }
516
517 if(totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
518 /*
519 * Fill the rest of the packet with zeros.
520 * N.B.: This is required! Otherwise MB86950 fails.
521 */
522 for(len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN);
523 len += 2)
524 *addr = (u_short)0x0000;
525 totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN);
526 }
527
528 return (totlen);
529 }
530
531 /*
532 * Copy packet from board RAM.
533 *
534 * Trailers not supported.
535 *
536 */
537 static void
538 qn_get_packet(struct qn_softc *sc, u_short len)
539 {
540 register u_short volatile *nic_fifo_ptr = sc->nic_fifo;
541 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
542 struct mbuf *m, *dst, *head = NULL;
543 register u_short len1;
544 u_short amount;
545
546 /* Allocate header mbuf. */
547 MGETHDR(m, M_DONTWAIT, MT_DATA);
548 if (m == NULL)
549 goto bad;
550
551 /*
552 * Round len to even value.
553 */
554 if (len & 1)
555 len++;
556
557 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
558 m->m_pkthdr.len = len;
559 m->m_len = 0;
560 head = m;
561
562 word_copy_from_card(nic_fifo_ptr,
563 mtod(head, u_short *),
564 sizeof(struct ether_header));
565
566 head->m_len += sizeof(struct ether_header);
567 len -= sizeof(struct ether_header);
568
569 while (len > 0) {
570 len1 = len;
571
572 amount = M_TRAILINGSPACE(m);
573 if (amount == 0) {
574 /* Allocate another mbuf. */
575 dst = m;
576 MGET(m, M_DONTWAIT, MT_DATA);
577 if (m == NULL)
578 goto bad;
579
580 if (len1 >= MINCLSIZE)
581 MCLGET(m, M_DONTWAIT);
582
583 m->m_len = 0;
584 dst->m_next = m;
585
586 amount = M_TRAILINGSPACE(m);
587 }
588
589 if (amount < len1)
590 len1 = amount;
591
592 word_copy_from_card(nic_fifo_ptr,
593 (u_short *)(mtod(m, caddr_t) + m->m_len),
594 len1);
595 m->m_len += len1;
596 len -= len1;
597 }
598
599 #if NBPFILTER > 0
600 if (sc->sc_bpf)
601 bpf_mtap(sc->sc_bpf, head);
602 #endif
603
604 (*ifp->if_input)(ifp, head);
605 return;
606
607 bad:
608 if (head) {
609 m_freem(head);
610 log(LOG_INFO, "qn_get_packet: mbuf alloc failed\n");
611 }
612 }
613
614 /*
615 * Ethernet interface receiver interrupt.
616 */
617 static void
618 qn_rint(struct qn_softc *sc, u_short rstat)
619 {
620 int i;
621 u_short len, status;
622
623 /* Clear the status register. */
624 *sc->nic_r_status = CLEAR_R_ERR;
625
626 /*
627 * Was there some error?
628 * Some of them are senseless because they are masked off.
629 * XXX
630 */
631 if (rstat & R_INT_OVR_FLO) {
632 #ifdef QN_DEBUG
633 log(LOG_INFO, "Overflow\n");
634 #endif
635 ++sc->sc_ethercom.ec_if.if_ierrors;
636 }
637 if (rstat & R_INT_CRC_ERR) {
638 #ifdef QN_DEBUG
639 log(LOG_INFO, "CRC Error\n");
640 #endif
641 ++sc->sc_ethercom.ec_if.if_ierrors;
642 }
643 if (rstat & R_INT_ALG_ERR) {
644 #ifdef QN_DEBUG
645 log(LOG_INFO, "Alignment error\n");
646 #endif
647 ++sc->sc_ethercom.ec_if.if_ierrors;
648 }
649 if (rstat & R_INT_SRT_PKT) {
650 /* Short packet (these may occur and are
651 * no reason to worry about - or maybe
652 * they are?).
653 */
654 #ifdef QN_DEBUG
655 log(LOG_INFO, "Short packet\n");
656 #endif
657 ++sc->sc_ethercom.ec_if.if_ierrors;
658 }
659 if (rstat & 0x4040) {
660 #ifdef QN_DEBUG
661 log(LOG_INFO, "Bus read error\n");
662 #endif
663 ++sc->sc_ethercom.ec_if.if_ierrors;
664 qnreset(sc);
665 }
666
667 /*
668 * Read at most MAX_PACKETS packets per interrupt
669 */
670 for (i = 0; i < MAX_PACKETS; i++) {
671 if (*sc->nic_r_mode & RM_BUF_EMP)
672 /* Buffer empty. */
673 break;
674
675 /*
676 * Read the first word: upper byte contains useful
677 * information.
678 */
679 status = *sc->nic_fifo;
680 if ((status & 0x7000) != 0x2000) {
681 log(LOG_INFO, "qn: ERROR: status=%04x\n", status);
682 continue;
683 }
684
685 /*
686 * Read packet length (byte-swapped).
687 * CRC is stripped off by the NIC.
688 */
689 len = *sc->nic_fifo;
690 len = ((len << 8) & 0xff00) | ((len >> 8) & 0x00ff);
691
692 #ifdef QN_CHECKS
693 if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN) ||
694 len < ETHER_HDR_LEN) {
695 log(LOG_WARNING,
696 "%s: received a %s packet? (%u bytes)\n",
697 sc->sc_dev.dv_xname,
698 len < ETHER_HDR_LEN ? "partial" : "big", len);
699 ++sc->sc_ethercom.ec_if.if_ierrors;
700 continue;
701 }
702 #endif
703 #ifdef QN_CHECKS
704 if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
705 log(LOG_WARNING,
706 "%s: received a short packet? (%u bytes)\n",
707 sc->sc_dev.dv_xname, len);
708 #endif
709
710 /* Read the packet. */
711 qn_get_packet(sc, len);
712
713 ++sc->sc_ethercom.ec_if.if_ipackets;
714 }
715
716 #ifdef QN_DEBUG
717 /* This print just to see whether MAX_PACKETS is large enough. */
718 if (i == MAX_PACKETS)
719 log(LOG_INFO, "used all the %d loops\n", MAX_PACKETS);
720 #endif
721 }
722
723 /*
724 * Our interrupt routine
725 */
726 int
727 qnintr(void *arg)
728 {
729 struct qn_softc *sc = arg;
730 u_short tint, rint, tintmask;
731 char return_tintmask = 0;
732
733 /*
734 * If the driver has not been initialized, just return immediately.
735 * This also happens if there is no QuickNet board present.
736 */
737 if (sc->sc_base == NULL)
738 return (0);
739
740 /* Get interrupt statuses and masks. */
741 rint = (*sc->nic_r_status) & NIC_R_MASK;
742 tintmask = *sc->nic_t_mask;
743 tint = (*sc->nic_t_status) & tintmask;
744 if (tint == 0 && rint == 0)
745 return (0);
746
747 /* Disable interrupts so that we won't miss anything. */
748 *sc->nic_r_mask = CLEAR_R_MASK;
749 *sc->nic_t_mask = CLEAR_T_MASK;
750
751 /*
752 * Handle transmitter interrupts. Some of them are not asked for
753 * but do happen, anyway.
754 */
755
756 if (tint != 0) {
757 /* Clear transmit interrupt status. */
758 *sc->nic_t_status = CLEAR_T_ERR;
759
760 if (sc->transmit_pending && (tint & T_TMT_OK)) {
761 sc->transmit_pending = 0;
762 /*
763 * Update total number of successfully
764 * transmitted packets.
765 */
766 sc->sc_ethercom.ec_if.if_opackets++;
767 }
768
769 if (tint & T_SIXTEEN_COL) {
770 /*
771 * 16 collision (i.e., packet lost).
772 */
773 log(LOG_INFO, "qn: 16 collision - packet lost\n");
774 #ifdef QN_DEBUG1
775 qn_dump(sc);
776 #endif
777 sc->sc_ethercom.ec_if.if_oerrors++;
778 sc->sc_ethercom.ec_if.if_collisions += 16;
779 sc->transmit_pending = 0;
780 }
781
782 if (sc->transmit_pending) {
783 log(LOG_INFO, "qn:still pending...\n");
784
785 /* Must return transmission interrupt mask. */
786 return_tintmask = 1;
787 } else {
788 sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE;
789
790 /* Clear watchdog timer. */
791 sc->sc_ethercom.ec_if.if_timer = 0;
792 }
793 } else
794 return_tintmask = 1;
795
796 /*
797 * Handle receiver interrupts.
798 */
799 if (rint != 0)
800 qn_rint(sc, rint);
801
802 if ((sc->sc_ethercom.ec_if.if_flags & IFF_OACTIVE) == 0)
803 qnstart(&sc->sc_ethercom.ec_if);
804 else if (return_tintmask == 1)
805 *sc->nic_t_mask = tintmask;
806
807 /* Set receive interrupt mask back. */
808 *sc->nic_r_mask = NIC_R_MASK;
809
810 return (1);
811 }
812
813 /*
814 * Process an ioctl request. This code needs some work - it looks pretty ugly.
815 * I somehow think that this is quite a common excuse... ;-)
816 */
817 int
818 qnioctl(register struct ifnet *ifp, u_long command, caddr_t data)
819 {
820 struct qn_softc *sc = ifp->if_softc;
821 register struct ifaddr *ifa = (struct ifaddr *)data;
822 #if 0
823 struct ifreg *ifr = (struct ifreg *)data;
824 #endif
825 int s, error = 0;
826
827 s = splnet();
828
829 switch (command) {
830
831 case SIOCSIFADDR:
832 ifp->if_flags |= IFF_UP;
833
834 switch (ifa->ifa_addr->sa_family) {
835 #ifdef INET
836 case AF_INET:
837 qnstop(sc);
838 qninit(sc);
839 arp_ifinit(ifp, ifa);
840 break;
841 #endif
842 #ifdef NS
843 case AF_NS:
844 {
845 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
846
847 if (ns_nullhost(*ina))
848 ina->x_host =
849 *(union ns_host *)LLADDR(ifp->if_sadl);
850 else
851 bcopy(ina->x_host.c_host,
852 LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
853 qnstop(sc);
854 qninit(sc);
855 break;
856 }
857 #endif
858 default:
859 log(LOG_INFO, "qn:sa_family:default (not tested)\n");
860 qnstop(sc);
861 qninit(sc);
862 break;
863 }
864 break;
865
866 case SIOCSIFFLAGS:
867 if ((ifp->if_flags & IFF_UP) == 0 &&
868 (ifp->if_flags & IFF_RUNNING) != 0) {
869 /*
870 * If interface is marked down and it is running, then
871 * stop it.
872 */
873 #ifdef QN_DEBUG1
874 qn_dump(sc);
875 #endif
876 qnstop(sc);
877 ifp->if_flags &= ~IFF_RUNNING;
878 } else if ((ifp->if_flags & IFF_UP) != 0 &&
879 (ifp->if_flags & IFF_RUNNING) == 0) {
880 /*
881 * If interface is marked up and it is stopped, then
882 * start it.
883 */
884 qninit(sc);
885 } else {
886 /*
887 * Something else... we won't do anything so we won't
888 * break anything (hope so).
889 */
890 #ifdef QN_DEBUG1
891 log(LOG_INFO, "Else branch...\n");
892 #endif
893 }
894 break;
895
896 case SIOCADDMULTI:
897 case SIOCDELMULTI:
898 log(LOG_INFO, "qnioctl: multicast not done yet\n");
899 #if 0
900 error = (command == SIOCADDMULTI) ?
901 ether_addmulti(ifr, &sc->sc_ethercom) :
902 ether_delmulti(ifr, &sc->sc_ethercom);
903
904 if (error == ENETRESET) {
905 /*
906 * Multicast list has changed; set the hardware filter
907 * accordingly.
908 */
909 log(LOG_INFO, "qnioctl: multicast not done yet\n");
910 error = 0;
911 }
912 #else
913 error = EINVAL;
914 #endif
915 break;
916
917 default:
918 log(LOG_INFO, "qnioctl: default\n");
919 error = EINVAL;
920 }
921
922 splx(s);
923 return (error);
924 }
925
926 /*
927 * Dump some register information.
928 */
929 #ifdef QN_DEBUG1
930 static void
931 qn_dump(struct qn_softc *sc)
932 {
933
934 log(LOG_INFO, "t_status : %04x\n", *sc->nic_t_status);
935 log(LOG_INFO, "t_mask : %04x\n", *sc->nic_t_mask);
936 log(LOG_INFO, "t_mode : %04x\n", *sc->nic_t_mode);
937 log(LOG_INFO, "r_status : %04x\n", *sc->nic_r_status);
938 log(LOG_INFO, "r_mask : %04x\n", *sc->nic_r_mask);
939 log(LOG_INFO, "r_mode : %04x\n", *sc->nic_r_mode);
940 log(LOG_INFO, "pending : %02x\n", sc->transmit_pending);
941 log(LOG_INFO, "if_flags : %04x\n", sc->sc_ethercom.ec_if.if_flags);
942 }
943 #endif
944
945 #endif /* NQN > 0 */
946