lance.c revision 1.2 1 /* $NetBSD: lance.c,v 1.2 1998/08/08 23:51:40 mycroft Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*-
41 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
44 *
45 * This code is derived from software contributed to Berkeley by
46 * Ralph Campbell and Rick Macklem.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
77 */
78
79 #include "opt_inet.h"
80 #include "opt_ccitt.h"
81 #include "opt_llc.h"
82 #include "opt_ns.h"
83 #include "bpfilter.h"
84 #include "rnd.h"
85
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/mbuf.h>
89 #include <sys/syslog.h>
90 #include <sys/socket.h>
91 #include <sys/device.h>
92 #include <sys/malloc.h>
93 #include <sys/ioctl.h>
94 #include <sys/errno.h>
95 #if NRND > 0
96 #include <sys/rnd.h>
97 #endif
98
99 #include <net/if.h>
100 #include <net/if_dl.h>
101 #include <net/if_ether.h>
102 #include <net/if_media.h>
103
104 #ifdef INET
105 #include <netinet/in.h>
106 #include <netinet/if_inarp.h>
107 #include <netinet/in_systm.h>
108 #include <netinet/in_var.h>
109 #include <netinet/ip.h>
110 #endif
111
112 #ifdef NS
113 #include <netns/ns.h>
114 #include <netns/ns_if.h>
115 #endif
116
117 #if defined(CCITT) && defined(LLC)
118 #include <sys/socketvar.h>
119 #include <netccitt/x25.h>
120 #include <netccitt/pk.h>
121 #include <netccitt/pk_var.h>
122 #include <netccitt/pk_extern.h>
123 #endif
124
125 #if NBPFILTER > 0
126 #include <net/bpf.h>
127 #include <net/bpfdesc.h>
128 #endif
129
130 #include <dev/ic/lancereg.h>
131 #include <dev/ic/lancevar.h>
132
133 #if defined(_KERNEL) && !defined(_LKM)
134 #include "opt_ddb.h"
135 #endif
136
137 #ifdef DDB
138 #define integrate
139 #define hide
140 #else
141 #define integrate static __inline
142 #define hide static
143 #endif
144
145 integrate struct mbuf *lance_get __P((struct lance_softc *, int, int));
146
147 hide void lance_shutdown __P((void *));
148
149 int lance_mediachange __P((struct ifnet *));
150 void lance_mediastatus __P((struct ifnet *, struct ifmediareq *));
151
152 static inline u_int16_t ether_cmp __P((void *, void *));
153
154 void lance_stop __P((struct lance_softc *));
155 int lance_ioctl __P((struct ifnet *, u_long, caddr_t));
156 void lance_watchdog __P((struct ifnet *));
157
158 /*
159 * Compare two Ether/802 addresses for equality, inlined and
160 * unrolled for speed. Use this like bcmp().
161 *
162 * XXX: Add <machine/inlines.h> for stuff like this?
163 * XXX: or maybe add it to libkern.h instead?
164 *
165 * "I'd love to have an inline assembler version of this."
166 * XXX: Who wanted that? mycroft? I wrote one, but this
167 * version in C is as good as hand-coded assembly. -gwr
168 *
169 * Please do NOT tweak this without looking at the actual
170 * assembly code generated before and after your tweaks!
171 */
172 static inline u_int16_t
173 ether_cmp(one, two)
174 void *one, *two;
175 {
176 register u_int16_t *a = (u_short *) one;
177 register u_int16_t *b = (u_short *) two;
178 register u_int16_t diff;
179
180 #ifdef m68k
181 /*
182 * The post-increment-pointer form produces the best
183 * machine code for m68k. This was carefully tuned
184 * so it compiles to just 8 short (2-byte) op-codes!
185 */
186 diff = *a++ - *b++;
187 diff |= *a++ - *b++;
188 diff |= *a++ - *b++;
189 #else
190 /*
191 * Most modern CPUs do better with a single expresion.
192 * Note that short-cut evaluation is NOT helpful here,
193 * because it just makes the code longer, not faster!
194 */
195 diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
196 #endif
197
198 return (diff);
199 }
200
201 #define ETHER_CMP ether_cmp
202
203 #ifdef LANCE_REVC_BUG
204 /* Make sure this is short-aligned, for ether_cmp(). */
205 static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
206 #endif
207
208 #define ifp (&sc->sc_ethercom.ec_if)
209
210 void
211 lance_config(sc)
212 struct lance_softc *sc;
213 {
214 int i;
215
216 /* Make sure the chip is stopped. */
217 lance_stop(sc);
218
219 /* Initialize ifnet structure. */
220 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
221 ifp->if_softc = sc;
222 ifp->if_start = sc->sc_start;
223 ifp->if_ioctl = lance_ioctl;
224 ifp->if_watchdog = lance_watchdog;
225 ifp->if_flags =
226 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
227 #ifdef LANCE_REVC_BUG
228 ifp->if_flags &= ~IFF_MULTICAST;
229 #endif
230
231 /* Initialize ifmedia structures. */
232 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
233 if (sc->sc_supmedia != NULL) {
234 for (i = 0; i < sc->sc_nsupmedia; i++)
235 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
236 0, NULL);
237 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
238 } else {
239 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
240 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
241 }
242
243 /* Attach the interface. */
244 if_attach(ifp);
245 ether_ifattach(ifp, sc->sc_enaddr);
246
247 #if NBPFILTER > 0
248 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
249 #endif
250
251 switch (sc->sc_memsize) {
252 case 8192:
253 sc->sc_nrbuf = 4;
254 sc->sc_ntbuf = 1;
255 break;
256 case 16384:
257 sc->sc_nrbuf = 8;
258 sc->sc_ntbuf = 2;
259 break;
260 case 32768:
261 sc->sc_nrbuf = 16;
262 sc->sc_ntbuf = 4;
263 break;
264 case 65536:
265 sc->sc_nrbuf = 32;
266 sc->sc_ntbuf = 8;
267 break;
268 case 131072:
269 sc->sc_nrbuf = 64;
270 sc->sc_ntbuf = 16;
271 break;
272 default:
273 panic("lance_config: weird memory size");
274 }
275
276 printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
277 printf("%s: %d receive buffers, %d transmit buffers\n",
278 sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
279
280 sc->sc_sh = shutdownhook_establish(lance_shutdown, sc);
281 if (sc->sc_sh == NULL)
282 panic("lance_config: can't establish shutdownhook");
283 sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
284 M_WAITOK);
285 sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
286 M_WAITOK);
287
288 #if NRND > 0
289 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
290 RND_TYPE_NET);
291 #endif
292 }
293
294 void
295 lance_reset(sc)
296 struct lance_softc *sc;
297 {
298 int s;
299
300 s = splnet();
301 lance_init(sc);
302 splx(s);
303 }
304
305 void
306 lance_stop(sc)
307 struct lance_softc *sc;
308 {
309
310 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
311 }
312
313 /*
314 * Initialization of interface; set up initialization block
315 * and transmit/receive descriptor rings.
316 */
317 void
318 lance_init(sc)
319 register struct lance_softc *sc;
320 {
321 register int timo;
322 u_long a;
323
324 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
325 DELAY(100);
326
327 /* Newer LANCE chips have a reset register */
328 if (sc->sc_hwreset)
329 (*sc->sc_hwreset)(sc);
330
331 /* Set the correct byte swapping mode, etc. */
332 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
333
334 /* Set up LANCE init block. */
335 (*sc->sc_meminit)(sc);
336
337 /* Give LANCE the physical address of its init block. */
338 a = sc->sc_addr + LE_INITADDR(sc);
339 (*sc->sc_wrcsr)(sc, LE_CSR1, a);
340 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
341
342 /* Try to initialize the LANCE. */
343 DELAY(100);
344 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
345
346 /* Wait for initialization to finish. */
347 for (timo = 100000; timo; timo--)
348 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
349 break;
350
351 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
352 /* Start the LANCE. */
353 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
354 LE_C0_IDON);
355 ifp->if_flags |= IFF_RUNNING;
356 ifp->if_flags &= ~IFF_OACTIVE;
357 ifp->if_timer = 0;
358 (*sc->sc_start)(ifp);
359 } else
360 printf("%s: controller failed to initialize\n",
361 sc->sc_dev.dv_xname);
362 if (sc->sc_hwinit)
363 (*sc->sc_hwinit)(sc);
364 }
365
366 /*
367 * Routine to copy from mbuf chain to transmit buffer in
368 * network buffer memory.
369 */
370 int
371 lance_put(sc, boff, m)
372 struct lance_softc *sc;
373 int boff;
374 register struct mbuf *m;
375 {
376 register struct mbuf *n;
377 register int len, tlen = 0;
378
379 for (; m; m = n) {
380 len = m->m_len;
381 if (len == 0) {
382 MFREE(m, n);
383 continue;
384 }
385 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
386 boff += len;
387 tlen += len;
388 MFREE(m, n);
389 }
390 if (tlen < LEMINSIZE) {
391 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
392 tlen = LEMINSIZE;
393 }
394 return (tlen);
395 }
396
397 /*
398 * Pull data off an interface.
399 * Len is length of data, with local net header stripped.
400 * We copy the data into mbufs. When full cluster sized units are present
401 * we copy into clusters.
402 */
403 integrate struct mbuf *
404 lance_get(sc, boff, totlen)
405 struct lance_softc *sc;
406 int boff, totlen;
407 {
408 register struct mbuf *m;
409 struct mbuf *top, **mp;
410 int len;
411
412 MGETHDR(m, M_DONTWAIT, MT_DATA);
413 if (m == 0)
414 return (0);
415 m->m_pkthdr.rcvif = ifp;
416 m->m_pkthdr.len = totlen;
417 len = MHLEN;
418 top = 0;
419 mp = ⊤
420
421 while (totlen > 0) {
422 if (top) {
423 MGET(m, M_DONTWAIT, MT_DATA);
424 if (m == 0) {
425 m_freem(top);
426 return 0;
427 }
428 len = MLEN;
429 }
430 if (totlen >= MINCLSIZE) {
431 MCLGET(m, M_DONTWAIT);
432 if ((m->m_flags & M_EXT) == 0) {
433 m_free(m);
434 m_freem(top);
435 return 0;
436 }
437 len = MCLBYTES;
438 }
439 if (!top) {
440 register int pad =
441 ALIGN(sizeof(struct ether_header)) -
442 sizeof(struct ether_header);
443 m->m_data += pad;
444 len -= pad;
445 }
446 m->m_len = len = min(totlen, len);
447 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
448 boff += len;
449 totlen -= len;
450 *mp = m;
451 mp = &m->m_next;
452 }
453
454 return (top);
455 }
456
457 /*
458 * Pass a packet to the higher levels.
459 */
460 void
461 lance_read(sc, boff, len)
462 register struct lance_softc *sc;
463 int boff, len;
464 {
465 struct mbuf *m;
466 struct ether_header *eh;
467
468 if (len <= sizeof(struct ether_header) ||
469 len > ETHERMTU + sizeof(struct ether_header)) {
470 #ifdef LEDEBUG
471 printf("%s: invalid packet size %d; dropping\n",
472 sc->sc_dev.dv_xname, len);
473 #endif
474 ifp->if_ierrors++;
475 return;
476 }
477
478 /* Pull packet off interface. */
479 m = lance_get(sc, boff, len);
480 if (m == 0) {
481 ifp->if_ierrors++;
482 return;
483 }
484
485 ifp->if_ipackets++;
486
487 /* We assume that the header fit entirely in one mbuf. */
488 eh = mtod(m, struct ether_header *);
489
490 #if NBPFILTER > 0
491 /*
492 * Check if there's a BPF listener on this interface.
493 * If so, hand off the raw packet to BPF.
494 */
495 if (ifp->if_bpf) {
496 bpf_mtap(ifp->if_bpf, m);
497
498 #ifndef LANCE_REVC_BUG
499 /*
500 * Note that the interface cannot be in promiscuous mode if
501 * there are no BPF listeners. And if we are in promiscuous
502 * mode, we have to check if this packet is really ours.
503 */
504 if ((ifp->if_flags & IFF_PROMISC) != 0 &&
505 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
506 ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
507 m_freem(m);
508 return;
509 }
510 #endif
511 }
512 #endif
513
514 #ifdef LANCE_REVC_BUG
515 /*
516 * The old LANCE (Rev. C) chips have a bug which causes
517 * garbage to be inserted in front of the received packet.
518 * The work-around is to ignore packets with an invalid
519 * destination address (garbage will usually not match).
520 * Of course, this precludes multicast support...
521 */
522 if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
523 ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
524 m_freem(m);
525 return;
526 }
527 #endif
528
529 /* Pass the packet up, with the ether header sort-of removed. */
530 m_adj(m, sizeof(struct ether_header));
531 ether_input(ifp, eh, m);
532 }
533
534 #undef ifp
535
536 void
537 lance_watchdog(ifp)
538 struct ifnet *ifp;
539 {
540 struct lance_softc *sc = ifp->if_softc;
541
542 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
543 ++ifp->if_oerrors;
544
545 lance_reset(sc);
546 }
547
548 int
549 lance_mediachange(ifp)
550 struct ifnet *ifp;
551 {
552 struct lance_softc *sc = ifp->if_softc;
553
554 if (sc->sc_mediachange)
555 return ((*sc->sc_mediachange)(sc));
556 return (EINVAL);
557 }
558
559 void
560 lance_mediastatus(ifp, ifmr)
561 struct ifnet *ifp;
562 struct ifmediareq *ifmr;
563 {
564 struct lance_softc *sc = ifp->if_softc;
565
566 if ((ifp->if_flags & IFF_UP) == 0)
567 return;
568
569 ifmr->ifm_status = IFM_AVALID;
570 if (sc->sc_havecarrier)
571 ifmr->ifm_status |= IFM_ACTIVE;
572
573 if (sc->sc_mediastatus)
574 (*sc->sc_mediastatus)(sc, ifmr);
575 }
576
577 /*
578 * Process an ioctl request.
579 */
580 int
581 lance_ioctl(ifp, cmd, data)
582 register struct ifnet *ifp;
583 u_long cmd;
584 caddr_t data;
585 {
586 register struct lance_softc *sc = ifp->if_softc;
587 struct ifaddr *ifa = (struct ifaddr *)data;
588 struct ifreq *ifr = (struct ifreq *)data;
589 int s, error = 0;
590
591 s = splnet();
592
593 switch (cmd) {
594
595 case SIOCSIFADDR:
596 ifp->if_flags |= IFF_UP;
597
598 switch (ifa->ifa_addr->sa_family) {
599 #ifdef INET
600 case AF_INET:
601 lance_init(sc);
602 arp_ifinit(ifp, ifa);
603 break;
604 #endif
605 #ifdef NS
606 case AF_NS:
607 {
608 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
609
610 if (ns_nullhost(*ina))
611 ina->x_host =
612 *(union ns_host *)LLADDR(ifp->if_sadl);
613 else {
614 bcopy(ina->x_host.c_host,
615 LLADDR(ifp->if_sadl),
616 sizeof(sc->sc_enaddr));
617 }
618 /* Set new address. */
619 lance_init(sc);
620 break;
621 }
622 #endif
623 default:
624 lance_init(sc);
625 break;
626 }
627 break;
628
629 #if defined(CCITT) && defined(LLC)
630 case SIOCSIFCONF_X25:
631 ifp->if_flags |= IFF_UP;
632 ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
633 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
634 if (error == 0)
635 lance_init(sc);
636 break;
637 #endif /* CCITT && LLC */
638
639 case SIOCSIFFLAGS:
640 if ((ifp->if_flags & IFF_UP) == 0 &&
641 (ifp->if_flags & IFF_RUNNING) != 0) {
642 /*
643 * If interface is marked down and it is running, then
644 * stop it.
645 */
646 lance_stop(sc);
647 ifp->if_flags &= ~IFF_RUNNING;
648 } else if ((ifp->if_flags & IFF_UP) != 0 &&
649 (ifp->if_flags & IFF_RUNNING) == 0) {
650 /*
651 * If interface is marked up and it is stopped, then
652 * start it.
653 */
654 lance_init(sc);
655 } else {
656 /*
657 * Reset the interface to pick up changes in any other
658 * flags that affect hardware registers.
659 */
660 /*lance_stop(sc);*/
661 lance_init(sc);
662 }
663 #ifdef LEDEBUG
664 if (ifp->if_flags & IFF_DEBUG)
665 sc->sc_debug = 1;
666 else
667 sc->sc_debug = 0;
668 #endif
669 break;
670
671 case SIOCADDMULTI:
672 case SIOCDELMULTI:
673 error = (cmd == SIOCADDMULTI) ?
674 ether_addmulti(ifr, &sc->sc_ethercom) :
675 ether_delmulti(ifr, &sc->sc_ethercom);
676
677 if (error == ENETRESET) {
678 /*
679 * Multicast list has changed; set the hardware filter
680 * accordingly.
681 */
682 lance_reset(sc);
683 error = 0;
684 }
685 break;
686
687 case SIOCGIFMEDIA:
688 case SIOCSIFMEDIA:
689 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
690 break;
691
692 default:
693 error = EINVAL;
694 break;
695 }
696
697 splx(s);
698 return (error);
699 }
700
701 hide void
702 lance_shutdown(arg)
703 void *arg;
704 {
705
706 lance_stop((struct lance_softc *)arg);
707 }
708
709 /*
710 * Set up the logical address filter.
711 */
712 void
713 lance_setladrf(ac, af)
714 struct ethercom *ac;
715 u_int16_t *af;
716 {
717 struct ifnet *ifp = &ac->ec_if;
718 struct ether_multi *enm;
719 register u_char *cp;
720 register u_int32_t crc;
721 static const u_int32_t crctab[] = {
722 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
723 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
724 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
725 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
726 };
727 register int len;
728 struct ether_multistep step;
729
730 /*
731 * Set up multicast address filter by passing all multicast addresses
732 * through a crc generator, and then using the high order 6 bits as an
733 * index into the 64 bit logical address filter. The high order bit
734 * selects the word, while the rest of the bits select the bit within
735 * the word.
736 */
737
738 if (ifp->if_flags & IFF_PROMISC)
739 goto allmulti;
740
741 af[0] = af[1] = af[2] = af[3] = 0x0000;
742 ETHER_FIRST_MULTI(step, ac, enm);
743 while (enm != NULL) {
744 if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
745 /*
746 * We must listen to a range of multicast addresses.
747 * For now, just accept all multicasts, rather than
748 * trying to set only those filter bits needed to match
749 * the range. (At this time, the only use of address
750 * ranges is for IP multicast routing, for which the
751 * range is big enough to require all bits set.)
752 */
753 goto allmulti;
754 }
755
756 cp = enm->enm_addrlo;
757 crc = 0xffffffff;
758 for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
759 crc ^= *cp++;
760 crc = (crc >> 4) ^ crctab[crc & 0xf];
761 crc = (crc >> 4) ^ crctab[crc & 0xf];
762 }
763 /* Just want the 6 most significant bits. */
764 crc >>= 26;
765
766 /* Set the corresponding bit in the filter. */
767 af[crc >> 4] |= 1 << (crc & 0xf);
768
769 ETHER_NEXT_MULTI(step, enm);
770 }
771 ifp->if_flags &= ~IFF_ALLMULTI;
772 return;
773
774 allmulti:
775 ifp->if_flags |= IFF_ALLMULTI;
776 af[0] = af[1] = af[2] = af[3] = 0xffff;
777 }
778
779 /*
780 * Routines for accessing the transmit and receive buffers.
781 * The various CPU and adapter configurations supported by this
782 * driver require three different access methods for buffers
783 * and descriptors:
784 * (1) contig (contiguous data; no padding),
785 * (2) gap2 (two bytes of data followed by two bytes of padding),
786 * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
787 */
788
789 /*
790 * contig: contiguous data with no padding.
791 *
792 * Buffers may have any alignment.
793 */
794
795 void
796 lance_copytobuf_contig(sc, from, boff, len)
797 struct lance_softc *sc;
798 void *from;
799 int boff, len;
800 {
801 volatile caddr_t buf = sc->sc_mem;
802
803 /*
804 * Just call bcopy() to do the work.
805 */
806 bcopy(from, buf + boff, len);
807 }
808
809 void
810 lance_copyfrombuf_contig(sc, to, boff, len)
811 struct lance_softc *sc;
812 void *to;
813 int boff, len;
814 {
815 volatile caddr_t buf = sc->sc_mem;
816
817 /*
818 * Just call bcopy() to do the work.
819 */
820 bcopy(buf + boff, to, len);
821 }
822
823 void
824 lance_zerobuf_contig(sc, boff, len)
825 struct lance_softc *sc;
826 int boff, len;
827 {
828 volatile caddr_t buf = sc->sc_mem;
829
830 /*
831 * Just let bzero() do the work
832 */
833 bzero(buf + boff, len);
834 }
835
836 #if 0
837 /*
838 * Examples only; duplicate these and tweak (if necessary) in
839 * machine-specific front-ends.
840 */
841
842 /*
843 * gap2: two bytes of data followed by two bytes of pad.
844 *
845 * Buffers must be 4-byte aligned. The code doesn't worry about
846 * doing an extra byte.
847 */
848
849 void
850 lance_copytobuf_gap2(sc, fromv, boff, len)
851 struct lance_softc *sc;
852 void *fromv;
853 int boff;
854 register int len;
855 {
856 volatile caddr_t buf = sc->sc_mem;
857 register caddr_t from = fromv;
858 register volatile u_int16_t *bptr;
859
860 if (boff & 0x1) {
861 /* handle unaligned first byte */
862 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
863 *bptr = (*from++ << 8) | (*bptr & 0xff);
864 bptr += 2;
865 len--;
866 } else
867 bptr = ((volatile u_int16_t *)buf) + boff;
868 while (len > 1) {
869 *bptr = (from[1] << 8) | (from[0] & 0xff);
870 bptr += 2;
871 from += 2;
872 len -= 2;
873 }
874 if (len == 1)
875 *bptr = (u_int16_t)*from;
876 }
877
878 void
879 lance_copyfrombuf_gap2(sc, tov, boff, len)
880 struct lance_softc *sc;
881 void *tov;
882 int boff, len;
883 {
884 volatile caddr_t buf = sc->sc_mem;
885 register caddr_t to = tov;
886 register volatile u_int16_t *bptr;
887 register u_int16_t tmp;
888
889 if (boff & 0x1) {
890 /* handle unaligned first byte */
891 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
892 *to++ = (*bptr >> 8) & 0xff;
893 bptr += 2;
894 len--;
895 } else
896 bptr = ((volatile u_int16_t *)buf) + boff;
897 while (len > 1) {
898 tmp = *bptr;
899 *to++ = tmp & 0xff;
900 *to++ = (tmp >> 8) & 0xff;
901 bptr += 2;
902 len -= 2;
903 }
904 if (len == 1)
905 *to = *bptr & 0xff;
906 }
907
908 void
909 lance_zerobuf_gap2(sc, boff, len)
910 struct lance_softc *sc;
911 int boff, len;
912 {
913 volatile caddr_t buf = sc->sc_mem;
914 register volatile u_int16_t *bptr;
915
916 if ((unsigned)boff & 0x1) {
917 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
918 *bptr &= 0xff;
919 bptr += 2;
920 len--;
921 } else
922 bptr = ((volatile u_int16_t *)buf) + boff;
923 while (len > 0) {
924 *bptr = 0;
925 bptr += 2;
926 len -= 2;
927 }
928 }
929
930 /*
931 * gap16: 16 bytes of data followed by 16 bytes of pad.
932 *
933 * Buffers must be 32-byte aligned.
934 */
935
936 void
937 lance_copytobuf_gap16(sc, fromv, boff, len)
938 struct lance_softc *sc;
939 void *fromv;
940 int boff;
941 register int len;
942 {
943 volatile caddr_t buf = sc->sc_mem;
944 register caddr_t from = fromv;
945 register caddr_t bptr;
946 register int xfer;
947
948 bptr = buf + ((boff << 1) & ~0x1f);
949 boff &= 0xf;
950 xfer = min(len, 16 - boff);
951 while (len > 0) {
952 bcopy(from, bptr + boff, xfer);
953 from += xfer;
954 bptr += 32;
955 boff = 0;
956 len -= xfer;
957 xfer = min(len, 16);
958 }
959 }
960
961 void
962 lance_copyfrombuf_gap16(sc, tov, boff, len)
963 struct lance_softc *sc;
964 void *tov;
965 int boff, len;
966 {
967 volatile caddr_t buf = sc->sc_mem;
968 register caddr_t to = tov;
969 register caddr_t bptr;
970 register int xfer;
971
972 bptr = buf + ((boff << 1) & ~0x1f);
973 boff &= 0xf;
974 xfer = min(len, 16 - boff);
975 while (len > 0) {
976 bcopy(bptr + boff, to, xfer);
977 to += xfer;
978 bptr += 32;
979 boff = 0;
980 len -= xfer;
981 xfer = min(len, 16);
982 }
983 }
984
985 void
986 lance_zerobuf_gap16(sc, boff, len)
987 struct lance_softc *sc;
988 int boff, len;
989 {
990 volatile caddr_t buf = sc->sc_mem;
991 register caddr_t bptr;
992 register int xfer;
993
994 bptr = buf + ((boff << 1) & ~0x1f);
995 boff &= 0xf;
996 xfer = min(len, 16 - boff);
997 while (len > 0) {
998 bzero(bptr + boff, xfer);
999 bptr += 32;
1000 boff = 0;
1001 len -= xfer;
1002 xfer = min(len, 16);
1003 }
1004 }
1005 #endif /* Example only */
1006