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