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