Removed patch kit header, added $Id$
[unix-history] / sys / i386 / isa / if_we.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Tim L. Tucker.
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 includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)if_we.c 7.3 (Berkeley) 5/21/91
37 *
38 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
39 * -------------------- ----- ----------------------
40 * CURRENT PATCH LEVEL: 2 00112
41 * -------------------- ----- ----------------------
42 *
43 * 09 Sep 92 Mike Durkin Fix Danpex EW-2016 & other 8013 clones
44 * enable with "options WECOMPAT"
45 * 19 Sep 92 Michael Galassi Fixed multiboard routing
46 * 20 Sep 92 Barry Lustig WD8013 16 bit mode -- enable
47 * with "options WD8013".
48 * 14 Mar 93 Marc Frajola BPF packet filter support
49 * 14 Mar 93 David Greenman Input and other routines re-written
50 * 14 Mar 93 Rodney W. Grimes Added link level address to we_attach
51 */
52
53/*
54 * Modification history
55 *
56 * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
57 *
58 * 92.09.19 - Changes to allow multiple we interfaces in one box.
59 * Allowed interupt handler to look at unit other than 0
60 * Bdry was static, made it into an array w/ one entry per
61 * interface. nerd@percival.rain.com (Michael Galassi)
62 *
63 * BPF Packet Filter Support added by Marc Frajola, 12/30/92
64 * Input & other routines re-written by David Greenman, 1/2/93
65 * BPF trailer support added by David Greenman, 1/7/93
66 * we_attach enhanced with link level address by Rodney W. Grimes, 1/30/93
67 *
192b3b8a 68 * $Log: if_we.c,v $
4ca76e18
RG
69 * Revision 1.3 1993/08/22 22:54:56 ats
70 * Added a new-line in the output of the ethernet-address that it gets
71 * on it's line alone ( not mangled with the FPU detection ).
72 * Commented out a debug printf in if_ec.c ( printf("ecinit") ).
73 *
6b1becf0
AS
74 * Revision 1.2 1993/07/29 12:07:10 davidg
75 * Added include of systm.h to get min/max/bcmp etc...
76 *
192b3b8a
DG
77 * Revision 1.1.1.1 1993/06/12 14:58:01 rgrimes
78 * Initial import, 0.1 + pk 0.2.4-B1
79 *
15637ed4
RG
80 * Revision 1.2 93/02/18 17:21:57 davidg
81 * Bugs in mbuf cluster allocation fixed
82 * Problem with nfs wanting mbufs aligned on longword boundries fixed
83 *
84 */
85
86#include "we.h"
87#if NWE > 0
88/*
89 * Western Digital 8003 ethernet/starlan adapter
90 *
91 * Supports the following interface cards:
92 * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT
93 *
94 * The Western Digital card is one of many AT/MCA ethernet interfaces
95 * based on the National DS8390 Network Interface chip set.
96 */
97#include "param.h"
192b3b8a 98#include "systm.h"
15637ed4
RG
99#include "mbuf.h"
100#include "socket.h"
101#include "ioctl.h"
102#include "errno.h"
103#include "syslog.h"
104
105#include "net/if.h"
106#include "net/if_types.h"
107#include "net/if_dl.h"
108#include "net/netisr.h"
109
110#ifdef INET
111#include "netinet/in.h"
112#include "netinet/in_systm.h"
113#include "netinet/in_var.h"
114#include "netinet/ip.h"
115#include "netinet/if_ether.h"
116#endif
117
118#ifdef NS
119#include "netns/ns.h"
120#include "netns/ns_if.h"
121#endif
122
123#include "bpfilter.h"
124#if NBPFILTER > 0
125#include "net/bpf.h"
126#include "net/bpfdesc.h"
127#endif
128
129#include "i386/isa/isa.h"
130#include "i386/isa/if_wereg.h"
131#include "i386/isa/isa_device.h"
132#include "i386/isa/icu.h"
133#include "i386/include/pio.h"
134
135static inline char *we_ring_copy();
136
137/*
138 * This constant should really be 60 because the we adds 4 bytes of crc.
139 * However when set to 60 our packets are ignored by deunas , 3coms are
140 * okay ??????????????????????????????????????????
141 */
142#define ETHER_MIN_LEN 64
143#define ETHER_ADDR_LEN 6
144#define ETHER_HDR_SIZE 14
145
146/*
147 * Ethernet software status per interface.
148 *
149 * Each interface is referenced by a network interface structure,
150 * qe_if, which the routing code uses to locate the interface.
151 * This structure contains the output queue for the interface, its address, ...
152 */
153struct we_softc {
154 struct arpcom we_ac; /* Ethernet common part */
155#define we_if we_ac.ac_if /* network-visible interface */
156#define we_addr we_ac.ac_enaddr /* hardware Ethernet address */
157
158 u_char we_flags; /* software state */
159#define WDF_RUNNING 0x01
160#define WDF_TXBUSY 0x02
161#if NBPFILTER > 0
162#define WDF_ATTACHED 0x80
163#endif
164
165 u_char we_type; /* interface type code */
166 u_short we_vector; /* interrupt vector */
167 short we_io_ctl_addr; /* i/o bus address, control */
168 short we_io_nic_addr; /* i/o bus address, DS8390 */
169
170 caddr_t we_vmem_addr; /* card RAM virtual memory base */
171 u_long we_vmem_size; /* card RAM bytes */
172 caddr_t we_vmem_ring; /* receive ring RAM vaddress */
173 caddr_t we_vmem_end; /* receive ring RAM end */
174 caddr_t we_bpf; /* Magic Cookie for BPF */
175} we_softc[NWE];
176
177int weprobe(), weattach(), weintr(), westart();
178int weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
179
180struct isa_driver wedriver = {
181 weprobe, weattach, "we",
182};
183
184static unsigned short wemask[] =
185 { IRQ9, IRQ3, IRQ5, IRQ7, IRQ10, IRQ11, IRQ15, IRQ4 };
186
187/*
188 * Probe the WD8003 to see if its there
189 */
190weprobe(is)
191 struct isa_device *is;
192{
193 register int i;
194 register struct we_softc *sc = &we_softc[is->id_unit];
195 union we_mem_sel wem;
196 u_char sum;
197#ifdef WD8013 /* 20 Sep 92*/
198 union we_laar laar;
199
200 laar.laar_byte = 0;
201#endif /* WD8013*/
202
203 wem.ms_byte = 0; /* 20 Sep 92*/
204
205 /* reset card to force it into a known state. */
206 outb(is->id_iobase, 0x80);
207 DELAY(100);
208 outb(is->id_iobase, 0x00);
209 /* wait in the case this card is reading it's EEROM */
210 DELAY(5000);
211
212#ifdef WD8013 /* 20 Sep 92*/
213 /* allow the NIC to access the shared RAM 16 bits at a time */
214
215 laar.addr_l19 = 1;
216 laar.lan_16_en = 1;
217 laar.mem_16_en = 1;
218 outb(is->id_iobase+5, laar.laar_byte); /* Write a 0xc1 */
219#endif /* WD8013*/
220
221 /*
222 * Here we check the card ROM, if the checksum passes, and the
223 * type code and ethernet address check out, then we know we have
224 * a wd8003 card.
225 *
226 * Autoconfiguration: No warning message is printed on error.
227 */
228 for (sum = 0, i = 0; i < 8; ++i)
229 sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
230 if (sum != WD_CHECKSUM) { /* 09 Sep 92*/
231#ifdef WECOMPAT
4ca76e18
RG
232 printf( "we%d: probe: checksum failed... installing anyway\n",
233 is->id_unit);
234 printf( "we%d: Danpex EW-2016 or other 8013 clone card?\n",
235 is->id_unit);
15637ed4
RG
236#else /* !WECOMPAT*/
237 return (0);
238#endif /* !WECOMPAT*/
239 }
240 sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
241#ifdef nope
242 if ((sc->we_type & WD_REVMASK) != 2 /* WD8003E or WD8003S */
243 && (sc->we_type & WD_REVMASK) != 4 /* WD8003EBT */
244 && (sc->we_type & WD_REVMASK) != 6) /* WD8003ELB? */
245 return (0);
246#endif
247/*printf("type %x ", sc->we_type);*/
248 if (sc->we_type & WD_SOFTCONFIG) {
249 int iv = inb(is->id_iobase + 1) & 4 |
250 ((inb(is->id_iobase+4) & 0x60) >> 5);
251/*printf("iv %d ", iv);*/
252 if (wemask[iv] != is->id_irq)
253 return(0);
254 outb(is->id_iobase+4, inb(is->id_iobase+4) | 0x80);
255 }
256
257 /*
258 * Setup card RAM area and i/o addresses
259 * Kernel Virtual to segment C0000-DFFFF?????
260 */
261 sc->we_io_ctl_addr = is->id_iobase;
262 sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
263 sc->we_vector = is->id_irq;
264 sc->we_vmem_addr = (caddr_t)is->id_maddr;
265 sc->we_vmem_size = is->id_msize;
266 sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
267 sc->we_vmem_end = sc->we_vmem_addr + is->id_msize;
268
269 /*
270 * Save board ROM station address
271 */
272 for (i = 0; i < ETHER_ADDR_LEN; ++i)
273 sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
274
275 /*
276 * Mapin interface memory, setup memory select register
277 */
278 wem.ms_addr = kvtop(sc->we_vmem_addr) >> 13;
279 wem.ms_enable = 1;
280 wem.ms_reset = 0;
281 outb(sc->we_io_ctl_addr, wem.ms_byte);
282
283 /*
284 * clear interface memory, then sum to make sure its valid
285 */
286 for (i = 0; i < sc->we_vmem_size; ++i)
287 sc->we_vmem_addr[i] = 0x0;
288 for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
289 sum += sc->we_vmem_addr[i];
290 if (sum != 0x0) {
291 printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
292 return (0);
293 }
294
295 return (WD_IO_PORTS);
296}
297
298/*
299 * Interface exists: make available by filling in network interface
300 * record. System will initialize the interface when it is ready
301 * to accept packets.
302 */
303weattach(is)
304 struct isa_device *is;
305{
306 register struct we_softc *sc = &we_softc[is->id_unit];
307 register struct ifnet *ifp = &sc->we_if;
308 union we_command wecmd;
309 struct ifaddr *ifa;
310 struct sockaddr_dl *sdl;
311
312 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
313 wecmd.cs_stp = 1;
314 wecmd.cs_sta = 0;
315 wecmd.cs_ps = 0;
316 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
317 /*
318 * Initialize ifnet structure
319 */
320 ifp->if_unit = is->id_unit;
321 ifp->if_name = "we" ;
322 ifp->if_mtu = ETHERMTU;
323 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ;
324 ifp->if_init = weinit;
325 ifp->if_output = ether_output;
326 ifp->if_start = westart;
327 ifp->if_ioctl = weioctl;
328 ifp->if_reset = wereset;
329 ifp->if_watchdog = wewatchdog;
330 if_attach(ifp);
331 /* Search down the ifa address list looking for the AF_LINK type entry */
332 ifa = ifp->if_addrlist;
333 while ((ifa != 0) &&
334 (ifa->ifa_addr != 0) &&
335 (ifa->ifa_addr->sa_family != AF_LINK))
336 {
337 ifa = ifa->ifa_next;
338 }
339 /* If we find an AF_LINK type entry, we well fill in the hardware addr */
340 if ((ifa != 0) &&
341 (ifa->ifa_addr != 0))
342 {
343 /* Fill in the link level address for this interface */
344 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
345 sdl->sdl_type = IFT_ETHER;
346 sdl->sdl_alen = ETHER_ADDR_LEN;
347 sdl->sdl_slen = 0;
348 bcopy(sc->we_addr, LLADDR(sdl), ETHER_ADDR_LEN);
349 }
350
351#if NBPFILTER > 0
352 sc->we_flags &= ~WDF_ATTACHED; /* Make sure BPF attach flag clear */
353#endif
354
355 /*
356 * Banner...
357 */
4ca76e18
RG
358 printf("we%d: %s address %s\n",
359 is->id_unit,
360 (sc->we_type & WD_ETHERNET) ? "ethernet" : "starlan",
15637ed4
RG
361 ether_sprintf(sc->we_addr));
362}
363
364/*
365 * Reset of interface.
366 */
367wereset(unit, uban)
368 int unit, uban;
369{
370 if (unit >= NWE)
371 return;
372 printf("we%d: reset\n", unit);
373/* we_softc[unit].we_flags &= ~WDF_RUNNING; */
374 weinit(unit);
375}
376
377/*
378 * Take interface offline.
379 */
380westop(unit)
381 int unit;
382{
383 register struct we_softc *sc = &we_softc[unit];
384 union we_command wecmd;
385 int s;
386
387 /*
388 * Shutdown DS8390
389 */
390 s = splimp();
391 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
392 wecmd.cs_stp = 1;
393 wecmd.cs_sta = 0;
394 wecmd.cs_ps = 0;
395 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
396 (void) splx(s);
397}
398
399wewatchdog(unit) {
400
401 weintr(unit);
402 /*log(LOG_WARNING,"we%d: soft reset\n", unit);
403 westop(unit);
404 weinit(unit);*/
405}
406
407static Bdry[NWE]; /* 19 Sep 92*/
408/*
409 * Initialization of interface (really just DS8390).
410 */
411weinit(unit)
412 int unit;
413{
414 register struct we_softc *sc = &we_softc[unit];
415 register struct ifnet *ifp = &sc->we_if;
416 union we_command wecmd;
417 int i, s;
418
419#if NBPFILTER > 0
420 if ((sc->we_flags & WDF_ATTACHED) == 0) {
421 bpfattach(&sc->we_bpf, ifp, DLT_EN10MB,
422 sizeof(struct ether_header));
423 sc->we_flags |= WDF_ATTACHED;
424 }
425#endif
426
427 /* address not known */
428 if (ifp->if_addrlist == (struct ifaddr *)0)
429 return;
430
431 /* already running */
432 /*if (ifp->if_flags & IFF_RUNNING) return; */
433
434 /*
435 * Initialize DS8390 in order given in NSC NIC manual.
436 * this is stock code...please see the National manual for details.
437 */
438 s = splhigh();
439 Bdry[unit] = 0; /* 19 Sep 92*/
440 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
441 wecmd.cs_stp = 1;
442 wecmd.cs_sta = 0;
443 wecmd.cs_ps = 0;
444 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
445#ifdef WD8013 /* 20 Sep 92*/
446 /* enable 16 bit access if 8013 card */
447 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG16);
448#else /* !WD8013*/
449 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
450#endif /* !WD8013*/
451 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
452 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
453 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
454 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
455 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
456 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
457 outb(sc->we_io_nic_addr + WD_P0_PSTOP,
458 sc->we_vmem_size / WD_PAGE_SIZE);
459 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
460 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
461 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
462 wecmd.cs_ps = 1;
463 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
464 for (i = 0; i < ETHER_ADDR_LEN; ++i)
465 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
466 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */
467 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
468 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
469 wecmd.cs_ps = 0;
470 wecmd.cs_stp = 0;
471 wecmd.cs_sta = 1;
472 wecmd.cs_rd = 0x4;
473 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
474#if NBPFILTER > 0
475 if (sc->we_if.if_flags & IFF_PROMISC) {
476 outb(sc->we_io_nic_addr + WD_P0_RCR,
477 WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
478 } else
479#endif
480 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
481
482 /*
483 * Take the interface out of reset, program the vector,
484 * enable interrupts, and tell the world we are up.
485 */
486 ifp->if_flags |= IFF_RUNNING;
487 sc->we_flags &= ~WDF_TXBUSY;
488 (void) splx(s);
489 westart(ifp);
490}
491
492/*
493 * Start output on interface.
494 */
495westart(ifp)
496 struct ifnet *ifp;
497{
498 register struct we_softc *sc = &we_softc[ifp->if_unit];
499 struct mbuf *m0, *m;
500 register caddr_t buffer;
501 int len, s;
502 union we_command wecmd;
503
504 /*
505 * The DS8390 has only one transmit buffer, if it is busy we
506 * must wait until the transmit interrupt completes.
507 */
508 s = splhigh();
509
510 if (sc->we_flags & WDF_TXBUSY) {
511 (void) splx(s);
512 return;
513 }
514 IF_DEQUEUE(&sc->we_if.if_snd, m);
515 if (m == 0) {
516 (void) splx(s);
517 return;
518 }
519 sc->we_flags |= WDF_TXBUSY;
520
521 (void) splx(s);
522
523#if NBPFILTER > 0
524 if (sc->we_bpf) {
525 u_short etype;
526 int off, datasize, resid;
527 struct ether_header *eh;
528 struct trailer_header {
529 u_short ether_type;
530 u_short ether_residual;
531 } trailer_header;
532 char ether_packet[ETHERMTU+100];
533 char *ep;
534
535 ep = ether_packet;
536
537 /*
538 * We handle trailers below:
539 * Copy ether header first, then residual data,
540 * then data. Put all this in a temporary buffer
541 * 'ether_packet' and send off to bpf. Since the
542 * system has generated this packet, we assume
543 * that all of the offsets in the packet are
544 * correct; if they're not, the system will almost
545 * certainly crash in m_copydata.
546 * We make no assumptions about how the data is
547 * arranged in the mbuf chain (i.e. how much
548 * data is in each mbuf, if mbuf clusters are
549 * used, etc.), which is why we use m_copydata
550 * to get the ether header rather than assume
551 * that this is located in the first mbuf.
552 */
553 /* copy ether header */
554 m_copydata(m, 0, sizeof(struct ether_header), ep);
555 eh = (struct ether_header *) ep;
556 ep += sizeof(struct ether_header);
557 etype = ntohs(eh->ether_type);
558 if (etype >= ETHERTYPE_TRAIL &&
559 etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
560 datasize = ((etype - ETHERTYPE_TRAIL) << 9);
561 off = datasize + sizeof(struct ether_header);
562
563 /* copy trailer_header into a data structure */
564 m_copydata(m, off, sizeof(struct trailer_header),
565 &trailer_header.ether_type);
566
567 /* copy residual data */
568 m_copydata(m, off+sizeof(struct trailer_header),
569 resid = ntohs(trailer_header.ether_residual) -
570 sizeof(struct trailer_header), ep);
571 ep += resid;
572
573 /* copy data */
574 m_copydata(m, sizeof(struct ether_header), datasize, ep);
575 ep += datasize;
576
577 /* restore original ether packet type */
578 eh->ether_type = trailer_header.ether_type;
579
580 bpf_tap(sc->we_bpf, ether_packet, ep - ether_packet);
581 } else
582 bpf_mtap(sc->we_bpf, m);
583 }
584#endif
585
586 /*
587 * Copy the mbuf chain into the transmit buffer
588 */
589 buffer = sc->we_vmem_addr;
590 len = 0;
591 for (m0 = m; m != 0; m = m->m_next) {
592 bcopy(mtod(m, caddr_t), buffer, m->m_len);
593 buffer += m->m_len;
594 len += m->m_len;
595 }
596
597 m_freem(m0);
598
599 /*
600 * Init transmit length registers, and set transmit start flag.
601 */
602 s = splhigh();
603 len = MAX(len, ETHER_MIN_LEN);
604 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
605 wecmd.cs_ps = 0;
606 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
607 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
608 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
609 wecmd.cs_txp = 1;
610 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
611 sc->we_if.if_timer = 3;
612 (void) splx(s);
613}
614
615/*
616 * Ethernet interface interrupt processor
617 */
618weintr(unit)
619 int unit;
620{
621 register struct we_softc *sc = &we_softc[unit];
622 union we_command wecmd;
623 union we_interrupt weisr;
624
625
626 /* disable onboard interrupts, then get interrupt status */
627 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
628 wecmd.cs_ps = 0;
629 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
630 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
631loop:
632 outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
633
634 /* transmit error */
635 if (weisr.is_txe) {
636 /* need to read these registers to clear status */
637 sc->we_if.if_collisions +=
638 inb(sc->we_io_nic_addr + WD_P0_TBCR0);
639 ++sc->we_if.if_oerrors;
640 }
641
642 /* receiver error */
643 if (weisr.is_rxe) {
644 /* need to read these registers to clear status */
645 (void) inb(sc->we_io_nic_addr + 0xD);
646 (void) inb(sc->we_io_nic_addr + 0xE);
647 (void) inb(sc->we_io_nic_addr + 0xF);
648 ++sc->we_if.if_ierrors;
649 }
650
651 /* normal transmit complete */
652 if (weisr.is_ptx || weisr.is_txe)
653 wetint (unit);
654
655 /* normal receive notification */
656 if (weisr.is_prx || weisr.is_rxe)
657 werint (unit);
658
659 /* try to start transmit */
660 westart(&sc->we_if);
661
662 /* re-enable onboard interrupts */
663 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
664 wecmd.cs_ps = 0;
665 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
666 outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
667 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
668 if (weisr.is_byte) goto loop;
669}
670
671/*
672 * Ethernet interface transmit interrupt.
673 */
674wetint(unit)
675 int unit;
676{
677 register struct we_softc *sc = &we_softc[unit];
678
679 /*
680 * Do some statistics (assume page zero of NIC mapped in)
681 */
682 sc->we_flags &= ~WDF_TXBUSY;
683 sc->we_if.if_timer = 0;
684 ++sc->we_if.if_opackets;
685 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
686}
687
688/*
689 * Ethernet interface receiver interrupt.
690 */
691werint(unit)
692 int unit;
693{
694 register struct we_softc *sc = &we_softc[unit];
695 u_char bnry, curr;
696 long len;
697 union we_command wecmd;
698 struct we_ring *wer;
699
700 /*
701 * Traverse the receive ring looking for packets to pass back.
702 * The search is complete when we find a descriptor not in use.
703 */
704 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
705 wecmd.cs_ps = 0;
706 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
707 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
708 wecmd.cs_ps = 1;
709 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
710 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
711 if(Bdry[unit]) /* 19 Sep 92*/
712 bnry = Bdry[unit];
713
714 while (bnry != curr)
715 {
716 /* get pointer to this buffer header structure */
717 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
718
719 /* count includes CRC */
720 len = wer->we_count - 4;
721 if (len > 30 && len <= ETHERMTU+100)
722 weread(sc, (caddr_t)(wer + 1), len);
6b1becf0 723 else printf("we%d: reject - bad length %d\n", unit, len);
15637ed4
RG
724
725outofbufs:
726 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
727 wecmd.cs_ps = 0;
728 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
729
730 /* advance on chip Boundry register */
731 if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
732 bnry = WD_TXBUF_SIZE;
733 outb(sc->we_io_nic_addr + WD_P0_BNRY,
734 sc->we_vmem_size / WD_PAGE_SIZE-1);
735
736 } else {
737 if (len > 30 && len <= ETHERMTU+100)
738 bnry = wer->we_next_packet;
739 else bnry = curr;
740
741 /* watch out for NIC overflow, reset Boundry if invalid */
742 if ((bnry - 1) < WD_TXBUF_SIZE) {
743 outb(sc->we_io_nic_addr + WD_P0_BNRY,
744 (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
745 bnry = WD_TXBUF_SIZE;
746 } else
747 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
748 }
749
750 /* refresh our copy of CURR */
751 wecmd.cs_ps = 1;
752 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
753 curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
754 }
755 Bdry[unit] = bnry; /* 19 Sep 92*/
756}
757
758/*
759 * Process an ioctl request.
760 */
761weioctl(ifp, cmd, data)
762 register struct ifnet *ifp;
763 int cmd;
764 caddr_t data;
765{
766 register struct ifaddr *ifa = (struct ifaddr *)data;
767 struct we_softc *sc = &we_softc[ifp->if_unit];
768 struct ifreq *ifr = (struct ifreq *)data;
769 int s = splimp(), error = 0;
770
771
772 switch (cmd) {
773
774 case SIOCSIFADDR:
775 ifp->if_flags |= IFF_UP;
776
777 switch (ifa->ifa_addr->sa_family) {
778#ifdef INET
779 case AF_INET:
780 weinit(ifp->if_unit); /* before arpwhohas */
781 ((struct arpcom *)ifp)->ac_ipaddr =
782 IA_SIN(ifa)->sin_addr;
783 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
784 break;
785#endif
786#ifdef NS
787 case AF_NS:
788 {
789 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
790
791 if (ns_nullhost(*ina))
792 ina->x_host = *(union ns_host *)(sc->ns_addr);
793 else {
794 /*
795 * The manual says we cant change the address
796 * while the receiver is armed,
797 * so reset everything
798 */
799 ifp->if_flags &= ~IFF_RUNNING;
800 bcopy((caddr_t)ina->x_host.c_host,
801 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr));
802 }
803 weinit(ifp->if_unit); /* does ne_setaddr() */
804 break;
805 }
806#endif
807 default:
808 weinit(ifp->if_unit);
809 break;
810 }
811 break;
812
813 case SIOCSIFFLAGS:
814 if ((ifp->if_flags & IFF_UP) == 0 &&
815 ifp->if_flags & IFF_RUNNING) {
816 ifp->if_flags &= ~IFF_RUNNING;
817 westop(ifp->if_unit);
818 } else if (ifp->if_flags & IFF_UP &&
819 (ifp->if_flags & IFF_RUNNING) == 0)
820 weinit(ifp->if_unit);
821#if NBPFILTER > 0
822 if (sc->we_if.if_flags & IFF_PROMISC) {
823 outb(sc->we_io_nic_addr + WD_P0_RCR,
824 WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
825 } else
826#endif
827 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
828 break;
829
830#ifdef notdef
831 case SIOCGHWADDR:
832 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
833 sizeof(sc->sc_addr));
834 break;
835#endif
836
837 default:
838 error = EINVAL;
839 }
840 splx(s);
841 return (error);
842}
843/*
844 * set ethernet address for unit
845 */
846wesetaddr(physaddr, unit)
847 u_char *physaddr;
848 int unit;
849{
850 register struct we_softc *sc = &we_softc[unit];
851 register int i;
852
853 /*
854 * Rewrite ethernet address, and then force restart of NIC
855 */
856 for (i = 0; i < ETHER_ADDR_LEN; i++)
857 sc->we_addr[i] = physaddr[i];
858 sc->we_flags &= ~WDF_RUNNING;
859 weinit(unit);
860}
861
862#define ringoffset(sc, eh, off, type) \
863 ((type)( ((caddr_t)(eh)+(off) >= (sc)->we_vmem_end) ? \
864 (((caddr_t)(eh)+(off))) - (sc)->we_vmem_end \
865 + (sc)->we_vmem_ring: \
866 ((caddr_t)(eh)+(off)) ))
867/*
868 * Pass a packet to the higher levels.
869 * We deal with the trailer protocol here.
870 */
871weread(sc, buf, len)
872 register struct we_softc *sc;
873 char *buf;
874 int len;
875{
876 caddr_t we_ring_copy();
877 struct ether_header *eh;
878 struct mbuf *m, *head, *we_ring_to_mbuf();
879 int off, resid;
880 u_short etype;
881 struct trailer_header {
882 u_short trail_type;
883 u_short trail_residual;
884 } trailer_header;
885
886 ++sc->we_if.if_ipackets;
887
888 /* Allocate a header mbuf */
889 MGETHDR(m, M_DONTWAIT, MT_DATA);
890 if (m == 0)
891 goto bad;
892 m->m_pkthdr.rcvif = &sc->we_if;
893 m->m_pkthdr.len = len;
894 m->m_len = 0;
895 head = m;
896
897 eh = (struct ether_header *)buf;
898
899#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
900#define EOFF (EROUND - sizeof(struct ether_header))
901
902 /*
903 * The following assumes there is room for
904 * the ether header in the header mbuf
905 */
906 head->m_data += EOFF;
907 bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
908 buf += sizeof(struct ether_header);
909 head->m_len += sizeof(struct ether_header);
910 len -= sizeof(struct ether_header);
911
912 etype = ntohs((u_short)eh->ether_type);
913
914 /*
915 * Deal with trailer protocol:
916 * If trailer protocol, calculate the datasize as 'off',
917 * which is also the offset to the trailer header.
918 * Set resid to the amount of packet data following the
919 * trailer header.
920 * Finally, copy residual data into mbuf chain.
921 */
922 if (etype >= ETHERTYPE_TRAIL &&
923 etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
924
925 off = (etype - ETHERTYPE_TRAIL) << 9;
926 if ((off + sizeof(struct trailer_header)) > len)
927 goto bad; /* insanity */
928
929 eh->ether_type = *ringoffset(sc, buf, off, u_short *);
930 resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
931
932 if ((off + resid) > len) goto bad; /* insanity */
933
934 resid -= sizeof(struct trailer_header);
935 if (resid < 0) goto bad; /* insanity */
936
937 m = we_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
938 if (m == 0) goto bad;
939
940 len = off;
941 head->m_pkthdr.len -= 4; /* subtract trailer header */
942 }
943
944 /*
945 * Pull packet off interface. Or if this was a trailer packet,
946 * the data portion is appended.
947 */
948 m = we_ring_to_mbuf(sc, buf, m, len);
949 if (m == 0) goto bad;
950
951#if NBPFILTER > 0
952 /*
953 * Check if there's a bpf filter listening on this interface.
954 * If so, hand off the raw packet to bpf.
955 */
956 if (sc->we_bpf) {
957 bpf_mtap(sc->we_bpf, head);
958 }
959
960 /*
961 * Note that the interface cannot be in promiscuous mode if
962 * there are no bpf listeners. And if we are in promiscuous
963 * mode, we have to check if this packet is really ours.
964 *
965 * XXX This test does not support multicasts.
966 */
967 if ((sc->we_if.if_flags & IFF_PROMISC) &&
968 bcmp(eh->ether_dhost, sc->we_addr,
969 sizeof(eh->ether_dhost)) != 0 &&
970 bcmp(eh->ether_dhost, etherbroadcastaddr,
971 sizeof(eh->ether_dhost)) != 0) {
972
973 m_freem(head);
974 return;
975 }
976#endif
977
978 /*
979 * Fix up data start offset in mbuf to point past ether header
980 */
981 m_adj(head, sizeof(struct ether_header));
982
983 /*
984 * silly ether_input routine needs 'type' in host byte order
985 */
986 eh->ether_type = ntohs(eh->ether_type);
987
988 ether_input(&sc->we_if, eh, head);
989 return;
990
991bad: if (head)
992 m_freem(head);
993 return;
994}
995
996/*
997 * Supporting routines
998 */
999
1000/*
1001 * Copy data from receive buffer to end of mbuf chain
1002 * allocate additional mbufs as needed. return pointer
1003 * to last mbuf in chain.
1004 * sc = we info
1005 * src = pointer in we ring buffer
1006 * dst = pointer to last mbuf in mbuf chain to copy to
1007 * amount = amount of data to copy
1008 */
1009struct mbuf *
1010we_ring_to_mbuf(sc,src,dst,total_len)
1011 struct we_softc *sc;
1012 char *src;
1013 struct mbuf *dst;
1014 int total_len;
1015{
1016 register struct mbuf *m = dst;
1017
1018 while (total_len > 0) {
1019 register int amount = min(total_len, M_TRAILINGSPACE(m));
1020
1021 if (amount == 0) { /* no more data in this mbuf, alloc another */
1022 /*
1023 * if there is enough data for an mbuf cluster, attempt
1024 * to allocate one of those, otherwise, a regular mbuf
1025 * will do.
1026 */
1027 dst = m;
1028 MGET(m, M_DONTWAIT, MT_DATA);
1029 if (m == 0)
1030 return (0);
1031
1032 if (total_len >= MINCLSIZE)
1033 MCLGET(m, M_DONTWAIT);
1034
1035 m->m_len = 0;
1036 dst->m_next = m;
1037 amount = min(total_len, M_TRAILINGSPACE(m));
1038 }
1039
1040 src = we_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
1041
1042 m->m_len += amount;
1043 total_len -= amount;
1044
1045 }
1046 return (m);
1047}
1048
1049static inline char *
1050we_ring_copy(sc,src,dst,amount)
1051 struct we_softc *sc;
1052 char *src;
1053 char *dst;
1054 int amount;
1055{
1056 int tmp_amount;
1057
1058 /* does copy wrap to lower addr in ring buffer? */
1059 if (src + amount > sc->we_vmem_end) {
1060 tmp_amount = sc->we_vmem_end - src;
1061 bcopy(src,dst,tmp_amount); /* copy amount up to end */
1062 amount -= tmp_amount;
1063 src = sc->we_vmem_ring;
1064 dst += tmp_amount;
1065 }
1066
1067 bcopy(src, dst, amount);
1068
1069 return(src + amount);
1070}
1071#endif
1072