Fixed MAN8 to be .8 file, people bringing stuff in from NetBSD pease be very
[unix-history] / sys / i386 / isa / if_ne.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1990, 1991 William F. Jolitz.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)if_ne.c 7.4 (Berkeley) 5/21/91
35 */
36
37/*
b794bfc8 38 * NE2000/NE1000 Ethernet driver
15637ed4
RG
39 *
40 * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
41 * insight on the ne2000 gained from Robert Clements PC/FTP driver.
b794bfc8
JH
42 *
43 * Corrected for NE1000 by Andrew A. Chernov
15637ed4
RG
44 */
45
46#include "ne.h"
47#if NNE > 0
48
49#include "param.h"
50#include "systm.h"
51#include "mbuf.h"
52#include "buf.h"
53#include "protosw.h"
54#include "socket.h"
55#include "ioctl.h"
56#include "errno.h"
57#include "syslog.h"
58
59#include "net/if.h"
60#include "net/netisr.h"
61#include "net/route.h"
62
63#ifdef INET
64#include "netinet/in.h"
65#include "netinet/in_systm.h"
66#include "netinet/in_var.h"
67#include "netinet/ip.h"
68#include "netinet/if_ether.h"
69#endif
70
71#ifdef NS
72#include "netns/ns.h"
73#include "netns/ns_if.h"
74#endif
75
76#include "i386/isa/isa_device.h"
77#include "i386/isa/if_nereg.h"
78#include "i386/isa/icu.h"
79
80int neprobe(), neattach(), neintr();
81int nestart(),neinit(), ether_output(), neioctl();
82
83struct isa_driver nedriver = {
84 neprobe, neattach, "ne",
85};
86
87struct mbuf *neget();
88
89#define ETHER_MIN_LEN 64
90#define ETHER_MAX_LEN 1536
91
92/*
93 * Ethernet software status per interface.
94 *
95 * Each interface is referenced by a network interface structure,
d3a11a24 96 * arpcom.ac_if, which the routing code uses to locate the interface.
15637ed4
RG
97 * This structure contains the output queue for the interface, its address, ...
98 */
99struct ne_softc {
d3a11a24 100 struct arpcom arpcom; /* Ethernet common part */
15637ed4
RG
101 int ns_flags;
102#define DSF_LOCK 1 /* block re-entering enstart */
103 int ns_oactive ;
104 int ns_mask ;
105 int ns_ba; /* byte addr in buffer ram of inc pkt */
106 int ns_cur; /* current page being filled */
107 struct prhdr ns_ph; /* hardware header of incoming packet*/
108 struct ether_header ns_eh; /* header of incoming packet */
109 u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
110 short ns_txstart; /* transmitter buffer start */
b794bfc8 111 u_short ns_rxend; /* recevier buffer end */
15637ed4
RG
112 short ns_port; /* i/o port base */
113 short ns_mode; /* word/byte mode */
114} ne_softc[NNE] ;
115#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
116
117#define PAT(n) (0xa55a + 37*(n))
118
119u_short boarddata[16];
120
121neprobe(dvp)
122 struct isa_device *dvp;
123{
124 int val, i, s, sum, bytemode = 1, pat;
125 register struct ne_softc *ns = &ne_softc[0];
126 register nec;
127
128#ifdef lint
129 neintr(0);
130#endif
131
132 nec = ns->ns_port = dvp->id_iobase;
133 s = splimp();
134
135 if (bytemode) {
136 /* Byte Transfers, Burst Mode Select, Fifo at 8 bytes */
137 ns->ns_mode = DSDC_BMS|DSDC_FT1;
138 ns->ns_txstart = TBUF8;
139 ns->ns_rxend = RBUFEND8;
140 } else {
141word:
142 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
143 ns->ns_mode = DSDC_WTS|DSDC_BMS|DSDC_FT1;
144 ns->ns_txstart = TBUF16;
145 ns->ns_rxend = RBUFEND16;
146 bytemode = 0;
147 }
148
149 /* Reset the bastard */
150 val = inb(nec + ne_reset);
151 DELAY(200);
152 outb(nec + ne_reset, val);
153 DELAY(200);
154
155 outb(nec + ds_cmd, DSCM_STOP|DSCM_NODMA);
156
157 i = 10000;
158 while ((inb(nec + ds0_isr) & DSIS_RESET) == 0 && i-- > 0);
159 if (i < 0) return (0);
160
161 outb(nec + ds0_isr, 0xff);
162 outb(nec + ds0_dcr, ns->ns_mode);
163 outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
164 DELAY(1000);
165
166 /* Check cmd reg and fail if not right */
167 if ((i = inb(nec + ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
168 return(0);
169
170 outb(nec + ds0_tcr, 0);
171 outb(nec + ds0_rcr, DSRC_MON);
172 outb(nec + ds0_pstart, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
173 outb(nec + ds0_pstop, ns->ns_rxend/DS_PGSIZE);
174 outb(nec + ds0_bnry, ns->ns_rxend/DS_PGSIZE);
175 outb(nec + ds0_imr, 0);
176 outb(nec + ds0_isr, 0);
177 outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
178 outb(nec + ds1_curr, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
179 outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
180
181
182#ifdef NEDEBUG
183#define RCON 37
184 { int i, rom;
185
186 rom=1;
187 printf("ne ram ");
188
189 for (i = 0; i < 0xfff0; i+=4) {
190 pat = PAT(i);
191 neput(ns, &pat,i,4);
192 nefetch(ns, &pat,i,4);
193 if (pat == PAT(i)) {
194 if (rom) {
195 rom=0;
196 printf(" %x", i);
197 }
198 } else {
199 if (!rom) {
200 rom=1;
201 printf("..%x ", i);
202 }
203 }
204 pat=0;
205 neput(ns, &pat,i,4);
206 }
207 printf("\n");
208 }
209#endif
210
211 /*
212 * <groan> detect difference between units
213 * solely by where the RAM is decoded.
214 */
215 pat = PAT(0);
216 neput(ns, &pat, ns->ns_txstart, 4);
217 nefetch(ns, &pat, ns->ns_txstart, 4);
218 if (pat != PAT(0)) {
219 if (bytemode)
220 goto word;
221 else return (0);
222 }
223
224
225 /* Extract board address */
226 nefetch (ns, (caddr_t)boarddata, 0, sizeof(boarddata));
227
228 for(i=0; i < 6; i++)
d3a11a24 229 ns->arpcom.ac_enaddr[i] = boarddata[i];
15637ed4
RG
230 splx(s);
231 return (1);
232}
233
234/*
235 * Fetch from onboard ROM/RAM
236 */
237nefetch (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
238 u_char cmd;
239 register nec = ns->ns_port;
240 int counter = 100000;
241
242 cmd = inb (nec + ds_cmd);
243 outb (nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
244
245 /* Setup remote dma */
246 outb (nec + ds0_isr, DSIS_RDC);
247
248 if ((ns->ns_mode & DSDC_WTS) && len&1)
249 len++; /* roundup to words */
250
251 outb (nec+ds0_rbcr0, len);
252 outb (nec+ds0_rbcr1, len>>8);
253 outb (nec+ds0_rsar0, ad);
254 outb (nec+ds0_rsar1, ad>>8);
255
256 /* Execute & extract from card */
257 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
258
259 if (ns->ns_mode & DSDC_WTS)
260 insw (nec+ne_data, up, len/2);
261 else
262 insb (nec+ne_data, up, len);
263
264 /* Wait till done, then shutdown feature */
265 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
266 ;
267 outb (nec+ds0_isr, DSIS_RDC);
268 outb (nec+ds_cmd, cmd);
269}
270
271/*
272 * Put to onboard RAM
273 */
274neput (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
275 u_char cmd;
276 register nec = ns->ns_port;
277 int counter = 100000;
278
279 cmd = inb(nec+ds_cmd);
280 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
281
282 /* Setup for remote dma */
283 outb (nec+ds0_isr, DSIS_RDC);
284
285 if ((ns->ns_mode & DSDC_WTS) && len&1)
286 len++; /* roundup to words */
287
288 outb (nec+ds0_rbcr0, len);
289 outb (nec+ds0_rbcr1, len>>8);
290 outb (nec+ds0_rsar0, ad);
291 outb (nec+ds0_rsar1, ad>>8);
292
293 /* Execute & stuff to card */
294 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
295 if (ns->ns_mode & DSDC_WTS)
296 outsw (nec+ne_data, up, len/2);
297 else
298 outsb (nec+ne_data, up, len);
299
300 /* Wait till done, then shutdown feature */
301 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
302 ;
303 outb (nec+ds0_isr, DSIS_RDC);
304 outb (nec+ds_cmd, cmd);
305}
306
307/*
308 * Reset of interface.
309 */
310nereset(unit, uban)
311 int unit, uban;
312{
313 if (unit >= NNE)
314 return;
315 printf("ne%d: reset\n", unit);
316 ne_softc[unit].ns_flags &= ~DSF_LOCK;
317 neinit(unit);
318}
319
320/*
321 * Interface exists: make available by filling in network interface
322 * record. System will initialize the interface when it is ready
323 * to accept packets. We get the ethernet address here.
324 */
325neattach(dvp)
326 struct isa_device *dvp;
327{
328 int unit = dvp->id_unit;
329 register struct ne_softc *ns = &ne_softc[unit];
d3a11a24 330 register struct ifnet *ifp = &ns->arpcom.ac_if;
15637ed4
RG
331
332 ifp->if_unit = unit;
333 ifp->if_name = nedriver.name ;
334 ifp->if_mtu = ETHERMTU;
d3a11a24
RG
335 printf ("ne%d: address %s, type NE%s\n",
336 unit,
337 ether_sprintf(ns->arpcom.ac_enaddr),
338 (ns->ns_mode &DSDC_WTS) ? "2000" : "1000");
15637ed4
RG
339 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
340 ifp->if_init = neinit;
341 ifp->if_output = ether_output;
342 ifp->if_start = nestart;
343 ifp->if_ioctl = neioctl;
344 ifp->if_reset = nereset;
345 ifp->if_watchdog = 0;
346 if_attach(ifp);
347}
348
349/*
350 * Initialization of interface; set up initialization block
351 * and transmit/receive descriptor rings.
352 */
353neinit(unit)
354 int unit;
355{
356 register struct ne_softc *ns = &ne_softc[unit];
d3a11a24 357 struct ifnet *ifp = &ns->arpcom.ac_if;
15637ed4
RG
358 int s;
359 int i; char *cp;
360 register nec = ns->ns_port;
361
362 if (ifp->if_addrlist == (struct ifaddr *)0) return;
363 if (ifp->if_flags & IFF_RUNNING) return;
364
365 s = splimp();
366
367 /* set physical address on ethernet */
368 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
d3a11a24 369 for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->arpcom.ac_enaddr[i]);
15637ed4
RG
370
371 /* clr logical address hash filter for now */
372 for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
373
374 /* init regs */
375 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
376 outb (nec+ds0_rbcr0, 0);
377 outb (nec+ds0_rbcr1, 0);
378 outb (nec+ds0_imr, 0);
379 outb (nec+ds0_isr, 0xff);
380
381 /* Word Transfer select, Burst Mode Select, Fifo at 8 bytes */
382 outb(nec+ds0_dcr, ns->ns_mode);
383
384 outb(nec+ds0_tcr, 0);
385 outb (nec+ds0_rcr, DSRC_MON);
386 outb (nec+ds0_tpsr, 0);
387 outb(nec+ds0_pstart, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
388 outb(nec+ds0_pstop, ns->ns_rxend/DS_PGSIZE);
389 outb(nec+ds0_bnry, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
390 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
391 outb(nec+ds1_curr, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
392 ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
393 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
394 outb (nec+ds0_rcr, DSRC_AB);
395 outb(nec+ds0_dcr, ns->ns_mode);
396 outb (nec+ds0_imr, 0xff);
397
d3a11a24 398 ns->arpcom.ac_if.if_flags |= IFF_RUNNING;
15637ed4
RG
399 ns->ns_flags &= ~DSF_LOCK;
400 ns->ns_oactive = 0; ns->ns_mask = ~0;
401 nestart(ifp);
402 splx(s);
403}
404
405/*
406 * Setup output on interface.
407 * Get another datagram to send off of the interface queue,
408 * and map it to the interface before starting the output.
409 * called only at splimp or interrupt level.
410 */
411nestart(ifp)
412 struct ifnet *ifp;
413{
414 register struct ne_softc *ns = &ne_softc[ifp->if_unit];
415 struct mbuf *m0, *m;
b794bfc8 416 int len, i, total,t;
15637ed4 417 register nec = ns->ns_port;
b794bfc8
JH
418 u_char cmd;
419 u_short word;
420 int counter;
421
422 if (ns->ns_flags & DSF_LOCK)
423 return;
424
d3a11a24 425 if ((ns->arpcom.ac_if.if_flags & IFF_RUNNING) == 0)
b794bfc8 426 return;
15637ed4
RG
427
428 /*
429 * The DS8390 has only one transmit buffer, if it is busy we
430 * must wait until the transmit interrupt completes.
431 */
432 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
433
15637ed4
RG
434 if (inb(nec+ds_cmd) & DSCM_TRANS)
435 return;
436
d3a11a24 437 IF_DEQUEUE(&ns->arpcom.ac_if.if_snd, m);
15637ed4
RG
438
439 if (m == 0)
440 return;
441
b794bfc8
JH
442 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
443
15637ed4
RG
444 /*
445 * Copy the mbuf chain into the transmit buffer
446 */
447
b794bfc8 448 len = i = 0;
15637ed4
RG
449 t = 0;
450 for (m0 = m; m != 0; m = m->m_next)
451 t += m->m_len;
452
b794bfc8 453 /* next code derived from neput() */
15637ed4 454
b794bfc8
JH
455 if ((ns->ns_mode & DSDC_WTS) && t&1)
456 t++; /* roundup to words */
457
458 cmd = inb(nec+ds_cmd);
459 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
460
461 /* Setup for remote dma */
462 outb (nec+ds0_isr, DSIS_RDC);
463
464 outb (nec+ds0_rbcr0, t);
465 outb (nec+ds0_rbcr1, t>>8);
466 outb (nec+ds0_rsar0, ns->ns_txstart);
467 outb (nec+ds0_rsar1, ns->ns_txstart>>8);
468
469 /* Execute & stuff to card */
470 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
471
15637ed4 472 m = m0;
b794bfc8
JH
473 total = t;
474 if (ns->ns_mode & DSDC_WTS) { /* Word Mode */
475 while (m != 0) {
476 if (m->m_len > 1)
477 outsw(nec+ne_data, m->m_data, m->m_len / 2);
478 if (m->m_len & 1) {
479 word = (u_char) *(mtod(m, caddr_t) + m->m_len - 1);
480 if ((m = m->m_next) != 0) {
481 word |= *mtod(m, caddr_t) << 8;
482 m->m_len--;
483 m->m_data++;
484 }
485 outsw(nec+ne_data, (caddr_t)&word, 1);
486 } else
487 m = m->m_next;
488 }
489 }
490 else { /* Byte Mode */
491 while (m != 0) {
492 if (m->m_len > 0)
493 outsb(nec+ne_data, mtod(m, caddr_t), m->m_len);
494 m = m->m_next;
15637ed4
RG
495 }
496 }
497
b794bfc8
JH
498 m_freem(m0);
499
500 counter = 100000;
501 /* Wait till done, then shutdown feature */
502 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
503 ;
504 outb (nec+ds0_isr, DSIS_RDC);
505 outb (nec+ds_cmd, cmd);
506
15637ed4
RG
507 /*
508 * Init transmit length registers, and set transmit start flag.
509 */
510
511 len = total;
512 if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
513 outb(nec+ds0_tbcr0,len&0xff);
514 outb(nec+ds0_tbcr1,(len>>8)&0xff);
515 outb(nec+ds0_tpsr, ns->ns_txstart/DS_PGSIZE);
516 outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
517}
518
519/* buffer successor/predecessor in ring? */
520#define succ(n) (((n)+1 >= ns->ns_rxend/DS_PGSIZE) ? (ns->ns_txstart+PKTSZ)/DS_PGSIZE : (n)+1)
521#define pred(n) (((n)-1 < (ns->ns_txstart+PKTSZ)/DS_PGSIZE) ? ns->ns_rxend/DS_PGSIZE-1 : (n)-1)
522
523/*
524 * Controller interrupt.
525 */
526neintr(unit)
527{
528 register struct ne_softc *ns = &ne_softc[unit];
529 u_char cmd,isr;
530 register nec = ns->ns_port;
531
532 /* Save cmd, clear interrupt */
533 cmd = inb (nec+ds_cmd);
534loop:
535 isr = inb (nec+ds0_isr);
536 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
537 outb(nec+ds0_isr, isr);
538
539 /* Receiver error */
540 if (isr & DSIS_RXE) {
541 /* need to read these registers to clear status */
542 (void) inb(nec+ ds0_rsr);
543 (void) inb(nec+ 0xD);
544 (void) inb(nec + 0xE);
545 (void) inb(nec + 0xF);
d3a11a24 546 ns->arpcom.ac_if.if_ierrors++;
15637ed4
RG
547 }
548
549 /* We received something; rummage thru tiny ring buffer */
550 if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
551 u_char pend,lastfree;
552
553 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
554 pend = inb(nec+ds1_curr);
555 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
556 lastfree = inb(nec+ds0_bnry);
557
558 /* Have we wrapped? */
559 if (lastfree >= ns->ns_rxend/DS_PGSIZE)
560 lastfree = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
561 if (pend < lastfree && ns->ns_cur < pend)
562 lastfree = ns->ns_cur;
563 else if (ns->ns_cur > lastfree)
564 lastfree = ns->ns_cur;
565
566 /* Something in the buffer? */
567 while (pend != lastfree) {
568 u_char nxt;
569
570 /* Extract header from microcephalic board */
571 nefetch(ns, &ns->ns_ph,lastfree*DS_PGSIZE,
572 sizeof(ns->ns_ph));
573 ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
574
575 /* Incipient paranoia */
576 if (ns->ns_ph.pr_status == DSRS_RPC ||
577 /* for dequna's */
578 ns->ns_ph.pr_status == 0x21)
579 nerecv (ns);
580#ifdef NEDEBUG
581 else {
582 printf("cur %x pnd %x lfr %x ",
583 ns->ns_cur, pend, lastfree);
584 printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg,
585 (ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0);
586 printf("Bogus Sts %x\n", ns->ns_ph.pr_status);
587 }
588#endif
589
590 nxt = ns->ns_ph.pr_nxtpg ;
591
592 /* Sanity check */
593 if ( nxt >= (ns->ns_txstart+PKTSZ)/DS_PGSIZE
594 && nxt <= ns->ns_rxend/DS_PGSIZE && nxt <= pend)
595 ns->ns_cur = nxt;
596 else ns->ns_cur = nxt = pend;
597
598 /* Set the boundaries */
599 lastfree = nxt;
600 outb(nec+ds0_bnry, pred(nxt));
601 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
602 pend = inb(nec+ds1_curr);
603 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
604 }
605 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
606 }
607
608 /* Transmit error */
609 if (isr & DSIS_TXE) {
610 ns->ns_flags &= ~DSF_LOCK;
611 /* Need to read these registers to clear status */
d3a11a24
RG
612 ns->arpcom.ac_if.if_collisions += inb(nec+ds0_tbcr0);
613 ns->arpcom.ac_if.if_oerrors++;
15637ed4
RG
614 }
615
616 /* Packet Transmitted */
617 if (isr & DSIS_TX) {
618 ns->ns_flags &= ~DSF_LOCK;
d3a11a24
RG
619 ++ns->arpcom.ac_if.if_opackets;
620 ns->arpcom.ac_if.if_collisions += inb(nec+ds0_tbcr0);
15637ed4
RG
621 }
622
623 /* Receiver ovverun? */
624 if (isr & DSIS_ROVRN) {
625 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
626 /*, DSIS_BITS*/);
627 outb(nec+ds0_rbcr0, 0);
628 outb(nec+ds0_rbcr1, 0);
629 outb(nec+ds0_tcr, DSTC_LB0);
630 outb(nec+ds0_rcr, DSRC_MON);
631 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
632 outb(nec+ds0_rcr, DSRC_AB);
633 outb(nec+ds0_tcr, 0);
634 }
635
636 /* Any more to send? */
637 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
d3a11a24 638 nestart(&ns->arpcom.ac_if);
15637ed4
RG
639 outb (nec+ds_cmd, cmd);
640 outb (nec+ds0_imr, 0xff);
641
642 /* Still more to do? */
643 isr = inb (nec+ds0_isr);
644 if(isr) goto loop;
645}
646
647/*
648 * Ethernet interface receiver interface.
649 * If input error just drop packet.
650 * Otherwise examine packet to determine type. If can't determine length
651 * from type, then have to drop packet. Othewise decapsulate
652 * packet based on type and pass to type specific higher-level
653 * input routine.
654 */
655nerecv(ns)
656 register struct ne_softc *ns;
657{
658 int len,i;
659
d3a11a24 660 ns->arpcom.ac_if.if_ipackets++;
15637ed4
RG
661 len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
662 if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN)
663 return;
664
665 /* this need not be so torturous - one/two bcopys at most into mbufs */
666 nefetch(ns, ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
667 if (len > DS_PGSIZE-sizeof(ns->ns_ph)) {
668 int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
669 u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
670
b794bfc8
JH
671 if (++ns->ns_cur >= ns->ns_rxend/DS_PGSIZE)
672 ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
15637ed4
RG
673 b = ns->ns_cur*DS_PGSIZE;
674
675 while (l >= DS_PGSIZE) {
676 nefetch(ns, p, b, DS_PGSIZE);
677 p += DS_PGSIZE; l -= DS_PGSIZE;
b794bfc8
JH
678 if (++ns->ns_cur >= ns->ns_rxend/DS_PGSIZE)
679 ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
15637ed4
RG
680 b = ns->ns_cur*DS_PGSIZE;
681 }
682 if (l > 0)
683 nefetch(ns, p, b, l);
684 }
685 /* don't forget checksum! */
686 len -= sizeof(struct ether_header) + sizeof(long);
687
688 neread(ns,(caddr_t)(ns->ns_pb), len);
689}
690
691/*
692 * Pass a packet to the higher levels.
693 * We deal with the trailer protocol here.
694 */
695neread(ns, buf, len)
696 register struct ne_softc *ns;
697 char *buf;
698 int len;
699{
700 register struct ether_header *eh;
701 struct mbuf *m;
702 int off, resid;
703 register struct ifqueue *inq;
704
705 /*
706 * Deal with trailer protocol: if type is trailer type
707 * get true type from first 16-bit word past data.
708 * Remember that type was trailer by setting off.
709 */
710 eh = (struct ether_header *)buf;
711 eh->ether_type = ntohs((u_short)eh->ether_type);
712#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
713 if (eh->ether_type >= ETHERTYPE_TRAIL &&
714 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
715 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
716 if (off >= ETHERMTU) return; /* sanity */
717 eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
718 resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
719 if (off + resid > len) return; /* sanity */
720 len = off + resid;
721 } else off = 0;
722
723 if (len == 0) return;
724
725 /*
726 * Pull packet off interface. Off is nonzero if packet
727 * has trailing header; neget will then force this header
728 * information to be at the front, but we still have to drop
729 * the type and length which are at the front of any trailer data.
730 */
d3a11a24 731 m = neget(buf, len, off, &ns->arpcom.ac_if);
15637ed4
RG
732 if (m == 0) return;
733
d3a11a24 734 ether_input(&ns->arpcom.ac_if, eh, m);
15637ed4
RG
735}
736
737/*
738 * Supporting routines
739 */
740
741/*
742 * Pull read data off a interface.
743 * Len is length of data, with local net header stripped.
744 * Off is non-zero if a trailer protocol was used, and
745 * gives the offset of the trailer information.
746 * We copy the trailer information and then all the normal
747 * data into mbufs. When full cluster sized units are present
748 * we copy into clusters.
749 */
750struct mbuf *
751neget(buf, totlen, off0, ifp)
752 caddr_t buf;
753 int totlen, off0;
754 struct ifnet *ifp;
755{
756 struct mbuf *top, **mp, *m, *p;
757 int off = off0, len;
758 register caddr_t cp = buf;
759 char *epkt;
760
761 buf += sizeof(struct ether_header);
762 cp = buf;
763 epkt = cp + totlen;
764
765
766 if (off) {
767 cp += off + 2 * sizeof(u_short);
768 totlen -= 2 * sizeof(u_short);
769 }
770
771 MGETHDR(m, M_DONTWAIT, MT_DATA);
772 if (m == 0)
773 return (0);
774 m->m_pkthdr.rcvif = ifp;
775 m->m_pkthdr.len = totlen;
776 m->m_len = MHLEN;
777
778 top = 0;
779 mp = &top;
780 while (totlen > 0) {
781 if (top) {
782 MGET(m, M_DONTWAIT, MT_DATA);
783 if (m == 0) {
784 m_freem(top);
785 return (0);
786 }
787 m->m_len = MLEN;
788 }
789 len = min(totlen, epkt - cp);
790 if (len >= MINCLSIZE) {
791 MCLGET(m, M_DONTWAIT);
792 if (m->m_flags & M_EXT)
793 m->m_len = len = min(len, MCLBYTES);
794 else
795 len = m->m_len;
796 } else {
797 /*
798 * Place initial small packet/header at end of mbuf.
799 */
800 if (len < m->m_len) {
801 if (top == 0 && len + max_linkhdr <= m->m_len)
802 m->m_data += max_linkhdr;
803 m->m_len = len;
804 } else
805 len = m->m_len;
806 }
807 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
808 cp += len;
809 *mp = m;
810 mp = &m->m_next;
811 totlen -= len;
812 if (cp == epkt)
813 cp = buf;
814 }
815 return (top);
816}
817
818/*
819 * Process an ioctl request.
820 */
821neioctl(ifp, cmd, data)
822 register struct ifnet *ifp;
823 int cmd;
824 caddr_t data;
825{
826 register struct ifaddr *ifa = (struct ifaddr *)data;
827 struct ne_softc *ns = &ne_softc[ifp->if_unit];
828 struct ifreq *ifr = (struct ifreq *)data;
829 int s = splimp(), error = 0;
830
831
832 switch (cmd) {
833
834 case SIOCSIFADDR:
835 ifp->if_flags |= IFF_UP;
836
837 switch (ifa->ifa_addr->sa_family) {
838#ifdef INET
839 case AF_INET:
840 neinit(ifp->if_unit); /* before arpwhohas */
841 ((struct arpcom *)ifp)->ac_ipaddr =
842 IA_SIN(ifa)->sin_addr;
843 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
844 break;
845#endif
846#ifdef NS
847 case AF_NS:
848 {
849 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
850
851 if (ns_nullhost(*ina))
d3a11a24
RG
852 ina->x_host =
853 *(union ns_host *)(ns->arpcom.ac_enaddr);
15637ed4
RG
854 else {
855 /*
856 * The manual says we can't change the address
857 * while the receiver is armed,
858 * so reset everything
859 */
860 ifp->if_flags &= ~IFF_RUNNING;
861 bcopy((caddr_t)ina->x_host.c_host,
d3a11a24
RG
862 (caddr_t)ns->arpcom.ac_enaddr,
863 sizeof(ns->arpcom.ac_enaddr));
15637ed4
RG
864 }
865 neinit(ifp->if_unit); /* does ne_setaddr() */
866 break;
867 }
868#endif
869 default:
870 neinit(ifp->if_unit);
871 break;
872 }
873 break;
874
875 case SIOCSIFFLAGS:
876 if ((ifp->if_flags & IFF_UP) == 0 &&
877 ifp->if_flags & IFF_RUNNING) {
878 ifp->if_flags &= ~IFF_RUNNING;
879 outb(ns->ns_port + ds_cmd, DSCM_STOP|DSCM_NODMA);
880 } else if (ifp->if_flags & IFF_UP &&
881 (ifp->if_flags & IFF_RUNNING) == 0)
882 neinit(ifp->if_unit);
883 break;
884
885#ifdef notdef
886 case SIOCGHWADDR:
d3a11a24
RG
887 bcopy((caddr_t)ns->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data,
888 sizeof(ns->arpcom.ac_enaddr));
15637ed4
RG
889 break;
890#endif
891
892 default:
893 error = EINVAL;
894 }
895 splx(s);
896 return (error);
897}
898#endif