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