if_le.c revision 1.17 1 /*
2 * Copyright (c) 1982, 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)if_le.c 7.6 (Berkeley) 5/8/91
34 * $Id: if_le.c,v 1.17 1994/07/25 22:55:19 mycroft Exp $
35 */
36
37 #include "le.h"
38 #if NLE > 0
39
40 #include "bpfilter.h"
41
42 /*
43 * AMD 7990 LANCE
44 */
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/mbuf.h>
49 #include <sys/buf.h>
50 #include <sys/socket.h>
51 #include <sys/syslog.h>
52 #include <sys/ioctl.h>
53 #include <sys/malloc.h>
54 #include <sys/errno.h>
55
56 #include <net/if.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59 #if NBPFILTER > 0
60 #include <net/bpf.h>
61 #include <net/bpfdesc.h>
62 #endif
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 #endif
71
72 #ifdef NS
73 #include <netns/ns.h>
74 #include <netns/ns_if.h>
75 #endif
76
77 #include <machine/cpu.h>
78 #include <hp300/hp300/isr.h>
79 #include <machine/mtpr.h>
80
81 #include <hp300/dev/device.h>
82 #include <hp300/dev/if_lereg.h>
83
84
85 #define ETHER_MIN_LEN 64
86 #define ETHER_MAX_LEN 1518
87 #define ETHER_ADDR_LEN 6
88
89
90 /* offsets for: ID, REGS, MEM, NVRAM */
91 int lestd[] = { 0, 0x4000, 0x8000, 0xC008 };
92
93 struct isr le_isr[NLE];
94
95 /*
96 * Ethernet software status per interface.
97 *
98 * Each interface is referenced by a network interface structure,
99 * arpcom.ac_if, which the routing code uses to locate the interface.
100 * This structure contains the output queue for the interface, its address, ...
101 */
102 struct le_softc {
103 struct arpcom sc_arpcom; /* common Ethernet structures */
104 struct lereg0 *sc_r0; /* DIO registers */
105 struct lereg1 *sc_r1; /* LANCE registers */
106 void *sc_mem;
107 struct init_block *sc_init;
108 struct mds *sc_rd, *sc_td;
109 u_char *sc_rbuf, *sc_tbuf;
110 int sc_last_rd, sc_last_td;
111 int sc_no_td;
112 #ifdef LEDEBUG
113 int sc_debug;
114 #endif
115 } le_softc[NLE];
116
117 int leintr __P((int));
118 int leioctl __P((struct ifnet *, int, caddr_t));
119 int lestart __P((struct ifnet *));
120 int lewatchdog __P((/* short */));
121 static inline void lewrcsr __P((/* struct le_softc *, u_short, u_short */));
122 static inline u_short lerdcsr __P((/* struct le_softc *, u_short */));
123 void leinit __P((struct le_softc *));
124 void lememinit __P((struct le_softc *));
125 void lereset __P((struct le_softc *));
126 void lestop __P((struct le_softc *));
127 void letint __P((int));
128 void lerint __P((int));
129 void leread __P((struct le_softc *, u_char *, int));
130 struct mbuf *leget __P((u_char *, int, struct ifnet *));
131 #ifdef LEDEBUG
132 void recv_print __P((struct le_softc *, int));
133 void xmit_print __P((struct le_softc *, int));
134 #endif
135 void lesetladrf __P((struct arpcom *, u_long *));
136
137 int leattach __P((struct hp_device *));
138
139 struct driver ledriver = {
140 leattach, "le",
141 };
142
143 static inline void
144 lewrcsr(sc, port, val)
145 struct le_softc *sc;
146 register u_short port;
147 register u_short val;
148 {
149 register struct lereg0 *ler0 = sc->sc_r0;
150 register struct lereg1 *ler1 = sc->sc_r1;
151
152 do {
153 ler1->ler1_rap = port;
154 } while ((ler0->ler0_status & LE_ACK) == 0);
155 do {
156 ler1->ler1_rdp = val;
157 } while ((ler0->ler0_status & LE_ACK) == 0);
158 }
159
160 static inline u_short
161 lerdcsr(sc, port)
162 struct le_softc *sc;
163 register u_short port;
164 {
165 register struct lereg0 *ler0 = sc->sc_r0;
166 register struct lereg1 *ler1 = sc->sc_r1;
167 register u_short val;
168
169 do {
170 ler1->ler1_rap = port;
171 } while ((ler0->ler0_status & LE_ACK) == 0);
172 do {
173 val = ler1->ler1_rdp;
174 } while ((ler0->ler0_status & LE_ACK) == 0);
175 return (val);
176 }
177
178 /*
179 * Interface exists: make available by filling in network interface
180 * record. System will initialize the interface when it is ready
181 * to accept packets.
182 */
183 int
184 leattach(hd)
185 struct hp_device *hd;
186 {
187 register struct lereg0 *ler0;
188 struct le_softc *sc = &le_softc[hd->hp_unit];
189 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
190 char *cp;
191 int i;
192
193 ler0 = sc->sc_r0 = (struct lereg0 *)(lestd[0] + (int)hd->hp_addr);
194 if (ler0->ler0_id != LEID)
195 return(0);
196 sc->sc_r1 = (struct lereg1 *)(lestd[1] + (int)hd->hp_addr);
197 sc->sc_mem = (void *)(lestd[2] + (int)hd->hp_addr);
198 le_isr[hd->hp_unit].isr_intr = leintr;
199 hd->hp_ipl = le_isr[hd->hp_unit].isr_ipl = LE_IPL(ler0->ler0_status);
200 le_isr[hd->hp_unit].isr_arg = hd->hp_unit;
201 ler0->ler0_id = 0xFF;
202 DELAY(100);
203
204 /*
205 * Read the ethernet address off the board, one nibble at a time.
206 */
207 cp = (char *)(lestd[3] + (int)hd->hp_addr);
208 for (i = 0; i < sizeof(sc->sc_arpcom.ac_enaddr); i++) {
209 sc->sc_arpcom.ac_enaddr[i] = (*++cp & 0xF) << 4;
210 cp++;
211 sc->sc_arpcom.ac_enaddr[i] |= *++cp & 0xF;
212 cp++;
213 }
214 printf("le%d: hardware address %s\n", hd->hp_unit,
215 ether_sprintf(sc->sc_arpcom.ac_enaddr));
216
217 isrlink(&le_isr[hd->hp_unit]);
218 ler0->ler0_status = LE_IE;
219
220 ifp->if_unit = hd->hp_unit;
221 ifp->if_name = "le";
222 ifp->if_output = ether_output;
223 ifp->if_start = lestart;
224 ifp->if_ioctl = leioctl;
225 ifp->if_watchdog = lewatchdog;
226 ifp->if_flags =
227 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
228
229 if_attach(ifp);
230 ether_ifattach(ifp);
231
232 #if NBPFILTER > 0
233 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
234 #endif
235 return (1);
236 }
237
238 void
239 lereset(sc)
240 struct le_softc *sc;
241 {
242
243 leinit(sc);
244 }
245
246 int
247 lewatchdog(unit)
248 short unit;
249 {
250 struct le_softc *sc = &le_softc[unit];
251
252 log(LOG_ERR, "le%d: device timeout\n", unit);
253 ++sc->sc_arpcom.ac_if.if_oerrors;
254 lereset(sc);
255 }
256
257 #define LANCE_ADDR(sc, a) \
258 ((u_long)(a) - (u_long)sc->sc_mem)
259
260 /* LANCE initialization block set up. */
261 void
262 lememinit(sc)
263 register struct le_softc *sc;
264 {
265 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
266 int i;
267 void *mem;
268 u_long a;
269
270 /*
271 * At this point we assume that the memory allocated to the Lance is
272 * quadword aligned. If it isn't then the initialisation is going
273 * fail later on.
274 */
275 mem = sc->sc_mem;
276
277 sc->sc_init = mem;
278 #if NBPFILTER > 0
279 if (ifp->if_flags & IFF_PROMISC)
280 sc->sc_init->mode = LE_NORMAL | LE_PROM;
281 else
282 #endif
283 sc->sc_init->mode = LE_NORMAL;
284 for (i = 0; i < ETHER_ADDR_LEN; i++)
285 sc->sc_init->padr[i] = sc->sc_arpcom.ac_enaddr[i^1];
286 lesetladrf(&sc->sc_arpcom, sc->sc_init->ladrf);
287 mem += sizeof(struct init_block);
288
289 sc->sc_rd = mem;
290 a = LANCE_ADDR(sc, mem);
291 sc->sc_init->rdra = a;
292 sc->sc_init->rlen = ((a >> 16) & 0xff) | (RLEN << 13);
293 mem += NRBUF * sizeof(struct mds);
294
295 sc->sc_td = mem;
296 a = LANCE_ADDR(sc, mem);
297 sc->sc_init->tdra = a;
298 sc->sc_init->tlen = ((a >> 16) & 0xff) | (TLEN << 13);
299 mem += NTBUF * sizeof(struct mds);
300
301 /*
302 * Set up receive ring descriptors.
303 */
304 sc->sc_rbuf = mem;
305 for (i = 0; i < NRBUF; i++) {
306 a = LANCE_ADDR(sc, mem);
307 sc->sc_rd[i].addr = a;
308 sc->sc_rd[i].flags = ((a >> 16) & 0xff) | LE_OWN;
309 sc->sc_rd[i].bcnt = -BUFSIZE;
310 sc->sc_rd[i].mcnt = 0;
311 mem += BUFSIZE;
312 }
313
314 /*
315 * Set up transmit ring descriptors.
316 */
317 sc->sc_tbuf = mem;
318 for (i = 0; i < NTBUF; i++) {
319 a = LANCE_ADDR(sc, mem);
320 sc->sc_td[i].addr = a;
321 sc->sc_td[i].flags= ((a >> 16) & 0xff);
322 sc->sc_td[i].bcnt = 0xf000;
323 sc->sc_td[i].mcnt = 0;
324 mem += BUFSIZE;
325 }
326 }
327
328 void
329 lestop(sc)
330 struct le_softc *sc;
331 {
332
333 lewrcsr(sc, 0, LE_STOP);
334 }
335
336 /*
337 * Initialization of interface; set up initialization block
338 * and transmit/receive descriptor rings.
339 */
340 void
341 leinit(sc)
342 register struct le_softc *sc;
343 {
344 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
345 int s;
346 register int timo;
347 u_long a;
348
349 /* Address not known. */
350 if (!ifp->if_addrlist)
351 return;
352
353 s = splimp();
354
355 /* Don't want to get in a weird state. */
356 lewrcsr(sc, 0, LE_STOP);
357 DELAY(100);
358
359 sc->sc_last_rd = sc->sc_last_td = sc->sc_no_td = 0;
360
361 /* Set up LANCE init block. */
362 lememinit(sc);
363
364 /* Turn on byte swapping. */
365 lewrcsr(sc, 3, LE_BSWP);
366
367 /* Give LANCE the physical address of its init block. */
368 a = LANCE_ADDR(sc, sc->sc_init);
369 lewrcsr(sc, 1, a);
370 lewrcsr(sc, 2, (a >> 16) & 0xff);
371
372 /* Try to initialize the LANCE. */
373 DELAY(100);
374 lewrcsr(sc, 0, LE_INIT);
375
376 /* Wait for initialization to finish. */
377 for (timo = 100000; timo; timo--)
378 if (lerdcsr(sc, 0) & LE_IDON)
379 break;
380
381 if (lerdcsr(sc, 0) & LE_IDON) {
382 /* Start the LANCE. */
383 lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON);
384 ifp->if_flags |= IFF_RUNNING;
385 ifp->if_flags &= ~IFF_OACTIVE;
386 lestart(ifp);
387 } else
388 printf("le%d: card failed to initialize\n", ifp->if_unit);
389
390 (void) splx(s);
391 }
392
393 /*
394 * Controller interrupt.
395 */
396 int
397 leintr(unit)
398 int unit;
399 {
400 register struct le_softc *sc = &le_softc[unit];
401 register u_short isr;
402
403 isr = lerdcsr(sc, 0);
404 #ifdef LEDEBUG
405 if (sc->sc_debug)
406 printf("le%d: leintr entering with isr=%04x\n",
407 unit, isr);
408 #endif
409 if ((isr & LE_INTR) == 0)
410 return 0;
411
412 do {
413 lewrcsr(sc, 0,
414 isr & (LE_INEA | LE_BABL | LE_MISS | LE_MERR |
415 LE_RINT | LE_TINT | LE_IDON));
416 if (isr & (LE_BABL | LE_CERR | LE_MISS | LE_MERR)) {
417 if (isr & LE_BABL) {
418 printf("le%d: BABL\n", unit);
419 sc->sc_arpcom.ac_if.if_oerrors++;
420 }
421 #if 0
422 if (isr & LE_CERR) {
423 printf("le%d: CERR\n", unit);
424 sc->sc_arpcom.ac_if.if_collisions++;
425 }
426 #endif
427 if (isr & LE_MISS) {
428 #if 0
429 printf("le%d: MISS\n", unit);
430 #endif
431 sc->sc_arpcom.ac_if.if_ierrors++;
432 }
433 if (isr & LE_MERR) {
434 printf("le%d: MERR\n", unit);
435 lereset(sc);
436 goto out;
437 }
438 }
439
440 if ((isr & LE_RXON) == 0) {
441 printf("le%d: receiver disabled\n", unit);
442 sc->sc_arpcom.ac_if.if_ierrors++;
443 lereset(sc);
444 goto out;
445 }
446 if ((isr & LE_TXON) == 0) {
447 printf("le%d: transmitter disabled\n", unit);
448 sc->sc_arpcom.ac_if.if_oerrors++;
449 lereset(sc);
450 goto out;
451 }
452
453 if (isr & LE_RINT) {
454 /* Reset watchdog timer. */
455 sc->sc_arpcom.ac_if.if_timer = 0;
456 lerint(unit);
457 }
458 if (isr & LE_TINT) {
459 /* Reset watchdog timer. */
460 sc->sc_arpcom.ac_if.if_timer = 0;
461 letint(unit);
462 }
463
464 isr = lerdcsr(sc, 0);
465 } while ((isr & LE_INTR) != 0);
466
467 #ifdef LEDEBUG
468 if (sc->sc_debug)
469 printf("le%d: leintr returning with isr=%04x\n",
470 unit, isr);
471 #endif
472
473 out:
474 return 1;
475 }
476
477 #define NEXTTDS \
478 if (++tmd == NTBUF) tmd=0, cdm=sc->sc_td; else ++cdm
479
480 /*
481 * Setup output on interface.
482 * Get another datagram to send off of the interface queue, and map it to the
483 * interface before starting the output.
484 * Called only at splimp or interrupt level.
485 */
486 int
487 lestart(ifp)
488 struct ifnet *ifp;
489 {
490 register struct le_softc *sc = &le_softc[ifp->if_unit];
491 register int tmd;
492 struct mds *cdm;
493 struct mbuf *m0, *m;
494 u_char *buffer;
495 int len;
496
497 if ((sc->sc_arpcom.ac_if.if_flags & (IFF_RUNNING | IFF_OACTIVE)) !=
498 IFF_RUNNING)
499 return;
500
501 tmd = sc->sc_last_td;
502 cdm = &sc->sc_td[tmd];
503
504 for (;;) {
505 if (sc->sc_no_td >= NTBUF) {
506 sc->sc_arpcom.ac_if.if_flags |= IFF_OACTIVE;
507 #ifdef LEDEBUG
508 if (sc->sc_debug)
509 printf("no_td = %d, last_td = %d\n", sc->sc_no_td,
510 sc->sc_last_td);
511 #endif
512 break;
513 }
514
515 #ifdef LEDEBUG
516 if (cdm->flags & LE_OWN) {
517 sc->sc_arpcom.ac_if.if_flags |= IFF_OACTIVE;
518 printf("missing buffer, no_td = %d, last_td = %d\n",
519 sc->sc_no_td, sc->sc_last_td);
520 }
521 #endif
522
523 IF_DEQUEUE(&sc->sc_arpcom.ac_if.if_snd, m);
524 if (!m)
525 break;
526
527 ++sc->sc_no_td;
528
529 /*
530 * Copy the mbuf chain into the transmit buffer.
531 */
532 buffer = sc->sc_tbuf + (BUFSIZE * sc->sc_last_td);
533 len = 0;
534 for (m0 = m; m; m = m->m_next) {
535 bcopy(mtod(m, caddr_t), buffer, m->m_len);
536 buffer += m->m_len;
537 len += m->m_len;
538 }
539
540 #ifdef LEDEBUG
541 if (len > ETHER_MAX_LEN)
542 printf("packet length %d\n", len);
543 #endif
544
545 #if NBPFILTER > 0
546 if (sc->sc_arpcom.ac_if.if_bpf)
547 bpf_mtap(sc->sc_arpcom.ac_if.if_bpf, m0);
548 #endif
549
550 m_freem(m0);
551 len = max(len, ETHER_MIN_LEN);
552
553 /*
554 * Init transmit registers, and set transmit start flag.
555 */
556 cdm->bcnt = -len;
557 cdm->mcnt = 0;
558 cdm->flags |= LE_OWN | LE_STP | LE_ENP;
559
560 #ifdef LEDEBUG
561 if (sc->sc_debug)
562 xmit_print(sc, sc->sc_last_td);
563 #endif
564
565 lewrcsr(sc, 0, LE_INEA | LE_TDMD);
566
567 NEXTTDS;
568 }
569
570 sc->sc_last_td = tmd;
571 }
572
573 void
574 letint(unit)
575 int unit;
576 {
577 register struct le_softc *sc = &le_softc[unit];
578 register int tmd = (sc->sc_last_td - sc->sc_no_td + NTBUF) % NTBUF;
579 struct mds *cdm = &sc->sc_td[tmd];
580
581 if (cdm->flags & LE_OWN) {
582 /* Race condition with loop below. */
583 #ifdef LEDEBUG
584 if (sc->sc_debug)
585 printf("le%d: extra tint\n", unit);
586 #endif
587 return;
588 }
589
590 sc->sc_arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
591
592 do {
593 if (sc->sc_no_td <= 0)
594 break;
595 #ifdef LEDEBUG
596 if (sc->sc_debug)
597 printf("trans cdm = %x\n", cdm);
598 #endif
599 sc->sc_arpcom.ac_if.if_opackets++;
600 --sc->sc_no_td;
601 if (cdm->mcnt & (LE_TBUFF | LE_UFLO | LE_LCOL | LE_LCAR | LE_RTRY)) {
602 if (cdm->mcnt & LE_TBUFF)
603 printf("le%d: TBUFF\n", unit);
604 if ((cdm->mcnt & (LE_TBUFF | LE_UFLO)) == LE_UFLO)
605 printf("le%d: UFLO\n", unit);
606 if (cdm->mcnt & LE_UFLO) {
607 lereset(sc);
608 return;
609 }
610 #if 0
611 if (cdm->mcnt & LE_LCOL) {
612 printf("le%d: late collision\n", unit);
613 sc->sc_arpcom.ac_if.if_collisions++;
614 }
615 if (cdm->mcnt & LE_LCAR)
616 printf("le%d: lost carrier\n", unit);
617 if (cdm->mcnt & LE_RTRY) {
618 printf("le%d: excessive collisions, tdr %d\n",
619 unit, cdm->mcnt & 0x1ff);
620 sc->sc_arpcom.ac_if.if_collisions += 16;
621 }
622 #endif
623 } else if (cdm->flags & LE_ONE)
624 sc->sc_arpcom.ac_if.if_collisions++;
625 else if (cdm->flags & LE_MORE)
626 /* Real number is unknown. */
627 sc->sc_arpcom.ac_if.if_collisions += 2;
628 NEXTTDS;
629 } while ((cdm->flags & LE_OWN) == 0);
630
631 lestart(&sc->sc_arpcom.ac_if);
632 }
633
634 #define NEXTRDS \
635 if (++rmd == NRBUF) rmd=0, cdm=sc->sc_rd; else ++cdm
636
637 /* only called from one place, so may as well integrate */
638 void
639 lerint(unit)
640 int unit;
641 {
642 register struct le_softc *sc = &le_softc[unit];
643 register int rmd = sc->sc_last_rd;
644 struct mds *cdm = &sc->sc_rd[rmd];
645
646 if (cdm->flags & LE_OWN) {
647 /* Race condition with loop below. */
648 #ifdef LEDEBUG
649 if (sc->sc_debug)
650 printf("le%d: extra rint\n", unit);
651 #endif
652 return;
653 }
654
655 /* Process all buffers with valid data. */
656 do {
657 if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) {
658 if ((cdm->flags & (LE_FRAM | LE_OFLO | LE_ENP)) == (LE_FRAM | LE_ENP))
659 printf("le%d: FRAM\n", unit);
660 if ((cdm->flags & (LE_OFLO | LE_ENP)) == LE_OFLO)
661 printf("le%d: OFLO\n", unit);
662 if ((cdm->flags & (LE_CRC | LE_OFLO | LE_ENP)) == (LE_CRC | LE_ENP))
663 printf("le%d: CRC\n", unit);
664 if (cdm->flags & LE_RBUFF)
665 printf("le%d: RBUFF\n", unit);
666 } else if (cdm->flags & (LE_STP | LE_ENP) != (LE_STP | LE_ENP)) {
667 do {
668 cdm->mcnt = 0;
669 cdm->flags |= LE_OWN;
670 NEXTRDS;
671 } while ((cdm->flags & (LE_OWN | LE_ERR | LE_STP | LE_ENP)) == 0);
672 sc->sc_last_rd = rmd;
673 printf("le%d: chained buffer\n", unit);
674 if ((cdm->flags & (LE_OWN | LE_ERR | LE_STP | LE_ENP)) != LE_ENP) {
675 lereset(sc);
676 return;
677 }
678 } else {
679 #ifdef LEDEBUG
680 if (sc->sc_debug)
681 recv_print(sc, sc->sc_last_rd);
682 #endif
683 leread(sc, sc->sc_rbuf + (BUFSIZE * rmd),
684 (int)cdm->mcnt);
685 sc->sc_arpcom.ac_if.if_ipackets++;
686 }
687
688 cdm->mcnt = 0;
689 cdm->flags |= LE_OWN;
690 NEXTRDS;
691 #ifdef LEDEBUG
692 if (sc->sc_debug)
693 printf("sc->sc_last_rd = %x, cdm = %x\n",
694 sc->sc_last_rd, cdm);
695 #endif
696 } while ((cdm->flags & LE_OWN) == 0);
697
698 sc->sc_last_rd = rmd;
699 }
700
701 /*
702 * Pass a packet to the higher levels.
703 */
704 void
705 leread(sc, buf, len)
706 register struct le_softc *sc;
707 u_char *buf;
708 int len;
709 {
710 struct ifnet *ifp;
711 struct mbuf *m;
712 struct ether_header *eh;
713
714 len -= 4;
715 if (len <= 0)
716 return;
717
718 /* Pull packet off interface. */
719 ifp = &sc->sc_arpcom.ac_if;
720 m = leget(buf, len, ifp);
721 if (m == 0)
722 return;
723
724 /* We assume that the header fit entirely in one mbuf. */
725 eh = mtod(m, struct ether_header *);
726
727 #if NBPFILTER > 0
728 /*
729 * Check if there's a BPF listener on this interface.
730 * If so, hand off the raw packet to BPF.
731 */
732 if (ifp->if_bpf) {
733 bpf_mtap(ifp->if_bpf, m);
734
735 /*
736 * Note that the interface cannot be in promiscuous mode if
737 * there are no BPF listeners. And if we are in promiscuous
738 * mode, we have to check if this packet is really ours.
739 */
740 if ((ifp->if_flags & IFF_PROMISC) &&
741 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
742 bcmp(eh->ether_dhost, sc->sc_arpcom.ac_enaddr,
743 sizeof(eh->ether_dhost)) != 0) {
744 m_freem(m);
745 return;
746 }
747 }
748 #endif
749
750 /* We assume that the header fit entirely in one mbuf. */
751 m->m_pkthdr.len -= sizeof(*eh);
752 m->m_len -= sizeof(*eh);
753 m->m_data += sizeof(*eh);
754
755 ether_input(ifp, eh, m);
756 }
757
758 /*
759 * Supporting routines
760 */
761
762 /*
763 * Pull data off an interface.
764 * Len is length of data, with local net header stripped.
765 * We copy the data into mbufs. When full cluster sized units are present
766 * we copy into clusters.
767 */
768 struct mbuf *
769 leget(buf, totlen, ifp)
770 u_char *buf;
771 int totlen;
772 struct ifnet *ifp;
773 {
774 struct mbuf *top, **mp, *m;
775 int len;
776
777 MGETHDR(m, M_DONTWAIT, MT_DATA);
778 if (m == 0)
779 return 0;
780 m->m_pkthdr.rcvif = ifp;
781 m->m_pkthdr.len = totlen;
782 len = MHLEN;
783 top = 0;
784 mp = ⊤
785
786 while (totlen > 0) {
787 if (top) {
788 MGET(m, M_DONTWAIT, MT_DATA);
789 if (m == 0) {
790 m_freem(top);
791 return 0;
792 }
793 len = MLEN;
794 }
795 if (totlen >= MINCLSIZE) {
796 MCLGET(m, M_DONTWAIT);
797 if (m->m_flags & M_EXT)
798 len = MCLBYTES;
799 }
800 m->m_len = len = min(totlen, len);
801 bcopy((caddr_t)buf, mtod(m, caddr_t), len);
802 buf += len;
803 totlen -= len;
804 *mp = m;
805 mp = &m->m_next;
806 }
807
808 return top;
809 }
810
811 /*
812 * Process an ioctl request.
813 */
814 int
815 leioctl(ifp, cmd, data)
816 register struct ifnet *ifp;
817 int cmd;
818 caddr_t data;
819 {
820 struct le_softc *sc = &le_softc[ifp->if_unit];
821 struct ifaddr *ifa = (struct ifaddr *)data;
822 struct ifreq *ifr = (struct ifreq *)data;
823 int s, error = 0;
824
825 s = splimp();
826
827 switch (cmd) {
828
829 case SIOCSIFADDR:
830 ifp->if_flags |= IFF_UP;
831
832 switch (ifa->ifa_addr->sa_family) {
833 #ifdef INET
834 case AF_INET:
835 leinit(sc); /* before arpwhohas */
836 /*
837 * See if another station has *our* IP address.
838 * i.e.: There is an address conflict! If a
839 * conflict exists, a message is sent to the
840 * console.
841 */
842 sc->sc_arpcom.ac_ipaddr = IA_SIN(ifa)->sin_addr;
843 arpwhohas(&sc->sc_arpcom, &IA_SIN(ifa)->sin_addr);
844 break;
845 #endif
846 #ifdef NS
847 /* XXX - This code is probably wrong. */
848 case AF_NS:
849 {
850 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
851
852 if (ns_nullhost(*ina))
853 ina->x_host =
854 *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
855 else
856 bcopy(ina->x_host.c_host,
857 sc->sc_arpcom.ac_enaddr,
858 sizeof(sc->sc_arpcom.ac_enaddr));
859 /* Set new address. */
860 leinit(sc);
861 break;
862 }
863 #endif
864 default:
865 leinit(sc);
866 break;
867 }
868 break;
869
870 case SIOCSIFFLAGS:
871 /*
872 * If interface is marked down and it is running, then stop it
873 */
874 if ((ifp->if_flags & IFF_UP) == 0 &&
875 (ifp->if_flags & IFF_RUNNING) != 0) {
876 /*
877 * If interface is marked down and it is running, then
878 * stop it.
879 */
880 lestop(sc);
881 ifp->if_flags &= ~IFF_RUNNING;
882 } else if ((ifp->if_flags & IFF_UP) != 0 &&
883 (ifp->if_flags & IFF_RUNNING) == 0) {
884 /*
885 * If interface is marked up and it is stopped, then
886 * start it.
887 */
888 leinit(sc);
889 } else {
890 /*
891 * Reset the interface to pick up changes in any other
892 * flags that affect hardware registers.
893 */
894 /*lestop(sc);*/
895 leinit(sc);
896 }
897 #ifdef LEDEBUG
898 if (ifp->if_flags & IFF_DEBUG)
899 sc->sc_debug = 1;
900 else
901 sc->sc_debug = 0;
902 #endif
903 break;
904
905 case SIOCADDMULTI:
906 case SIOCDELMULTI:
907 error = (cmd == SIOCADDMULTI) ?
908 ether_addmulti(ifr, &sc->sc_arpcom):
909 ether_delmulti(ifr, &sc->sc_arpcom);
910
911 if (error == ENETRESET) {
912 /*
913 * Multicast list has changed; set the hardware filter
914 * accordingly.
915 */
916 leinit(sc);
917 error = 0;
918 }
919 break;
920
921 default:
922 error = EINVAL;
923 }
924 (void) splx(s);
925 return error;
926 }
927
928 #ifdef LEDEBUG
929 void
930 recv_print(sc, no)
931 struct le_softc *sc;
932 int no;
933 {
934 struct mds *rmd;
935 int i, printed = 0;
936 u_short len;
937
938 rmd = &sc->sc_rd[no];
939 len = rmd->mcnt;
940 printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
941 len);
942 printf("%s: status %x\n", sc->sc_dev.dv_xname, lerdcsr(sc, 0));
943 for (i = 0; i < len; i++) {
944 if (!printed) {
945 printed = 1;
946 printf("%s: data: ", sc->sc_dev.dv_xname);
947 }
948 printf("%x ", *(sc->sc_rbuf + (BUFSIZE*no) + i));
949 }
950 if (printed)
951 printf("\n");
952 }
953
954 void
955 xmit_print(sc, no)
956 struct le_softc *sc;
957 int no;
958 {
959 struct mds *rmd;
960 int i, printed=0;
961 u_short len;
962
963 rmd = &sc->sc_td[no];
964 len = -rmd->bcnt;
965 printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
966 len);
967 printf("%s: status %x\n", sc->sc_dev.dv_xname, lerdcsr(sc, 0));
968 printf("%s: addr %x, flags %x, bcnt %x, mcnt %x\n",
969 sc->sc_dev.dv_xname, rmd->addr, rmd->flags, rmd->bcnt, rmd->mcnt);
970 for (i = 0; i < len; i++) {
971 if (!printed) {
972 printed = 1;
973 printf("%s: data: ", sc->sc_dev.dv_xname);
974 }
975 printf("%x ", *(sc->sc_tbuf + (BUFSIZE*no) + i));
976 }
977 if (printed)
978 printf("\n");
979 }
980 #endif /* LEDEBUG */
981
982 /*
983 * Set up the logical address filter.
984 */
985 void
986 lesetladrf(ac, af)
987 struct arpcom *ac;
988 u_long *af;
989 {
990 struct ifnet *ifp = &ac->ac_if;
991 struct ether_multi *enm;
992 register u_char *cp, c;
993 register u_long crc;
994 register int i, len;
995 struct ether_multistep step;
996
997 /*
998 * Set up multicast address filter by passing all multicast addresses
999 * through a crc generator, and then using the high order 6 bits as an
1000 * index into the 64 bit logical address filter. The high order bit
1001 * selects the word, while the rest of the bits select the bit within
1002 * the word.
1003 */
1004
1005 if (ifp->if_flags & IFF_PROMISC) {
1006 ifp->if_flags |= IFF_ALLMULTI;
1007 af[0] = af[1] = 0xffffffff;
1008 return;
1009 }
1010
1011 af[0] = af[1] = 0;
1012 ETHER_FIRST_MULTI(step, ac, enm);
1013 while (enm != NULL) {
1014 if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
1015 sizeof(enm->enm_addrlo)) != 0) {
1016 /*
1017 * We must listen to a range of multicast addresses.
1018 * For now, just accept all multicasts, rather than
1019 * trying to set only those filter bits needed to match
1020 * the range. (At this time, the only use of address
1021 * ranges is for IP multicast routing, for which the
1022 * range is big enough to require all bits set.)
1023 */
1024 ifp->if_flags |= IFF_ALLMULTI;
1025 af[0] = af[1] = 0xffffffff;
1026 return;
1027 }
1028
1029 cp = enm->enm_addrlo;
1030 crc = 0xffffffff;
1031 for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
1032 c = *cp++;
1033 for (i = 8; --i >= 0;) {
1034 if ((crc & 0x01) ^ (c & 0x01)) {
1035 crc >>= 1;
1036 crc ^= 0x6db88320 | 0x80000000;
1037 } else
1038 crc >>= 1;
1039 c >>= 1;
1040 }
1041 }
1042 /* Just want the 6 most significant bits. */
1043 crc >>= 26;
1044
1045 /* Turn on the corresponding bit in the filter. */
1046 af[crc >> 5] |= 1 << (crc & 0x1f);
1047
1048 ETHER_NEXT_MULTI(step, enm);
1049 }
1050 ifp->if_flags &= ~IFF_ALLMULTI;
1051 }
1052
1053 #endif /* NLE > 0 */
1054