if_iy.c revision 1.5 1 /* $NetBSD: if_iy.c,v 1.5 1996/05/22 15:39:43 is Exp $ */
2 /* #define IYDEBUG */
3 /* #define IYMEMDEBUG */
4 /*-
5 * Copyright (c) 1996 Ignatios Souvatzis.
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 contains software developed by Ignatios Souvatzis for
19 * the NetBSD project.
20 * 4. The names 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
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "bpfilter.h"
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mbuf.h>
41 #include <sys/buf.h>
42 #include <sys/protosw.h>
43 #include <sys/socket.h>
44 #include <sys/ioctl.h>
45 #include <sys/errno.h>
46 #include <sys/syslog.h>
47 #include <sys/device.h>
48
49 #include <net/if.h>
50 #include <net/if_types.h>
51 #include <net/if_dl.h>
52 #include <net/netisr.h>
53 #include <net/route.h>
54
55 #if NBPFILTER > 0
56 #include <net/bpf.h>
57 #include <net/bpfdesc.h>
58 #endif
59
60 #ifdef INET
61 #include <netinet/in.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/in_var.h>
64 #include <netinet/ip.h>
65 #include <netinet/if_ether.h>
66 #endif
67
68 #ifdef NS
69 #include <netns/ns.h>
70 #include <netns/ns_if.h>
71 #endif
72
73 #include <vm/vm.h>
74
75 #include <machine/cpu.h>
76 #include <machine/intr.h>
77 #include <machine/pio.h>
78
79 #include <dev/isa/isareg.h>
80 #include <dev/isa/isavar.h>
81 #include <dev/ic/i82595reg.h>
82
83 #define ETHER_MIN_LEN 64
84 #define ETHER_MAX_LEN 1518
85
86 /*
87 * Ethernet status, per interface.
88 */
89 struct iy_softc {
90 struct device sc_dev;
91 void *sc_ih;
92
93 int sc_iobase;
94 struct arpcom sc_arpcom;
95
96 #define MAX_MBS 8
97 struct mbuf *mb[MAX_MBS];
98 int next_mb, last_mb;
99
100 int mappedirq;
101
102 int hard_vers;
103
104 int promisc;
105
106 int sram, tx_size, rx_size;
107
108 int tx_start, tx_end, tx_last;
109 int rx_start;
110
111 #ifdef IYDEBUG
112 int sc_debug;
113 #endif
114 };
115
116 void iywatchdog __P((struct ifnet *));
117 int iyioctl __P((struct ifnet *, u_long, caddr_t));
118 int iyintr __P((void *));
119 void iyinit __P((struct iy_softc *));
120 void iystop __P((struct iy_softc *));
121 void iystart __P((struct ifnet *));
122
123 void iy_intr_rx __P((struct iy_softc *));
124 void iy_intr_tx __P((struct iy_softc *));
125 void eepro_reset_595 __P((struct iy_softc *));
126 int eepro_probe __P((struct iy_softc *, struct isa_attach_args *));
127 void eepro_eeprom_outbits __P((struct iy_softc *, int, int));
128 void eepro_eeprom_clock __P((struct iy_softc *, int));
129 u_short eepro_read_eeprom __P((struct iy_softc *, int));
130 int eepro_eeprom_inbits __P((struct iy_softc *));
131
132 void iyreset __P((struct iy_softc *));
133 void iy_readframe __P((struct iy_softc *, int));
134 void iy_drop_packet_buffer __P((struct iy_softc *));
135 void iy_find_mem_size __P((struct iy_softc *));
136 void iyrint __P((struct iy_softc *));
137 void iytint __P((struct iy_softc *));
138 void iyxmit __P((struct iy_softc *));
139 void iyget __P((struct iy_softc *, int, int));
140 void iymbuffill __P((void *));
141 void iymbufempty __P((void *));
142 void iyprobemem __P((struct iy_softc *));
143
144 /*
145 * void iymeminit __P((void *, struct iy_softc *));
146 * static int iy_mc_setup __P((struct iy_softc *, void *));
147 * static void iy_mc_reset __P((struct iy_softc *));
148 */
149 #ifdef IYDEBUGX
150 void print_rbd __P((volatile struct iy_recv_buf_desc *));
151
152 int in_ifrint = 0;
153 int in_iftint = 0;
154 #endif
155
156 int iyprobe __P((struct device *, void *, void *));
157 void iyattach __P((struct device *, struct device *, void *));
158
159 static u_int16_t eepromread __P((int, int));
160
161 struct cfattach iy_ca = {
162 sizeof(struct iy_softc), iyprobe, iyattach
163 };
164
165 struct cfdriver iy_cd = {
166 NULL, "iy", DV_IFNET
167 };
168
169 static u_int8_t eepro_irqmap[] = EEPP_INTMAP;
170 static u_int8_t eepro_revirqmap[] = EEPP_RINTMAP;
171
172 int
173 iyprobe(parent, match, aux)
174 struct device *parent;
175 void *match, *aux;
176 {
177 struct iy_softc *sc = match;
178 struct isa_attach_args *ia = aux;
179
180 u_int16_t eaddr[8];
181 int iobase;
182 int i;
183
184 u_int16_t checksum = 0;
185 u_int16_t eepromtmp;
186 u_int8_t c, d;
187
188
189 iobase = ia->ia_iobase;
190
191 if (iobase == -1)
192 return 0;
193
194 /* try to find the round robin sig: */
195
196 /* check here for addresses already given to other devices */
197
198 c = inb(iobase + ID_REG);
199 if (c & ID_REG_MASK != ID_REG_SIG)
200 return 0;
201
202 d = inb(iobase + ID_REG);
203 if (d & ID_REG_MASK != ID_REG_SIG)
204 return 0;
205
206 if (((d-c) & R_ROBIN_BITS) != 0x40)
207 return 0;
208
209 d = inb(iobase + ID_REG);
210 if (d & ID_REG_MASK != ID_REG_SIG)
211 return 0;
212
213 if (((d-c) & R_ROBIN_BITS) != 0x80)
214 return 0;
215
216 d = inb(iobase + ID_REG);
217 if (d & ID_REG_MASK != ID_REG_SIG)
218 return 0;
219
220 if (((d-c) & R_ROBIN_BITS) != 0xC0)
221 return 0;
222
223 d = inb(iobase + ID_REG);
224 if (d & ID_REG_MASK != ID_REG_SIG)
225 return 0;
226
227 if (((d-c) & R_ROBIN_BITS) != 0x00)
228 return 0;
229
230 #ifdef IYDEBUG
231 printf("eepro_probe verified working ID reg.\n");
232 #endif
233
234 for (i=0; i<64; ++i) {
235 eepromtmp = eepromread(iobase, i);
236 checksum += eepromtmp;
237 if (i<(sizeof(eaddr)/sizeof(*eaddr)))
238 eaddr[i] = eepromtmp;
239 }
240 if (checksum != EEPP_CHKSUM)
241 printf("wrong EEPROM checksum 0x%x should be 0x%x\n",
242 checksum, EEPP_CHKSUM);
243
244
245 if ((eaddr[EEPPEther0] != eepromread(iobase, EEPPEther0a)) &&
246 (eaddr[EEPPEther1] != eepromread(iobase, EEPPEther1a)) &&
247 (eaddr[EEPPEther2] != eepromread(iobase, EEPPEther2a)))
248 printf("EEPROM Ethernet address differs from copy\n");
249
250 sc->sc_arpcom.ac_enaddr[1] = eaddr[EEPPEther0] & 0xFF;
251 sc->sc_arpcom.ac_enaddr[0] = eaddr[EEPPEther0] >> 8;
252 sc->sc_arpcom.ac_enaddr[3] = eaddr[EEPPEther1] & 0xFF;
253 sc->sc_arpcom.ac_enaddr[2] = eaddr[EEPPEther1] >> 8;
254 sc->sc_arpcom.ac_enaddr[5] = eaddr[EEPPEther2] & 0xFF;
255 sc->sc_arpcom.ac_enaddr[4] = eaddr[EEPPEther2] >> 8;
256
257 if (ia->ia_irq == IRQUNK)
258 ia->ia_irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
259
260 if (ia->ia_irq >= sizeof(eepro_revirqmap))
261 return 0;
262
263 if ((sc->mappedirq = eepro_revirqmap[ia->ia_irq]) == -1)
264 return 0;
265
266 sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
267
268 /* now lets reset the chip */
269
270 outb(iobase + COMMAND_REG, RESET_CMD);
271 delay(200);
272
273 ia->ia_iobase = iobase;
274 ia->ia_iosize = 16;
275 return 1; /* found */
276 }
277
278 void
279 iyattach(parent, self, aux)
280 struct device *parent, *self;
281 void *aux;
282 {
283 struct iy_softc *sc = (void *)self;
284 struct isa_attach_args *ia = aux;
285 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
286
287 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
288 ifp->if_softc = sc;
289 ifp->if_start = iystart;
290 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
291 /* XXX todo: | IFF_MULTICAST */
292 sc->sc_iobase = ia->ia_iobase;
293
294 iyprobemem(sc);
295
296 ifp->if_ioctl = iyioctl;
297 ifp->if_watchdog = iywatchdog;
298
299 /* Attach the interface. */
300 if_attach(ifp);
301 ether_ifattach(ifp);
302 printf(": address %s, chip rev. %d, %d kB SRAM\n",
303 ether_sprintf(sc->sc_arpcom.ac_enaddr),
304 sc->hard_vers, sc->sram/1024);
305 #if NBPFILTER > 0
306 bpfattach(&sc->sc_arpcom.ac_if.if_bpf, ifp, DLT_EN10MB,
307 sizeof(struct ether_header));
308 #endif
309
310 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
311 IPL_NET, iyintr, sc);
312 }
313
314 void
315 iystop(sc)
316 struct iy_softc *sc;
317 {
318 int iobase;
319 #ifdef IYDEBUG
320 u_int p, v;
321 #endif
322
323 iobase = sc->sc_iobase;
324
325 outb(iobase + COMMAND_REG, RCV_DISABLE_CMD);
326
327 outb(iobase + INT_MASK_REG, ALL_INTS);
328 outb(iobase + STATUS_REG, ALL_INTS);
329
330 outb(iobase + COMMAND_REG, RESET_CMD);
331 delay(200);
332 #ifdef IYDEBUG
333 printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n",
334 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
335 p = sc->tx_last;
336 if (!p)
337 p = sc->tx_start;
338 do {
339 outw(iobase + HOST_ADDR_REG, p);
340 v = inw(iobase + MEM_PORT_REG);
341 printf("0x%04x: %b ", p, v, "\020\006Ab\010Dn");
342 v = inw(iobase + MEM_PORT_REG);
343 printf("0x%b", v, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL");
344 p = inw(iobase + MEM_PORT_REG);
345 printf(" 0x%04x", p);
346 v = inw(iobase + MEM_PORT_REG);
347 printf(" 0x%b\n", v, "\020\020Ch");
348
349 } while (v & 0x8000);
350 #endif
351 sc->tx_start = sc->tx_end = sc->rx_size;
352 sc->tx_last = 0;
353 sc->sc_arpcom.ac_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
354
355 iymbufempty((void *)sc);
356 }
357
358 void
359 iyreset(sc)
360 struct iy_softc *sc;
361 {
362 int s;
363 s = splimp();
364 iystop(sc);
365 iyinit(sc);
366 splx(s);
367 }
368
369 void
370 iyinit(sc)
371 struct iy_softc *sc;
372 {
373 int i;
374 unsigned temp;
375 struct ifnet *ifp;
376 int iobase;
377
378 ifp = &sc->sc_arpcom.ac_if;
379 #ifdef IYDEBUG
380 printf("ifp is %p\n", ifp);
381 #endif
382 iobase = sc->sc_iobase;
383
384 outb(iobase, BANK_SEL(2));
385
386 temp = inb(iobase + EEPROM_REG);
387 if (temp & 0x10)
388 outb(iobase + EEPROM_REG, temp & ~0x10);
389
390 for (i=0; i<6; ++i) {
391 outb(iobase + I_ADD(i), sc->sc_arpcom.ac_enaddr[i]);
392 }
393
394 temp = inb(iobase + REG1);
395 outb(iobase + REG1, temp | XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP |
396 RCV_DISCARD_BAD);
397
398 temp = inb(iobase + RECV_MODES_REG);
399 outb(iobase + RECV_MODES_REG, temp | MATCH_BRDCST);
400 #ifdef IYDEBUG
401 printf("%s: RECV_MODES were %b set to %b\n",
402 sc->sc_dev.dv_xname,
403 temp, "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA",
404 temp|MATCH_BRDCST,
405 "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA");
406 #endif
407
408
409 DELAY(500000); /* for the hardware to test for the connector */
410
411 temp = inb(iobase + MEDIA_SELECT);
412 #ifdef IYDEBUG
413 printf("%s: media select was 0x%b ", sc->sc_dev.dv_xname,
414 temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC");
415 #endif
416 temp = (temp & TEST_MODE_MASK);
417
418 switch(ifp->if_flags & (IFF_LINK0 | IFF_LINK1)) {
419 case IFF_LINK0:
420 temp &= ~ (BNC_BIT | TPE_BIT);
421 break;
422
423 case IFF_LINK1:
424 temp = temp & ~TPE_BIT | BNC_BIT;
425 break;
426
427 case IFF_LINK0|IFF_LINK1:
428 temp = temp & ~BNC_BIT | TPE_BIT;
429 break;
430 default:
431 /* nothing; leave as it is */
432 }
433
434 outb(iobase + MEDIA_SELECT, temp);
435 #ifdef IYDEBUG
436 printf("changed to 0x%b\n",
437 temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC");
438 #endif
439
440 outb(iobase, BANK_SEL(1));
441
442 temp = inb(iobase + INT_NO_REG);
443 outb(iobase + INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
444
445 #ifdef IYDEBUG
446 printf("%s: int no was %b\n", sc->sc_dev.dv_xname,
447 temp, "\020\4bad_irq\010flash/boot present");
448 temp = inb(iobase + INT_NO_REG);
449 printf("%s: int no now 0x%02x\n", sc->sc_dev.dv_xname,
450 temp, "\020\4BAD IRQ\010flash/boot present");
451 #endif
452
453
454 outb(iobase + RCV_LOWER_LIMIT_REG, 0);
455 outb(iobase + RCV_UPPER_LIMIT_REG, (sc->rx_size - 2) >> 8);
456 outb(iobase + XMT_LOWER_LIMIT_REG, sc->rx_size >> 8);
457 outb(iobase + XMT_UPPER_LIMIT_REG, sc->sram >> 8);
458
459 temp = inb(iobase + REG1);
460 #ifdef IYDEBUG
461 printf("%s: HW access is %b\n", sc->sc_dev.dv_xname,
462 temp, "\020\2WORD_WIDTH\010INT_ENABLE");
463 #endif
464 outb(iobase + REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */
465
466 #ifdef IYDEBUG
467 temp = inb(iobase + REG1);
468 printf("%s: HW access is %b\n", sc->sc_dev.dv_xname,
469 temp, "\020\2WORD_WIDTH\010INT_ENABLE");
470 #endif
471
472 outb(iobase, BANK_SEL(0));
473
474 outb(iobase + INT_MASK_REG, ALL_INTS & ~(RX_BIT|TX_BIT));
475 outb(iobase + STATUS_REG, ALL_INTS); /* clear ints */
476
477 outw(iobase + RCV_START_LOW, 0);
478 outw(iobase + RCV_STOP_LOW, sc->rx_size - 2);
479 sc->rx_start = 0;
480
481 outb(iobase, SEL_RESET_CMD);
482 DELAY(200);
483
484 outw(iobase + XMT_ADDR_REG, sc->rx_size);
485
486 sc->tx_start = sc->tx_end = sc->rx_size;
487 sc->tx_last = 0;
488
489 outb(iobase, RCV_ENABLE_CMD);
490
491 ifp->if_flags |= IFF_RUNNING;
492 ifp->if_flags &= ~IFF_OACTIVE;
493 }
494
495 void
496 iystart(ifp)
497 struct ifnet *ifp;
498 {
499 struct iy_softc *sc;
500 int iobase;
501
502 struct mbuf *m0, *m;
503 u_int len, pad, last, end;
504 u_int llen, residual;
505 int avail;
506 caddr_t data;
507 u_int16_t resval, stat;
508
509 #ifdef IYDEBUG
510 printf("iystart called\n");
511 #endif
512 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
513 return;
514
515 sc = ifp->if_softc;
516 iobase = sc->sc_iobase;
517
518 while ((m0 = ifp->if_snd.ifq_head) != NULL) {
519 #ifdef IYDEBUG
520 printf("%s: trying to write another packet to the hardware\n",
521 sc->sc_dev.dv_xname);
522 #endif
523
524 /* We need to use m->m_pkthdr.len, so require the header */
525 if ((m0->m_flags & M_PKTHDR) == 0)
526 panic("iystart: no header mbuf");
527
528 len = m0->m_pkthdr.len;
529 pad = len & 1;
530
531 #ifdef IYDEBUG
532 printf("%s: length is %d.\n", sc->sc_dev.dv_xname, len);
533 #endif
534 if (len < ETHER_MIN_LEN) {
535 pad = ETHER_MIN_LEN - len;
536 }
537
538 if (len + pad > ETHER_MAX_LEN) {
539 /* packet is obviously too large: toss it */
540 ++ifp->if_oerrors;
541 IF_DEQUEUE(&ifp->if_snd, m0);
542 m_freem(m0);
543 continue;
544 }
545
546 #if NBPFILTER > 0
547 if (ifp->if_bpf)
548 bpf_mtap(ifp->if_bpf, m0);
549 #endif
550
551 avail = sc->tx_start - sc->tx_end;
552 if (avail <= 0)
553 avail += sc->tx_size;
554
555 #ifdef IYDEBUG
556 printf("%s: avail is %d.\n", sc->sc_dev.dv_xname, avail);
557 #endif
558 /*
559 * we MUST RUN at splnet here ---
560 * XXX todo: or even turn off the boards ints ??? hm...
561 */
562
563 /* See if there is room to put another packet in the buffer. */
564
565 if ((len+pad+2*I595_XMT_HDRLEN) > avail) {
566 printf("%s: len = %d, avail = %d, setting OACTIVE\n",
567 sc->sc_dev.dv_xname, len, avail);
568 ifp->if_flags |= IFF_OACTIVE;
569 return;
570 }
571
572 /* we know it fits in the hardware now, so dequeue it */
573 IF_DEQUEUE(&ifp->if_snd, m0);
574
575 last = sc->tx_end;
576 end = last + pad + len + I595_XMT_HDRLEN;
577
578 if (end >= sc->sram) {
579 if ((sc->sram - last) <= I595_XMT_HDRLEN) {
580 /* keep header in one piece */
581 last = sc->rx_size;
582 end = last + pad + len + I595_XMT_HDRLEN;
583 } else
584 end -= sc->tx_size;
585 }
586
587 outw(iobase + HOST_ADDR_REG, last);
588 outw(iobase + MEM_PORT_REG, XMT_CMD);
589 outw(iobase + MEM_PORT_REG, 0);
590 outw(iobase + MEM_PORT_REG, 0);
591 outw(iobase + MEM_PORT_REG, len + pad);
592
593 residual = resval = 0;
594
595 while ((m = m0)!=0) {
596 data = mtod(m, caddr_t);
597 llen = m->m_len;
598 if (residual) {
599 #ifdef IYDEBUG
600 printf("%s: merging residual with next mbuf.\n",
601 sc->sc_dev.dv_xname);
602 #endif
603 resval |= *data << 8;
604 outw(iobase + MEM_PORT_REG, resval);
605 --llen;
606 ++data;
607 }
608 if (llen > 1)
609 outsw(iobase + MEM_PORT_REG, data, llen>>1);
610 residual = llen & 1;
611 if (residual) {
612 resval = *(data + llen - 1);
613 #ifdef IYDEBUG
614 printf("%s: got odd mbuf to send.\n",
615 sc->sc_dev.dv_xname);
616 #endif
617 }
618
619 MFREE(m, m0);
620 }
621
622 if (residual)
623 outw(iobase + MEM_PORT_REG, resval);
624
625 pad >>= 1;
626 while (pad-- > 0)
627 outw(iobase + MEM_PORT_REG, 0);
628
629 #ifdef IYDEBUG
630 printf("%s: new last = 0x%x, end = 0x%x.\n",
631 sc->sc_dev.dv_xname, last, end);
632 printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n",
633 sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
634 #endif
635
636 if (sc->tx_start != sc->tx_end) {
637 outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_COUNT);
638 stat = inw(iobase + MEM_PORT_REG);
639
640 outw(iobase + HOST_ADDR_REG, sc->tx_last + XMT_CHAIN);
641 outw(iobase + MEM_PORT_REG, last);
642 outw(iobase + MEM_PORT_REG, stat | CHAIN);
643 #ifdef IYDEBUG
644 printf("%s: setting 0x%x to 0x%x\n",
645 sc->sc_dev.dv_xname, sc->tx_last + XMT_COUNT,
646 stat | CHAIN);
647 #endif
648 }
649 stat = inw(iobase + MEM_PORT_REG); /* dummy read */
650
651 /* XXX todo: enable ints here if disabled */
652
653 ++ifp->if_opackets;
654
655 if (sc->tx_start == sc->tx_end) {
656 outw(iobase + XMT_ADDR_REG, last);
657 outb(iobase, XMT_CMD);
658 sc->tx_start = last;
659 #ifdef IYDEBUG
660 printf("%s: writing 0x%x to XAR and giving XCMD\n",
661 sc->sc_dev.dv_xname, last);
662 #endif
663 } else {
664 outb(iobase, RESUME_XMT_CMD);
665 #ifdef IYDEBUG
666 printf("%s: giving RESUME_XCMD\n",
667 sc->sc_dev.dv_xname);
668 #endif
669 }
670 sc->tx_last = last;
671 sc->tx_end = end;
672 }
673 }
674
675
676 static __inline void
677 eepromwritebit(eio, what)
678 int eio, what;
679 {
680 outb(eio, what);
681 delay(1);
682 outb(eio, what|EESK);
683 delay(1);
684 outb(eio, what);
685 delay(1);
686 }
687
688 static __inline int
689 eepromreadbit(eio)
690 int eio;
691 {
692 int b;
693
694 outb(eio, EECS|EESK);
695 delay(1);
696 b = inb(eio);
697 outb(eio, EECS);
698 delay(1);
699
700 return ((b & EEDO) != 0);
701 }
702
703 static u_int16_t
704 eepromread(io, offset)
705 int io, offset;
706 {
707 volatile int i;
708 volatile int j;
709 volatile u_int16_t readval;
710 int eio = io+EEPROM_REG;
711
712 outb(io, BANK_SEL(2));
713 delay(1);
714 outb(io, EECS);
715 delay(1);
716
717 eepromwritebit(eio, EECS|EEDI);
718 eepromwritebit(eio, EECS|EEDI);
719 eepromwritebit(eio, EECS);
720
721 for (j=5; j>=0; --j) {
722 if ((offset>>j) & 1)
723 eepromwritebit(eio, EECS|EEDI);
724 else
725 eepromwritebit(eio, EECS);
726 }
727
728 for (readval=0, i=0; i<16; ++i) {
729 readval<<=1;
730 readval |= eepromreadbit(eio);
731 }
732
733 outb(eio, 0|EESK);
734 delay(1);
735 outb(eio, 0);
736
737 outb(eio, BANK_SEL(0));
738
739 return readval;
740 }
741
742 /*
743 * Device timeout/watchdog routine. Entered if the device neglects to generate
744 * an interrupt after a transmit has been started on it.
745 */
746 void
747 iywatchdog(ifp)
748 struct ifnet *ifp;
749 {
750 struct iy_softc *sc = ifp->if_softc;
751
752 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
753 ++sc->sc_arpcom.ac_if.if_oerrors;
754 iyreset(sc);
755 }
756
757 /*
758 * What to do upon receipt of an interrupt.
759 */
760 int
761 iyintr(arg)
762 void *arg;
763 {
764 struct iy_softc *sc = arg;
765 int iobase;
766 register u_short status;
767
768 iobase = sc->sc_iobase;
769 status = inb(iobase + STATUS_REG);
770 #ifdef IYDEBUG
771 if (status & ALL_INTS) {
772 printf("%s: got interupt %b", sc->sc_dev.dv_xname, status,
773 "\020\1RX_STP\2RX\3TX\4EXEC");
774 if (status & EXEC_INT)
775 printf(" event %b\n", inb(iobase),
776 "\020\6ABORT");
777 else
778 printf("\n");
779 }
780 #endif
781 if ((status & (RX_INT | TX_INT) == 0))
782 return 0;
783
784 if (status & RX_INT) {
785 iy_intr_rx(sc);
786 outb(iobase + STATUS_REG, RX_INT);
787 } else if (status & TX_INT) {
788 iy_intr_tx(sc);
789 outb(iobase + STATUS_REG, TX_INT);
790 }
791 return 1;
792 }
793
794 void
795 iyget(sc, iobase, rxlen)
796 struct iy_softc *sc;
797 int iobase, rxlen;
798 {
799 struct mbuf *m, *top, **mp;
800 struct ether_header *eh;
801 struct ifnet *ifp;
802 int len;
803
804 ifp = &sc->sc_arpcom.ac_if;
805
806 m = sc->mb[sc->next_mb];
807 sc->mb[sc->next_mb] = 0;
808 if (m == 0) {
809 MGETHDR(m, M_DONTWAIT, MT_DATA);
810 if (m == 0)
811 goto dropped;
812 } else {
813 if (sc->last_mb == sc->next_mb)
814 timeout(iymbuffill, sc, 1);
815 sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
816 m->m_data = m->m_pktdat;
817 m->m_flags = M_PKTHDR;
818 }
819 m->m_pkthdr.rcvif = ifp;
820 m->m_pkthdr.len = rxlen;
821 len = MHLEN;
822 top = 0;
823 mp = ⊤
824
825 while (rxlen > 0) {
826 if (top) {
827 m = sc->mb[sc->next_mb];
828 sc->mb[sc->next_mb] = 0;
829 if (m == 0) {
830 MGET(m, M_DONTWAIT, MT_DATA);
831 if (m == 0) {
832 m_freem(top);
833 goto dropped;
834 }
835 } else {
836 sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
837 }
838 len = MLEN;
839 }
840 if (rxlen >= MINCLSIZE) {
841 MCLGET(m, M_DONTWAIT);
842 if (m->m_flags & M_EXT)
843 len = MCLBYTES;
844 }
845 len = min(rxlen, len);
846 if (len > 1) {
847 len &= ~1;
848 insw(iobase + MEM_PORT_REG, mtod(m, caddr_t), len/2);
849 } else {
850 #ifdef IYDEBUG
851 printf("%s: received odd mbuf\n", sc->sc_dev.dv_xname);
852 #endif
853 *(mtod(m, caddr_t)) = inw(iobase + MEM_PORT_REG);
854 }
855 m->m_len = len;
856 rxlen -= len;
857 *mp = m;
858 mp = &m->m_next;
859 }
860 /* XXX receive the top here */
861 ++ifp->if_ipackets;
862
863 eh = mtod(top, struct ether_header *);
864
865 #if NBPFILTER > 0
866 if (ifp->if_bpf) {
867 bpf_mtap(ifp->if_bpf, top);
868 if ((ifp->if_flags & IFF_PROMISC) &&
869 (eh->ether_dhost[0] & 1) == 0 &&
870 bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
871 sizeof(eh->ether_dhost)) != 0) {
872 m_freem(top);
873 return;
874 }
875 }
876 #endif
877 m_adj(top, sizeof(struct ether_header));
878 ether_input(ifp, eh, top);
879 return;
880
881 dropped:
882 ++ifp->if_ierrors;
883 return;
884 }
885 void
886 iy_intr_rx(sc)
887 struct iy_softc *sc;
888 {
889 struct ifnet *ifp;
890 int iobase;
891 u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen;
892
893 iobase = sc->sc_iobase;
894 ifp = &sc->sc_arpcom.ac_if;
895
896 rxadrs = sc->rx_start;
897 outw(iobase + HOST_ADDR_REG, rxadrs);
898 rxevnt = inw(iobase + MEM_PORT_REG);
899 rxnext = 0;
900
901 while (rxevnt == RCV_DONE) {
902 rxstatus = inw(iobase + MEM_PORT_REG);
903 rxnext = inw(iobase + MEM_PORT_REG);
904 rxlen = inw(iobase + MEM_PORT_REG);
905 #ifdef IYDEBUG
906 printf("%s: pck at 0x%04x stat %b next 0x%x len 0x%x\n",
907 sc->sc_dev.dv_xname, rxadrs, rxstatus,
908 "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR"
909 "\014CRCERR\015LENERR\016RCVOK\020TYP",
910 rxnext, rxlen);
911 #endif
912 iyget(sc, iobase, rxlen);
913
914 /* move stop address */
915 outw(iobase + RCV_STOP_LOW,
916 rxnext == 0 ? sc->rx_size - 2 : rxnext - 2);
917
918 outw(iobase + HOST_ADDR_REG, rxnext);
919 rxadrs = rxnext;
920 rxevnt = inw(iobase + MEM_PORT_REG);
921 }
922 sc->rx_start = rxnext;
923 }
924
925 void
926 iy_intr_tx(sc)
927 struct iy_softc *sc;
928 {
929 int iobase;
930 struct ifnet *ifp;
931 u_int txstatus, txstat2, txlen, txnext;
932
933 ifp = &sc->sc_arpcom.ac_if;
934 iobase = sc->sc_iobase;
935
936 while (sc->tx_start != sc->tx_end) {
937 outw(iobase + HOST_ADDR_REG, sc->tx_start);
938 txstatus = inw(iobase + MEM_PORT_REG);
939 if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD))
940 break;
941
942 txstat2 = inw(iobase + MEM_PORT_REG);
943 txnext = inw(iobase + MEM_PORT_REG);
944 txlen = inw(iobase + MEM_PORT_REG);
945 #ifdef IYDEBUG
946 printf("txstat 0x%x stat2 0x%b next 0x%x len 0x%x\n",
947 txstatus, txstat2, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF"
948 "\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL",
949 txnext, txlen);
950 #endif
951 if (txlen & CHAIN)
952 sc->tx_start = txnext;
953 else
954 sc->tx_start = sc->tx_end;
955 ifp->if_flags &= ~IFF_OACTIVE;
956
957 if ((txstat2 & 0x2000) == 0)
958 ++ifp->if_oerrors;
959 if (txstat2 & 0x000f)
960 ifp->if_oerrors += txstat2 & 0x000f;
961 }
962 ifp->if_flags &= ~IFF_OACTIVE;
963 }
964
965 #if 0
966 /*
967 * Compare two Ether/802 addresses for equality, inlined and unrolled for
968 * speed. I'd love to have an inline assembler version of this...
969 */
970 static inline int
971 ether_equal(one, two)
972 u_char *one, *two;
973 {
974
975 if (one[0] != two[0] || one[1] != two[1] || one[2] != two[2] ||
976 one[3] != two[3] || one[4] != two[4] || one[5] != two[5])
977 return 0;
978 return 1;
979 }
980
981 /*
982 * Check for a valid address. to_bpf is filled in with one of the following:
983 * 0 -> BPF doesn't get this packet
984 * 1 -> BPF does get this packet
985 * 2 -> BPF does get this packet, but we don't
986 * Return value is true if the packet is for us, and false otherwise.
987 *
988 * This routine is a mess, but it's also critical that it be as fast
989 * as possible. It could be made cleaner if we can assume that the
990 * only client which will fiddle with IFF_PROMISC is BPF. This is
991 * probably a good assumption, but we do not make it here. (Yet.)
992 */
993 static inline int
994 check_eh(sc, eh, to_bpf)
995 struct iy_softc *sc;
996 struct ether_header *eh;
997 int *to_bpf;
998 {
999 int i;
1000
1001 switch (sc->promisc) {
1002 case IFF_ALLMULTI:
1003 /*
1004 * Receiving all multicasts, but no unicasts except those
1005 * destined for us.
1006 */
1007 #if NBPFILTER > 0
1008 *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0); /* BPF gets this packet if anybody cares */
1009 #endif
1010 if (eh->ether_dhost[0] & 1)
1011 return 1;
1012 if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
1013 return 1;
1014 return 0;
1015
1016 case IFF_PROMISC:
1017 /*
1018 * Receiving all packets. These need to be passed on to BPF.
1019 */
1020 #if NBPFILTER > 0
1021 *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0);
1022 #endif
1023 /* If for us, accept and hand up to BPF */
1024 if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
1025 return 1;
1026
1027 #if NBPFILTER > 0
1028 if (*to_bpf)
1029 *to_bpf = 2; /* we don't need to see it */
1030 #endif
1031
1032 /*
1033 * Not a multicast, so BPF wants to see it but we don't.
1034 */
1035 if (!(eh->ether_dhost[0] & 1))
1036 return 1;
1037
1038 /*
1039 * If it's one of our multicast groups, accept it and pass it
1040 * up.
1041 */
1042 for (i = 0; i < sc->mcast_count; i++) {
1043 if (ether_equal(eh->ether_dhost, (u_char *)&sc->mcast_addrs[i])) {
1044 #if NBPFILTER > 0
1045 if (*to_bpf)
1046 *to_bpf = 1;
1047 #endif
1048 return 1;
1049 }
1050 }
1051 return 1;
1052
1053 case IFF_ALLMULTI | IFF_PROMISC:
1054 /*
1055 * Acting as a multicast router, and BPF running at the same
1056 * time. Whew! (Hope this is a fast machine...)
1057 */
1058 #if NBPFILTER > 0
1059 *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0);
1060 #endif
1061 /* We want to see multicasts. */
1062 if (eh->ether_dhost[0] & 1)
1063 return 1;
1064
1065 /* We want to see our own packets */
1066 if (ether_equal(eh->ether_dhost, sc->sc_arpcom.ac_enaddr))
1067 return 1;
1068
1069 /* Anything else goes to BPF but nothing else. */
1070 #if NBPFILTER > 0
1071 if (*to_bpf)
1072 *to_bpf = 2;
1073 #endif
1074 return 1;
1075
1076 case 0:
1077 /*
1078 * Only accept unicast packets destined for us, or multicasts
1079 * for groups that we belong to. For now, we assume that the
1080 * '586 will only return packets that we asked it for. This
1081 * isn't strictly true (it uses hashing for the multicast
1082 * filter), but it will do in this case, and we want to get out
1083 * of here as quickly as possible.
1084 */
1085 #if NBPFILTER > 0
1086 *to_bpf = (sc->sc_arpcom.ac_if.iy_bpf != 0);
1087 #endif
1088 return 1;
1089 }
1090
1091 #ifdef DIAGNOSTIC
1092 panic("check_eh: impossible");
1093 #endif
1094 }
1095 #endif
1096
1097 int
1098 iyioctl(ifp, cmd, data)
1099 register struct ifnet *ifp;
1100 u_long cmd;
1101 caddr_t data;
1102 {
1103 struct iy_softc *sc;
1104 struct ifaddr *ifa;
1105 struct ifreq *ifr;
1106 int s, error = 0;
1107
1108 sc = ifp->if_softc;
1109 ifa = (struct ifaddr *)data;
1110 ifr = (struct ifreq *)data;
1111
1112 #ifdef IYDEBUG
1113 printf("iyioctl called with ifp 0x%p (%s) cmd 0x%x data 0x%p\n",
1114 ifp, ifp->if_xname, cmd, data);
1115 #endif
1116
1117 s = splimp();
1118
1119 switch (cmd) {
1120
1121 case SIOCSIFADDR:
1122 ifp->if_flags |= IFF_UP;
1123
1124 switch (ifa->ifa_addr->sa_family) {
1125 #ifdef INET
1126 case AF_INET:
1127 iyinit(sc);
1128 arp_ifinit(&sc->sc_arpcom, ifa);
1129 break;
1130 #endif
1131 #ifdef NS
1132 /* XXX - This code is probably wrong. */
1133 case AF_NS:
1134 {
1135 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
1136
1137 if (ns_nullhost(*ina))
1138 ina->x_host =
1139 *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
1140 else
1141 bcopy(ina->x_host.c_host,
1142 sc->sc_arpcom.ac_enaddr,
1143 sizeof(sc->sc_arpcom.ac_enaddr));
1144 /* Set new address. */
1145 iyinit(sc);
1146 break;
1147 }
1148 #endif /* NS */
1149 default:
1150 iyinit(sc);
1151 break;
1152 }
1153 break;
1154
1155 case SIOCSIFFLAGS:
1156 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1157 if ((ifp->if_flags & IFF_UP) == 0 &&
1158 (ifp->if_flags & IFF_RUNNING) != 0) {
1159 /*
1160 * If interface is marked down and it is running, then
1161 * stop it.
1162 */
1163 iystop(sc);
1164 ifp->if_flags &= ~IFF_RUNNING;
1165 } else if ((ifp->if_flags & IFF_UP) != 0 &&
1166 (ifp->if_flags & IFF_RUNNING) == 0) {
1167 /*
1168 * If interface is marked up and it is stopped, then
1169 * start it.
1170 */
1171 iyinit(sc);
1172 } else {
1173 /*
1174 * Reset the interface to pick up changes in any other
1175 * flags that affect hardware registers.
1176 */
1177 iystop(sc);
1178 iyinit(sc);
1179 }
1180 #ifdef IYDEBUGX
1181 if (ifp->if_flags & IFF_DEBUG)
1182 sc->sc_debug = IFY_ALL;
1183 else
1184 sc->sc_debug = 0;
1185 #endif
1186 break;
1187
1188 #if 0 /* XXX */
1189 case SIOCADDMULTI:
1190 case SIOCDELMULTI:
1191 error = (cmd == SIOCADDMULTI) ?
1192 ether_addmulti(ifr, &sc->sc_arpcom):
1193 ether_delmulti(ifr, &sc->sc_arpcom);
1194
1195 if (error == ENETRESET) {
1196 /*
1197 * Multicast list has changed; set the hardware filter
1198 * accordingly.
1199 */
1200 iy_mc_reset(sc); /* XXX */
1201 error = 0;
1202 }
1203 break;
1204 #endif
1205 default:
1206 error = EINVAL;
1207 }
1208 splx(s);
1209 return error;
1210 }
1211
1212 #if 0
1213 static void
1214 iy_mc_reset(sc)
1215 struct iy_softc *sc;
1216 {
1217 struct ether_multi *enm;
1218 struct ether_multistep step;
1219
1220 /*
1221 * Step through the list of addresses.
1222 */
1223 sc->mcast_count = 0;
1224 ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
1225 while (enm) {
1226 if (sc->mcast_count >= MAXMCAST ||
1227 bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
1228 sc->sc_arpcom.ac_if.if_flags |= IFF_ALLMULTI;
1229 iyioctl(&sc->sc_arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
1230 goto setflag;
1231 }
1232
1233 bcopy(enm->enm_addrlo, &sc->mcast_addrs[sc->mcast_count], 6);
1234 sc->mcast_count++;
1235 ETHER_NEXT_MULTI(step, enm);
1236 }
1237 setflag:
1238 sc->want_mcsetup = 1;
1239 }
1240
1241 #ifdef IYDEBUG
1242 void
1243 print_rbd(rbd)
1244 volatile struct ie_recv_buf_desc *rbd;
1245 {
1246
1247 printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1248 "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1249 rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1250 rbd->mbz);
1251 }
1252 #endif
1253 #endif
1254
1255 void
1256 iymbuffill(arg)
1257 void *arg;
1258 {
1259 struct iy_softc *sc = (struct iy_softc *)arg;
1260 int s, i;
1261
1262 s = splimp();
1263 i = sc->last_mb;
1264 do {
1265 if (sc->mb[i] == NULL)
1266 MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
1267 if (sc->mb[i] == NULL)
1268 break;
1269 i = (i + 1) % MAX_MBS;
1270 } while (i != sc->next_mb);
1271 sc->last_mb = i;
1272 /* If the queue was not filled, try again. */
1273 if (sc->last_mb != sc->next_mb)
1274 timeout(iymbuffill, sc, 1);
1275 splx(s);
1276 }
1277
1278
1279 void
1280 iymbufempty(arg)
1281 void *arg;
1282 {
1283 struct iy_softc *sc = (struct iy_softc *)arg;
1284 int s, i;
1285
1286 s = splimp();
1287 for (i = 0; i<MAX_MBS; i++) {
1288 if (sc->mb[i]) {
1289 m_freem(sc->mb[i]);
1290 sc->mb[i] = NULL;
1291 }
1292 }
1293 sc->last_mb = sc->next_mb = 0;
1294 untimeout(iymbuffill, sc);
1295 splx(s);
1296 }
1297
1298 void
1299 iyprobemem(sc)
1300 struct iy_softc *sc;
1301 {
1302 int iobase;
1303 int testing;
1304
1305 iobase = sc->sc_iobase;
1306
1307 outw(iobase + HOST_ADDR_REG, 4096-2);
1308 outw(iobase + MEM_PORT_REG, 0);
1309
1310 for (testing=65536; testing >= 4096; testing >>= 1) {
1311 outw(iobase + HOST_ADDR_REG, testing-2);
1312 outw(iobase + MEM_PORT_REG, 0xdead);
1313 outw(iobase + HOST_ADDR_REG, testing-2);
1314 if (inw(iobase + MEM_PORT_REG) != 0xdead) {
1315 #ifdef IYMEMDEBUG
1316 printf("%s: Didn't keep 0xdead at 0x%x\n",
1317 sc->sc_dev.dv_xname, testing-2);
1318 #endif
1319 continue;
1320 }
1321
1322 outw(iobase + HOST_ADDR_REG, testing-2);
1323 outw(iobase + MEM_PORT_REG, 0xbeef);
1324 outw(iobase + HOST_ADDR_REG, testing-2);
1325 if (inw(iobase + MEM_PORT_REG) != 0xbeef) {
1326 #ifdef IYMEMDEBUG
1327 printf("%s: Didn't keep 0xbeef at 0x%x\n",
1328 sc->sc_dev.dv_xname, testing-2);
1329 #endif
1330 continue;
1331 }
1332
1333 outw(iobase + HOST_ADDR_REG, 0);
1334 outw(iobase + MEM_PORT_REG, 0);
1335 outw(iobase + HOST_ADDR_REG, testing >> 1);
1336 outw(iobase + MEM_PORT_REG, testing >> 1);
1337 outw(iobase + HOST_ADDR_REG, 0);
1338 if (inw(iobase + MEM_PORT_REG) == (testing >> 1)) {
1339 #ifdef IYMEMDEBUG
1340 printf("%s: 0x%x alias of 0x0\n",
1341 sc->sc_dev.dv_xname, testing >> 1);
1342 #endif
1343 continue;
1344 }
1345
1346 break;
1347 }
1348
1349 sc->sram = testing;
1350
1351 switch(testing) {
1352 case 65536:
1353 /* 4 NFS packets + overhead RX, 2 NFS + overhead TX */
1354 sc->rx_size = 44*1024;
1355 break;
1356
1357 case 32768:
1358 /* 2 NFS packets + overhead RX, 1 NFS + overhead TX */
1359 sc->rx_size = 22*1024;
1360 break;
1361
1362 case 16384:
1363 /* 1 NFS packet + overhead RX, 4 big packets TX */
1364 sc->rx_size = 10*1024;
1365 break;
1366 default:
1367 sc->rx_size = testing/2;
1368 break;
1369 }
1370 sc->tx_size = testing - sc->rx_size;
1371 }
1372