Oh GACK! src-clean doesn't quite work that easily since cleandist rebuilds the
[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/*
aa544edf 38 * NE1000/NE2000 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.
42 */
43
44#include "ne.h"
45#if NNE > 0
46
47#include "param.h"
48#include "systm.h"
aa544edf
RG
49#include "errno.h"
50#include "ioctl.h"
15637ed4 51#include "mbuf.h"
15637ed4 52#include "socket.h"
15637ed4
RG
53#include "syslog.h"
54
55#include "net/if.h"
aa544edf
RG
56#include "net/if_dl.h"
57#include "net/if_types.h"
15637ed4 58#include "net/netisr.h"
15637ed4
RG
59
60#ifdef INET
61#include "netinet/in.h"
62#include "netinet/in_systm.h"
63#include "netinet/in_var.h"
64#include "netinet/ip.h"
65#include "netinet/if_ether.h"
66#endif
67
68#ifdef NS
69#include "netns/ns.h"
70#include "netns/ns_if.h"
71#endif
72
aa544edf 73#include "i386/isa/isa.h"
15637ed4 74#include "i386/isa/isa_device.h"
15637ed4 75#include "i386/isa/icu.h"
aa544edf
RG
76#include "i386/isa/if_nereg.h"
77
78#include "i386/include/pio.h"
15637ed4
RG
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
aa544edf
RG
92/* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
93#define DCR_CTRL2 (DSDC_WTS|DSDC_BMS|DSDC_FT1)
94/* No Word Transfers, Burst Mode Select, Fifo at 8 bytes */
95#define DCR_CTRL1 (DSDC_BMS|DSDC_FT1)
96
97
15637ed4
RG
98/*
99 * Ethernet software status per interface.
100 *
101 * Each interface is referenced by a network interface structure,
d3a11a24 102 * arpcom.ac_if, which the routing code uses to locate the interface.
15637ed4
RG
103 * This structure contains the output queue for the interface, its address, ...
104 */
105struct ne_softc {
d3a11a24 106 struct arpcom arpcom; /* Ethernet common part */
15637ed4
RG
107 int ns_flags;
108#define DSF_LOCK 1 /* block re-entering enstart */
aa544edf 109 int ns_mask;
15637ed4
RG
110 int ns_ba; /* byte addr in buffer ram of inc pkt */
111 int ns_cur; /* current page being filled */
aa544edf
RG
112 u_short ns_iobase;
113 u_short ns_board; /* Board-Type: 0:NE1000, 1:NE2000 */
114 u_short ns_tbuf;
115 u_short ns_rbuf;
116 u_short ns_rbufend;
15637ed4
RG
117 struct prhdr ns_ph; /* hardware header of incoming packet*/
118 struct ether_header ns_eh; /* header of incoming packet */
119 u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
aa544edf 120} ne_softc[NNE];
15637ed4
RG
121#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
122
aa544edf
RG
123u_char boarddata[16];
124void nefetch (struct ne_softc *ns, void *up, u_int ad, u_int len);
125void neput (struct ne_softc *ns, void *up, u_int ad, u_int len);
126
15637ed4 127
15637ed4
RG
128neprobe(dvp)
129 struct isa_device *dvp;
130{
aa544edf
RG
131 int val,i, test, unit;
132 u_short iobase;
133 register struct ne_softc *ns;
15637ed4 134
aa544edf
RG
135 unit = dvp->id_unit;
136 if (unit >= NNE)
137 return (0);
138 ns = &ne_softc[unit];
139 if (ns->ns_iobase)
140 /* Unit already configured */
141 return (0);
142 iobase = ns->ns_iobase = dvp->id_iobase;
15637ed4
RG
143
144 /* Reset the bastard */
aa544edf 145 val = inb(iobase+ne_reset);
15637ed4 146 DELAY(200);
aa544edf 147 outb(iobase+ne_reset,val);
15637ed4
RG
148 DELAY(200);
149
aa544edf 150 outb(iobase+ds_cmd, DSCM_STOP|DSCM_NODMA);
15637ed4 151
aa544edf
RG
152 if (inb (iobase + ds_cmd) != (DSCM_STOP | DSCM_NODMA))
153 return (0);
154 i = 1000000;
155 while ((inb(iobase+ds0_isr)&DSIS_RESET) == 0 && i-- > 0);
156 if (i <= 0) return (0);
157
158 outb(iobase+ds0_isr, 0xff);
15637ed4 159
aa544edf
RG
160 /* No Word Transfers, Burst Mode Select, Fifo at 8 bytes */
161 outb (iobase+ds0_dcr, DCR_CTRL1);
162
163 outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
164 DELAY(10000);
15637ed4
RG
165
166 /* Check cmd reg and fail if not right */
aa544edf 167 if ((i=inb(iobase+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
15637ed4
RG
168 return(0);
169
aa544edf
RG
170 outb(iobase+ds0_tcr, 0);
171 outb(iobase+ds0_rcr, DSRC_MON);
172 outb(iobase+ds0_pstart, RBUF1/DS_PGSIZE);
173 outb(iobase+ds0_pstop, RBUFEND1/DS_PGSIZE);
174 outb(iobase+ds0_bnry, RBUFEND1/DS_PGSIZE);
175 outb(iobase+ds0_imr, 0);
176 outb(iobase+ds0_isr, 0);
177 outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
178 outb(iobase+ds1_curr, RBUF1/DS_PGSIZE);
179 outb(iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
180 test = 0xA55A55AA;
181 neput (ns, &test, TBUF1, sizeof (test));
182 nefetch (ns, &test, TBUF1, sizeof (test));
183 if (test == 0xA55A55AA) {
184 ns->ns_board = 0; /* NE1000 */
185 ns->ns_tbuf = TBUF1;
186 ns->ns_rbuf = RBUF1;
187 ns->ns_rbufend = RBUFEND1;
188 }
189 else {
190 ns->ns_board = 1; /* NE2000 */
191 ns->ns_tbuf = TBUF2;
192 ns->ns_rbuf = RBUF2;
193 ns->ns_rbufend = RBUFEND2;
194 outb(iobase+ds0_dcr, DCR_CTRL2);
195 }
15637ed4
RG
196
197#ifdef NEDEBUG
aa544edf 198#define PAT(n) (0xa55a + 37*(n))
15637ed4 199#define RCON 37
aa544edf 200 { int i, rom, pat;
15637ed4
RG
201
202 rom=1;
203 printf("ne ram ");
204
205 for (i = 0; i < 0xfff0; i+=4) {
206 pat = PAT(i);
aa544edf
RG
207 neput (ns, &pat,i,4);
208 nefetch (ns, &pat,i,4);
15637ed4
RG
209 if (pat == PAT(i)) {
210 if (rom) {
211 rom=0;
212 printf(" %x", i);
213 }
214 } else {
215 if (!rom) {
216 rom=1;
217 printf("..%x ", i);
218 }
219 }
220 pat=0;
aa544edf 221 neput (ns, &pat,i,4);
15637ed4
RG
222 }
223 printf("\n");
224 }
225#endif
226
15637ed4 227 /* Extract board address */
aa544edf
RG
228 nefetch (ns, boarddata, 0, sizeof(boarddata));
229 if (ns->ns_board)
230 for (i = 0; i < 6; i++)
231 ns->arpcom.ac_enaddr[i] = boarddata[2 * i];
232 else
233 for (i = 0; i < 6; i++)
234 ns->arpcom.ac_enaddr[i] = boarddata[i];
15637ed4
RG
235 return (1);
236}
237
238/*
239 * Fetch from onboard ROM/RAM
240 */
aa544edf
RG
241void nefetch (struct ne_softc *ns, void *up, u_int ad, u_int len)
242{
15637ed4 243 u_char cmd;
aa544edf 244 const u_short iobase = ns->ns_iobase;
15637ed4 245
aa544edf
RG
246 if (len == 0)
247 return;
248 cmd = inb(iobase+ds_cmd);
249 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
15637ed4
RG
250
251 /* Setup remote dma */
aa544edf
RG
252 outb (iobase+ds0_isr, DSIS_RDC);
253 outb (iobase+ds0_rbcr0, len);
254 outb (iobase+ds0_rbcr1, len>>8);
255 outb (iobase+ds0_rsar0, ad);
256 outb (iobase+ds0_rsar1, ad>>8);
15637ed4
RG
257
258 /* Execute & extract from card */
aa544edf
RG
259 outb (iobase+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
260 if (ns->ns_board)
261 insw (iobase+ne_data, up, len/2);
15637ed4 262 else
aa544edf 263 insb (iobase+ne_data, up, len/1);
15637ed4
RG
264
265 /* Wait till done, then shutdown feature */
aa544edf 266 while ((inb (iobase+ds0_isr) & DSIS_RDC) == 0)
15637ed4 267 ;
aa544edf
RG
268 outb (iobase+ds0_isr, DSIS_RDC);
269 outb (iobase+ds_cmd, cmd);
15637ed4
RG
270}
271
272/*
273 * Put to onboard RAM
274 */
aa544edf
RG
275void neput (struct ne_softc *ns, void *up, u_int ad, u_int len)
276{
15637ed4 277 u_char cmd;
aa544edf 278 const u_short iobase = ns->ns_iobase;
15637ed4 279
aa544edf
RG
280 if (len == 0)
281 return;
282 cmd = inb(iobase+ds_cmd);
283 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
15637ed4
RG
284
285 /* Setup for remote dma */
aa544edf
RG
286 outb (iobase+ds0_isr, DSIS_RDC);
287 if(len&1) len++; /* roundup to words */
288 outb (iobase+ds0_rbcr0, len);
289 outb (iobase+ds0_rbcr1, len>>8);
290 outb (iobase+ds0_rsar0, ad);
291 outb (iobase+ds0_rsar1, ad>>8);
15637ed4
RG
292
293 /* Execute & stuff to card */
aa544edf
RG
294 outb (iobase+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
295 if (ns->ns_board)
296 outsw (iobase+ne_data, up, len/2);
15637ed4 297 else
aa544edf 298 outsb (iobase+ne_data, up, len/1);
15637ed4
RG
299
300 /* Wait till done, then shutdown feature */
aa544edf 301 while ((inb (iobase+ds0_isr) & DSIS_RDC) == 0)
15637ed4 302 ;
aa544edf
RG
303 outb (iobase+ds0_isr, DSIS_RDC);
304 outb (iobase+ds_cmd, cmd);
15637ed4
RG
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;
aa544edf 333 ifp->if_name = nedriver.name;
15637ed4 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),
aa544edf 338 (ns->ns_board) ? "1000" : "2000");
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 358 int s;
aa544edf
RG
359 register i; char *cp;
360 const u_short iobase = ns->ns_iobase;
15637ed4
RG
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 */
aa544edf
RG
368 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
369 for (i=0; i < 6; i++) outb(iobase+ds1_par0+i,ns->arpcom.ac_enaddr[i]);
15637ed4
RG
370
371 /* clr logical address hash filter for now */
aa544edf 372 for (i=0; i < 8; i++) outb(iobase+ds1_mar0+i,0xff);
15637ed4
RG
373
374 /* init regs */
aa544edf
RG
375 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
376 outb (iobase+ds0_rbcr0, 0);
377 outb (iobase+ds0_rbcr1, 0);
378 outb (iobase+ds0_imr, 0);
379 outb (iobase+ds0_isr, 0xff);
380
381 outb(iobase+ds0_tcr, 0);
382 outb (iobase+ds0_rcr, DSRC_MON);
383 outb (iobase+ds0_tpsr, 0);
384 outb(iobase+ds0_pstart, ns->ns_rbuf/DS_PGSIZE);
385 outb(iobase+ds0_pstop, ns->ns_rbufend/DS_PGSIZE);
386 outb(iobase+ds0_bnry, ns->ns_rbuf/DS_PGSIZE);
387 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
388 outb(iobase+ds1_curr, ns->ns_rbuf/DS_PGSIZE);
389 ns->ns_cur = ns->ns_rbuf/DS_PGSIZE;
390 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
391 outb (iobase+ds0_rcr, DSRC_AB);
392 if (ns->ns_board) {
393 outb(iobase + ds0_dcr, DCR_CTRL2);
394 } else {
395 outb(iobase+ds0_dcr, DCR_CTRL1);
396 }
397 outb (iobase+ds0_imr, 0xff);
15637ed4 398
d3a11a24 399 ns->arpcom.ac_if.if_flags |= IFF_RUNNING;
aa544edf 400 ns->ns_mask = ~0;
15637ed4
RG
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;
aa544edf
RG
416 int buffer;
417 int len = 0, i, total,t;
418 const u_short iobase = ns->ns_iobase;
15637ed4
RG
419
420 /*
421 * The DS8390 has only one transmit buffer, if it is busy we
422 * must wait until the transmit interrupt completes.
423 */
aa544edf
RG
424 outb(iobase+ds_cmd,DSCM_NODMA|DSCM_START);
425
426 if (ns->ns_flags & DSF_LOCK)
427 return;
428
429 if (inb(iobase+ds_cmd) & DSCM_TRANS)
430 return;
15637ed4 431
aa544edf 432 if ((ns->arpcom.ac_if.if_flags & IFF_RUNNING) == 0)
15637ed4
RG
433 return;
434
d3a11a24 435 IF_DEQUEUE(&ns->arpcom.ac_if.if_snd, m);
15637ed4
RG
436
437 if (m == 0)
438 return;
439
440 /*
441 * Copy the mbuf chain into the transmit buffer
442 */
443
aa544edf
RG
444 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
445 buffer = ns->ns_tbuf; len = i = 0;
15637ed4
RG
446 t = 0;
447 for (m0 = m; m != 0; m = m->m_next)
448 t += m->m_len;
449
aa544edf
RG
450 m = m0;
451 total = t;
452 for (m0 = m; m != 0; ) {
b794bfc8 453
aa544edf
RG
454 if (m->m_len&1 && t > m->m_len) {
455 neput (ns, mtod(m, caddr_t), buffer, m->m_len - 1);
456 t -= m->m_len - 1;
457 buffer += m->m_len - 1;
458 m->m_data += m->m_len - 1;
459 m->m_len = 1;
460 m = m_pullup(m, 2);
461 } else {
462 if (m->m_len) {
463 neput (ns, mtod(m, caddr_t), buffer, m->m_len);
464 buffer += m->m_len;
465 t -= m->m_len;
466 }
467 MFREE(m, m0);
15637ed4 468 m = m0;
b794bfc8
JH
469 }
470 }
b794bfc8 471
15637ed4
RG
472 /*
473 * Init transmit length registers, and set transmit start flag.
474 */
475
476 len = total;
477 if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
aa544edf
RG
478 outb(iobase+ds0_tbcr0,len&0xff);
479 outb(iobase+ds0_tbcr1,(len>>8)&0xff);
480 outb(iobase+ds0_tpsr, ns->ns_tbuf/DS_PGSIZE);
481 outb(iobase+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
15637ed4
RG
482}
483
484/* buffer successor/predecessor in ring? */
aa544edf
RG
485#define succ1(n) (((n)+1 >= RBUFEND1/DS_PGSIZE) ? RBUF1/DS_PGSIZE : (n)+1)
486#define pred1(n) (((n)-1 < RBUF1/DS_PGSIZE) ? RBUFEND1/DS_PGSIZE-1 : (n)-1)
487#define succ2(n) (((n)+1 >= RBUFEND2/DS_PGSIZE) ? RBUF2/DS_PGSIZE : (n)+1)
488#define pred2(n) (((n)-1 < RBUF2/DS_PGSIZE) ? RBUFEND2/DS_PGSIZE-1 : (n)-1)
15637ed4
RG
489
490/*
491 * Controller interrupt.
492 */
493neintr(unit)
494{
495 register struct ne_softc *ns = &ne_softc[unit];
496 u_char cmd,isr;
aa544edf 497 const u_short iobase = ns->ns_iobase;
15637ed4
RG
498
499 /* Save cmd, clear interrupt */
aa544edf 500 cmd = inb (iobase+ds_cmd);
15637ed4 501loop:
aa544edf
RG
502 isr = inb (iobase+ds0_isr);
503 outb(iobase+ds_cmd,DSCM_NODMA|DSCM_START);
504 outb(iobase+ds0_isr, isr);
15637ed4
RG
505
506 /* Receiver error */
507 if (isr & DSIS_RXE) {
508 /* need to read these registers to clear status */
aa544edf
RG
509 (void) inb(iobase+ ds0_rsr);
510 (void) inb(iobase+ 0xD);
511 (void) inb(iobase + 0xE);
512 (void) inb(iobase + 0xF);
d3a11a24 513 ns->arpcom.ac_if.if_ierrors++;
15637ed4
RG
514 }
515
516 /* We received something; rummage thru tiny ring buffer */
517 if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
518 u_char pend,lastfree;
519
aa544edf
RG
520 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
521 pend = inb(iobase+ds1_curr);
522 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
523 lastfree = inb(iobase+ds0_bnry);
15637ed4
RG
524
525 /* Have we wrapped? */
aa544edf
RG
526 if (lastfree >= ns->ns_rbufend/DS_PGSIZE)
527 lastfree = ns->ns_rbuf/DS_PGSIZE;
15637ed4
RG
528 if (pend < lastfree && ns->ns_cur < pend)
529 lastfree = ns->ns_cur;
530 else if (ns->ns_cur > lastfree)
531 lastfree = ns->ns_cur;
532
533 /* Something in the buffer? */
534 while (pend != lastfree) {
535 u_char nxt;
536
537 /* Extract header from microcephalic board */
aa544edf 538 nefetch (ns, &ns->ns_ph,lastfree*DS_PGSIZE,
15637ed4
RG
539 sizeof(ns->ns_ph));
540 ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
541
542 /* Incipient paranoia */
543 if (ns->ns_ph.pr_status == DSRS_RPC ||
544 /* for dequna's */
545 ns->ns_ph.pr_status == 0x21)
546 nerecv (ns);
547#ifdef NEDEBUG
aa544edf 548 else {
15637ed4
RG
549 printf("cur %x pnd %x lfr %x ",
550 ns->ns_cur, pend, lastfree);
551 printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg,
552 (ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0);
553 printf("Bogus Sts %x\n", ns->ns_ph.pr_status);
554 }
555#endif
556
aa544edf 557 nxt = ns->ns_ph.pr_nxtpg;
15637ed4
RG
558
559 /* Sanity check */
aa544edf
RG
560 if ( nxt >= ns->ns_rbuf/DS_PGSIZE && nxt <= ns->ns_rbufend/DS_PGSIZE
561 && nxt <= pend)
15637ed4
RG
562 ns->ns_cur = nxt;
563 else ns->ns_cur = nxt = pend;
564
565 /* Set the boundaries */
566 lastfree = nxt;
aa544edf
RG
567 if (ns->ns_board) {
568 outb(iobase+ds0_bnry, pred2(nxt));
569 } else {
570 outb(iobase+ds0_bnry, pred1(nxt));
571 }
572 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
573 pend = inb(iobase+ds1_curr);
574 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
15637ed4 575 }
aa544edf 576 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA);
15637ed4
RG
577 }
578
579 /* Transmit error */
580 if (isr & DSIS_TXE) {
581 ns->ns_flags &= ~DSF_LOCK;
582 /* Need to read these registers to clear status */
aa544edf 583 ns->arpcom.ac_if.if_collisions += inb(iobase+ds0_tbcr0);
d3a11a24 584 ns->arpcom.ac_if.if_oerrors++;
15637ed4
RG
585 }
586
587 /* Packet Transmitted */
588 if (isr & DSIS_TX) {
589 ns->ns_flags &= ~DSF_LOCK;
d3a11a24 590 ++ns->arpcom.ac_if.if_opackets;
aa544edf 591 ns->arpcom.ac_if.if_collisions += inb(iobase+ds0_tbcr0);
15637ed4
RG
592 }
593
594 /* Receiver ovverun? */
595 if (isr & DSIS_ROVRN) {
596 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
597 /*, DSIS_BITS*/);
aa544edf
RG
598 outb(iobase+ds0_rbcr0, 0);
599 outb(iobase+ds0_rbcr1, 0);
600 outb(iobase+ds0_tcr, DSTC_LB0);
601 outb(iobase+ds0_rcr, DSRC_MON);
602 outb(iobase+ds_cmd, DSCM_START|DSCM_NODMA);
603 outb(iobase+ds0_rcr, DSRC_AB);
604 outb(iobase+ds0_tcr, 0);
15637ed4
RG
605 }
606
607 /* Any more to send? */
aa544edf 608 outb (iobase+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
d3a11a24 609 nestart(&ns->arpcom.ac_if);
aa544edf
RG
610 outb (iobase+ds_cmd, cmd);
611 outb (iobase+ds0_imr, 0xff);
612
15637ed4
RG
613
614 /* Still more to do? */
aa544edf 615 isr = inb (iobase+ds0_isr);
15637ed4
RG
616 if(isr) goto loop;
617}
618
619/*
620 * Ethernet interface receiver interface.
621 * If input error just drop packet.
622 * Otherwise examine packet to determine type. If can't determine length
623 * from type, then have to drop packet. Othewise decapsulate
624 * packet based on type and pass to type specific higher-level
625 * input routine.
626 */
627nerecv(ns)
628 register struct ne_softc *ns;
629{
630 int len,i;
631
d3a11a24 632 ns->arpcom.ac_if.if_ipackets++;
15637ed4
RG
633 len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
634 if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN)
635 return;
636
637 /* this need not be so torturous - one/two bcopys at most into mbufs */
aa544edf 638 nefetch (ns, ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
15637ed4 639 if (len > DS_PGSIZE-sizeof(ns->ns_ph)) {
aa544edf 640 int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b, m;
15637ed4
RG
641 u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
642
aa544edf
RG
643 for (;;) {
644 if (ns->ns_board == 1)
645 ns->ns_cur = succ2 (ns->ns_cur);
646 else
647 ns->ns_cur = succ1 (ns->ns_cur);
15637ed4 648 b = ns->ns_cur*DS_PGSIZE;
aa544edf
RG
649 if (l >= DS_PGSIZE) {
650 nefetch (ns, p, b, DS_PGSIZE);
651 p += DS_PGSIZE; l -= DS_PGSIZE;
652 continue;
653 }
654 if (l > 0)
655 nefetch (ns, p, b, l);
656 break;
15637ed4 657 }
15637ed4
RG
658 }
659 /* don't forget checksum! */
660 len -= sizeof(struct ether_header) + sizeof(long);
661
662 neread(ns,(caddr_t)(ns->ns_pb), len);
663}
664
665/*
666 * Pass a packet to the higher levels.
667 * We deal with the trailer protocol here.
668 */
669neread(ns, buf, len)
670 register struct ne_softc *ns;
671 char *buf;
672 int len;
673{
674 register struct ether_header *eh;
aa544edf 675 struct mbuf *m;
15637ed4
RG
676 int off, resid;
677 register struct ifqueue *inq;
678
679 /*
680 * Deal with trailer protocol: if type is trailer type
681 * get true type from first 16-bit word past data.
682 * Remember that type was trailer by setting off.
683 */
684 eh = (struct ether_header *)buf;
685 eh->ether_type = ntohs((u_short)eh->ether_type);
686#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
687 if (eh->ether_type >= ETHERTYPE_TRAIL &&
688 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
689 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
690 if (off >= ETHERMTU) return; /* sanity */
691 eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
692 resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
693 if (off + resid > len) return; /* sanity */
694 len = off + resid;
695 } else off = 0;
696
697 if (len == 0) return;
698
699 /*
700 * Pull packet off interface. Off is nonzero if packet
701 * has trailing header; neget will then force this header
702 * information to be at the front, but we still have to drop
703 * the type and length which are at the front of any trailer data.
704 */
d3a11a24 705 m = neget(buf, len, off, &ns->arpcom.ac_if);
15637ed4
RG
706 if (m == 0) return;
707
d3a11a24 708 ether_input(&ns->arpcom.ac_if, eh, m);
15637ed4
RG
709}
710
711/*
712 * Supporting routines
713 */
714
715/*
716 * Pull read data off a interface.
717 * Len is length of data, with local net header stripped.
718 * Off is non-zero if a trailer protocol was used, and
719 * gives the offset of the trailer information.
720 * We copy the trailer information and then all the normal
721 * data into mbufs. When full cluster sized units are present
722 * we copy into clusters.
723 */
724struct mbuf *
725neget(buf, totlen, off0, ifp)
726 caddr_t buf;
727 int totlen, off0;
728 struct ifnet *ifp;
729{
730 struct mbuf *top, **mp, *m, *p;
731 int off = off0, len;
732 register caddr_t cp = buf;
733 char *epkt;
734
735 buf += sizeof(struct ether_header);
736 cp = buf;
737 epkt = cp + totlen;
738
739
740 if (off) {
741 cp += off + 2 * sizeof(u_short);
742 totlen -= 2 * sizeof(u_short);
743 }
744
745 MGETHDR(m, M_DONTWAIT, MT_DATA);
746 if (m == 0)
747 return (0);
748 m->m_pkthdr.rcvif = ifp;
749 m->m_pkthdr.len = totlen;
750 m->m_len = MHLEN;
751
752 top = 0;
753 mp = &top;
754 while (totlen > 0) {
755 if (top) {
756 MGET(m, M_DONTWAIT, MT_DATA);
757 if (m == 0) {
758 m_freem(top);
759 return (0);
760 }
761 m->m_len = MLEN;
762 }
763 len = min(totlen, epkt - cp);
764 if (len >= MINCLSIZE) {
765 MCLGET(m, M_DONTWAIT);
766 if (m->m_flags & M_EXT)
767 m->m_len = len = min(len, MCLBYTES);
768 else
769 len = m->m_len;
770 } else {
771 /*
772 * Place initial small packet/header at end of mbuf.
773 */
774 if (len < m->m_len) {
775 if (top == 0 && len + max_linkhdr <= m->m_len)
776 m->m_data += max_linkhdr;
777 m->m_len = len;
778 } else
779 len = m->m_len;
780 }
781 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
782 cp += len;
783 *mp = m;
784 mp = &m->m_next;
785 totlen -= len;
786 if (cp == epkt)
787 cp = buf;
788 }
789 return (top);
790}
791
792/*
793 * Process an ioctl request.
794 */
795neioctl(ifp, cmd, data)
796 register struct ifnet *ifp;
797 int cmd;
798 caddr_t data;
799{
800 register struct ifaddr *ifa = (struct ifaddr *)data;
801 struct ne_softc *ns = &ne_softc[ifp->if_unit];
802 struct ifreq *ifr = (struct ifreq *)data;
803 int s = splimp(), error = 0;
804
805
806 switch (cmd) {
807
808 case SIOCSIFADDR:
809 ifp->if_flags |= IFF_UP;
810
811 switch (ifa->ifa_addr->sa_family) {
812#ifdef INET
813 case AF_INET:
814 neinit(ifp->if_unit); /* before arpwhohas */
815 ((struct arpcom *)ifp)->ac_ipaddr =
816 IA_SIN(ifa)->sin_addr;
817 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
818 break;
819#endif
820#ifdef NS
821 case AF_NS:
aa544edf 822 {
15637ed4
RG
823 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
824
825 if (ns_nullhost(*ina))
d3a11a24
RG
826 ina->x_host =
827 *(union ns_host *)(ns->arpcom.ac_enaddr);
15637ed4
RG
828 else {
829 /*
830 * The manual says we can't change the address
831 * while the receiver is armed,
832 * so reset everything
833 */
834 ifp->if_flags &= ~IFF_RUNNING;
835 bcopy((caddr_t)ina->x_host.c_host,
aa544edf 836 (caddr_t)ns->arpcom.ac_enaddr,
d3a11a24 837 sizeof(ns->arpcom.ac_enaddr));
15637ed4
RG
838 }
839 neinit(ifp->if_unit); /* does ne_setaddr() */
840 break;
aa544edf 841 }
15637ed4
RG
842#endif
843 default:
844 neinit(ifp->if_unit);
845 break;
846 }
847 break;
848
849 case SIOCSIFFLAGS:
aa544edf
RG
850 if (((ifp->if_flags & IFF_UP) == 0) &&
851 (ifp->if_flags & IFF_RUNNING)) {
852 outb(ns->ns_iobase+ds_cmd,DSCM_STOP|DSCM_NODMA);
15637ed4 853 ifp->if_flags &= ~IFF_RUNNING;
aa544edf
RG
854 } else {
855 if ((ifp->if_flags & IFF_UP) &&
856 ((ifp->if_flags & IFF_RUNNING) == 0))
857 neinit(ifp->if_unit);
858 }
15637ed4
RG
859 break;
860
861#ifdef notdef
862 case SIOCGHWADDR:
d3a11a24
RG
863 bcopy((caddr_t)ns->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data,
864 sizeof(ns->arpcom.ac_enaddr));
15637ed4
RG
865 break;
866#endif
867
868 default:
869 error = EINVAL;
870 }
871 splx(s);
872 return (error);
873}
874#endif