1 /* $OpenBSD: if_eg.c,v 1.53 2024/08/19 03:08:27 jsg Exp $ */
2 /* $NetBSD: if_eg.c,v 1.26 1996/05/12 23:52:27 mycroft Exp $ */
3
4 /*
5 * Copyright (c) 1993 Dean Huxley <dean@fsa.ca>
6 * All rights reserved.
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 Dean Huxley.
19 * 4. The name of Dean Huxley may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 /*
34 * Support for 3Com 3c505 Etherlink+ card.
35 */
36
37 /* To do:
38 * - multicast
39 * - promiscuous
40 */
41 #include "bpfilter.h"
42
43 #include <sys/param.h>
44 #include <sys/mbuf.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/syslog.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51
52 #include <net/if.h>
53
54 #include <netinet/in.h>
55 #include <netinet/if_ether.h>
56
57 #if NBPFILTER > 0
58 #include <net/bpf.h>
59 #endif
60
61 #include <machine/cpu.h>
62 #include <machine/intr.h>
63
64 #include <dev/isa/isavar.h>
65 #include <dev/isa/if_egreg.h>
66 #include <dev/isa/elink.h>
67
68 /* for debugging convenience */
69 #ifdef EGDEBUG
70 #define DPRINTF(x) printf x
71 #else
72 #define DPRINTF(x)
73 #endif
74
75 #define EG_INLEN 10
76 #define EG_BUFLEN 0x0670
77
78 /*
79 * Ethernet software status per interface.
80 */
81 struct eg_softc {
82 struct device sc_dev;
83 void *sc_ih;
84 bus_space_tag_t sc_bst;
85 bus_space_handle_t sc_bsh;
86 struct arpcom sc_arpcom; /* Ethernet common part */
87 u_char eg_rom_major; /* Cards ROM version (major number) */
88 u_char eg_rom_minor; /* Cards ROM version (minor number) */
89 short eg_ram; /* Amount of RAM on the card */
90 u_char eg_pcb[64]; /* Primary Command Block buffer */
91 u_char eg_incount; /* Number of buffers currently used */
92 u_char *eg_inbuf; /* Incoming packet buffer */
93 u_char *eg_outbuf; /* Outgoing packet buffer */
94 };
95
96 int egprobe(struct device *, void *, void *);
97 void egattach(struct device *, struct device *, void *);
98
99 const struct cfattach eg_ca = {
100 sizeof(struct eg_softc), egprobe, egattach
101 };
102
103 struct cfdriver eg_cd = {
104 NULL, "eg", DV_IFNET
105 };
106
107 int egintr(void *);
108 void eginit(struct eg_softc *);
109 int egioctl(struct ifnet *, u_long, caddr_t);
110 void egrecv(struct eg_softc *);
111 void egstart(struct ifnet *);
112 void egwatchdog(struct ifnet *);
113 void egreset(struct eg_softc *);
114 void egread(struct eg_softc *, caddr_t, int);
115 struct mbuf *egget(struct eg_softc *, caddr_t, int);
116 void egstop(struct eg_softc *);
117
118 static __inline void egprintpcb(struct eg_softc *);
119 static int egoutPCB(struct eg_softc *, u_char);
120 static int egreadPCBstat(struct eg_softc *, u_char);
121 static int egreadPCBready(struct eg_softc *);
122 static int egwritePCB(struct eg_softc *);
123 static int egreadPCB(struct eg_softc *);
124
125 /*
126 * Support stuff
127 */
128
129 static __inline void
egprintpcb(struct eg_softc * sc)130 egprintpcb(struct eg_softc *sc)
131 {
132 int i;
133
134 for (i = 0; i < sc->eg_pcb[1] + 2; i++)
135 DPRINTF(("pcb[%2d] = %x\n", i, sc->eg_pcb[i]));
136 }
137
138
139 static int
egoutPCB(struct eg_softc * sc,u_char b)140 egoutPCB(struct eg_softc *sc, u_char b)
141 {
142 bus_space_tag_t bst = sc->sc_bst;
143 bus_space_handle_t bsh = sc->sc_bsh;
144 int i;
145
146 for (i = 0; i < 4000; i++) {
147 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE) {
148 bus_space_write_1(bst, bsh, EG_COMMAND, b);
149 return 0;
150 }
151 delay(10);
152 }
153 DPRINTF(("egoutPCB failed\n"));
154 return (1);
155 }
156
157 static int
egreadPCBstat(struct eg_softc * sc,u_char statb)158 egreadPCBstat(struct eg_softc *sc, u_char statb)
159 {
160 bus_space_tag_t bst = sc->sc_bst;
161 bus_space_handle_t bsh = sc->sc_bsh;
162 int i;
163
164 for (i=0; i < 5000; i++) {
165 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
166 EG_PCB_NULL)
167 break;
168 delay(10);
169 }
170 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) == statb)
171 return (0);
172 return (1);
173 }
174
175 static int
egreadPCBready(struct eg_softc * sc)176 egreadPCBready(struct eg_softc *sc)
177 {
178 bus_space_tag_t bst = sc->sc_bst;
179 bus_space_handle_t bsh = sc->sc_bsh;
180 int i;
181
182 for (i=0; i < 10000; i++) {
183 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF)
184 return (0);
185 delay(5);
186 }
187 DPRINTF(("PCB read not ready status %02x\n",
188 bus_space_read_1(bst, bsh, EG_STATUS)));
189 return (1);
190 }
191
192 static int
egwritePCB(struct eg_softc * sc)193 egwritePCB(struct eg_softc *sc)
194 {
195 bus_space_tag_t bst = sc->sc_bst;
196 bus_space_handle_t bsh = sc->sc_bsh;
197 int i;
198 u_char len;
199
200 bus_space_write_1(bst, bsh, EG_CONTROL,
201 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
202 EG_PCB_NULL);
203
204 len = sc->eg_pcb[1] + 2;
205 for (i = 0; i < len; i++)
206 egoutPCB(sc, sc->eg_pcb[i]);
207
208 for (i=0; i < 4000; i++) {
209 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HCRE)
210 break;
211 delay(10);
212 }
213
214 bus_space_write_1(bst, bsh, EG_CONTROL,
215 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
216 EG_PCB_DONE);
217
218 egoutPCB(sc, len);
219
220 if (egreadPCBstat(sc, EG_PCB_ACCEPT))
221 return (1);
222 return (0);
223 }
224
225 static int
egreadPCB(struct eg_softc * sc)226 egreadPCB(struct eg_softc *sc)
227 {
228 bus_space_tag_t bst = sc->sc_bst;
229 bus_space_handle_t bsh = sc->sc_bsh;
230 int i;
231 u_char b;
232
233 bus_space_write_1(bst, bsh, EG_CONTROL,
234 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
235 EG_PCB_NULL);
236
237 bzero(sc->eg_pcb, sizeof(sc->eg_pcb));
238
239 if (egreadPCBready(sc))
240 return (1);
241
242 sc->eg_pcb[0] = bus_space_read_1(bst, bsh, EG_COMMAND);
243
244 if (egreadPCBready(sc))
245 return (1);
246
247 sc->eg_pcb[1] = bus_space_read_1(bst, bsh, EG_COMMAND);
248
249 if (sc->eg_pcb[1] > 62) {
250 DPRINTF(("len %d too large\n", sc->eg_pcb[1]));
251 return (1);
252 }
253
254 for (i = 0; i < sc->eg_pcb[1]; i++) {
255 if (egreadPCBready(sc))
256 return (1);
257 sc->eg_pcb[2+i] = bus_space_read_1(bst, bsh, EG_COMMAND);
258 }
259 if (egreadPCBready(sc))
260 return (1);
261 if (egreadPCBstat(sc, EG_PCB_DONE))
262 return (1);
263 if ((b = bus_space_read_1(bst, bsh, EG_COMMAND)) != sc->eg_pcb[1] + 2) {
264 DPRINTF(("%d != %d\n", b, sc->eg_pcb[1] + 2));
265 return (1);
266 }
267
268 bus_space_write_1(bst, bsh, EG_CONTROL,
269 (bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_PCB_STAT) |
270 EG_PCB_ACCEPT);
271
272 return (0);
273 }
274
275 /*
276 * Real stuff
277 */
278
279 int
egprobe(struct device * parent,void * match,void * aux)280 egprobe(struct device *parent, void *match, void *aux)
281 {
282 struct eg_softc *sc = match;
283 struct isa_attach_args *ia = aux;
284 bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
285 bus_space_handle_t bsh;
286 int i;
287
288 if ((ia->ia_iobase & ~0x07f0) != 0) {
289 DPRINTF(("Weird iobase %x\n", ia->ia_iobase));
290 return (0);
291 }
292
293 if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
294 DPRINTF(("%s: can't map i/o space\n", sc->sc_dev.dv_xname));
295 return (0);
296 }
297 sc->sc_bsh = bsh;
298
299 /* hard reset card */
300 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_RESET);
301 bus_space_write_1(bst, bsh, EG_CONTROL, 0);
302 for (i = 0; i < 5000; i++) {
303 delay(1000);
304 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) ==
305 EG_PCB_NULL)
306 break;
307 }
308 if ((bus_space_read_1(bst, bsh, EG_STATUS) & EG_PCB_STAT) !=
309 EG_PCB_NULL) {
310 DPRINTF(("eg: Reset failed\n"));
311 goto lose;
312 }
313 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
314 sc->eg_pcb[1] = 0;
315 if (egwritePCB(sc) != 0)
316 goto lose;
317
318 if (egreadPCB(sc) != 0) {
319 egprintpcb(sc);
320 goto lose;
321 }
322
323 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
324 sc->eg_pcb[1] != 0x0a) {
325 egprintpcb(sc);
326 goto lose;
327 }
328 sc->eg_rom_major = sc->eg_pcb[3];
329 sc->eg_rom_minor = sc->eg_pcb[2];
330 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
331
332 ia->ia_iosize = 0x08;
333 ia->ia_msize = 0;
334 bus_space_unmap(bst, bsh, EG_IO_PORTS);
335 return (1);
336
337 lose:
338 bus_space_unmap(bst, bsh, EG_IO_PORTS);
339 return (0);
340 }
341
342 void
egattach(struct device * parent,struct device * self,void * aux)343 egattach(struct device *parent, struct device *self, void *aux)
344 {
345 struct eg_softc *sc = (void *)self;
346 struct isa_attach_args *ia = aux;
347 bus_space_tag_t bst = sc->sc_bst = ia->ia_iot;
348 bus_space_handle_t bsh;
349 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
350
351 if (bus_space_map(bst, ia->ia_iobase, EG_IO_PORTS, 0, &bsh)) {
352 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
353 return;
354 }
355 sc->sc_bsh = bsh;
356
357 egstop(sc);
358
359 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
360 sc->eg_pcb[1] = 0;
361 if (egwritePCB(sc) != 0) {
362 DPRINTF(("write error\n"));
363 return;
364 }
365 if (egreadPCB(sc) != 0) {
366 DPRINTF(("read error\n"));
367 egprintpcb(sc);
368 return;
369 }
370
371 /* check Get station address response */
372 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
373 DPRINTF(("parse error\n"));
374 egprintpcb(sc);
375 return;
376 }
377 bcopy(&sc->eg_pcb[2], sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
378
379 printf(": ROM v%d.%02d %dk address %s\n",
380 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
381 ether_sprintf(sc->sc_arpcom.ac_enaddr));
382
383 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
384 if (egwritePCB(sc) != 0) {
385 DPRINTF(("write error2\n"));
386 return;
387 }
388 if (egreadPCB(sc) != 0) {
389 DPRINTF(("read error2\n"));
390 egprintpcb(sc);
391 return;
392 }
393 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
394 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
395 DPRINTF(("parse error2\n"));
396 egprintpcb(sc);
397 return;
398 }
399
400 /* Initialize ifnet structure. */
401 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
402 ifp->if_softc = sc;
403 ifp->if_start = egstart;
404 ifp->if_ioctl = egioctl;
405 ifp->if_watchdog = egwatchdog;
406 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
407
408 /* Now we can attach the interface. */
409 if_attach(ifp);
410 ether_ifattach(ifp);
411
412 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
413 IPL_NET, egintr, sc, sc->sc_dev.dv_xname);
414 }
415
416 void
eginit(register struct eg_softc * sc)417 eginit(register struct eg_softc *sc)
418 {
419 bus_space_tag_t bst = sc->sc_bst;
420 bus_space_handle_t bsh = sc->sc_bsh;
421 register struct ifnet *ifp = &sc->sc_arpcom.ac_if;
422
423 /* soft reset the board */
424 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_FLSH);
425 delay(100);
426 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_ATTN);
427 delay(100);
428 bus_space_write_1(bst, bsh, EG_CONTROL, 0);
429 delay(200);
430
431 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
432 sc->eg_pcb[1] = 2;
433 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
434 sc->eg_pcb[3] = 0;
435 if (egwritePCB(sc) != 0)
436 DPRINTF(("write error3\n"));
437
438 if (egreadPCB(sc) != 0) {
439 DPRINTF(("read error3\n"));
440 egprintpcb(sc);
441 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
442 printf("%s: configure card command failed\n",
443 sc->sc_dev.dv_xname);
444
445 if (sc->eg_inbuf == NULL)
446 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
447 sc->eg_incount = 0;
448
449 if (sc->eg_outbuf == NULL)
450 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
451
452 bus_space_write_1(bst, bsh, EG_CONTROL, EG_CTL_CMDE);
453
454 sc->eg_incount = 0;
455 egrecv(sc);
456
457 /* Interface is now `running', with no output active. */
458 ifp->if_flags |= IFF_RUNNING;
459 ifq_clr_oactive(&ifp->if_snd);
460
461 /* Attempt to start output, if any. */
462 egstart(ifp);
463 }
464
465 void
egrecv(struct eg_softc * sc)466 egrecv(struct eg_softc *sc)
467 {
468 while (sc->eg_incount < EG_INLEN) {
469 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
470 sc->eg_pcb[1] = 0x08;
471 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
472 sc->eg_pcb[3] = 0;
473 sc->eg_pcb[4] = 0;
474 sc->eg_pcb[5] = 0;
475 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
476 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
477 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
478 sc->eg_pcb[9] = 0;
479 if (egwritePCB(sc) != 0)
480 break;
481 sc->eg_incount++;
482 }
483 }
484
485 void
egstart(struct ifnet * ifp)486 egstart(struct ifnet *ifp)
487 {
488 struct eg_softc *sc = ifp->if_softc;
489 bus_space_tag_t bst = sc->sc_bst;
490 bus_space_handle_t bsh = sc->sc_bsh;
491 struct mbuf *m0, *m;
492 caddr_t buffer;
493 int len;
494 u_short *ptr;
495 u_int i;
496
497 /* Don't transmit if interface is busy or not running */
498 if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
499 return;
500
501 loop:
502 /* Dequeue the next datagram. */
503 m0 = ifq_dequeue(&ifp->if_snd);
504 if (m0 == NULL)
505 return;
506
507 ifq_set_oactive(&ifp->if_snd);
508
509 /* We need to use m->m_pkthdr.len, so require the header */
510 if ((m0->m_flags & M_PKTHDR) == 0)
511 panic("egstart: no header mbuf");
512 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
513
514 #if NBPFILTER > 0
515 if (ifp->if_bpf)
516 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
517 #endif
518
519 sc->eg_pcb[0] = EG_CMD_SENDPACKET;
520 sc->eg_pcb[1] = 0x06;
521 sc->eg_pcb[2] = 0; /* address not used, we send zero */
522 sc->eg_pcb[3] = 0;
523 sc->eg_pcb[4] = 0;
524 sc->eg_pcb[5] = 0;
525 sc->eg_pcb[6] = len; /* length of packet */
526 sc->eg_pcb[7] = len >> 8;
527 if (egwritePCB(sc) != 0) {
528 DPRINTF(("egwritePCB in egstart failed\n"));
529 ifp->if_oerrors++;
530 ifq_clr_oactive(&ifp->if_snd);
531 m_freem(m0);
532 goto loop;
533 }
534
535 buffer = sc->eg_outbuf;
536 for (m = m0; m != 0; m = m->m_next) {
537 bcopy(mtod(m, caddr_t), buffer, m->m_len);
538 buffer += m->m_len;
539 }
540 if (len > m0->m_pkthdr.len)
541 bzero(buffer, len - m0->m_pkthdr.len);
542
543 /* set direction bit: host -> adapter */
544 bus_space_write_1(bst, bsh, EG_CONTROL,
545 bus_space_read_1(bst, bsh, EG_CONTROL) & ~EG_CTL_DIR);
546
547 for (ptr = (u_short *)sc->eg_outbuf; len > 0; len -= 2) {
548 bus_space_write_2(bst, bsh, EG_DATA, *ptr++);
549 for (i = 10000; i != 0; i--) {
550 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
551 break;
552 delay(10);
553 }
554 if (i == 0) {
555 printf("%s: start failed\n", sc->sc_dev.dv_xname);
556 break;
557 }
558 }
559
560 m_freem(m0);
561 }
562
563 int
egintr(void * arg)564 egintr(void *arg)
565 {
566 struct eg_softc *sc = arg;
567 bus_space_tag_t bst = sc->sc_bst;
568 bus_space_handle_t bsh = sc->sc_bsh;
569 int ret = 0;
570 int i, len;
571 u_short *ptr;
572
573 while (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_ACRF) {
574 ret = 1;
575 egreadPCB(sc);
576 switch (sc->eg_pcb[0]) {
577 case EG_RSP_RECVPACKET:
578 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
579
580 /* Set direction bit : Adapter -> host */
581 bus_space_write_1(bst, bsh, EG_CONTROL,
582 bus_space_read_1(bst, bsh, EG_CONTROL) |
583 EG_CTL_DIR);
584
585 for (ptr = (u_short *)sc->eg_inbuf; len > 0; len -= 2) {
586 for (i = 10000; i != 0; i--) {
587 if (bus_space_read_1(bst, bsh, EG_STATUS) & EG_STAT_HRDY)
588 break;
589 delay(10);
590 }
591 if (i == 0) {
592 printf("%s: receive failed\n",
593 sc->sc_dev.dv_xname);
594 break;
595 }
596 *ptr++ = bus_space_read_2(bst, bsh, EG_DATA);
597 }
598
599 if (len <= 0) {
600 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
601 egread(sc, sc->eg_inbuf, len);
602
603 sc->eg_incount--;
604 egrecv(sc);
605 }
606 break;
607
608 case EG_RSP_SENDPACKET:
609 if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
610 DPRINTF(("packet dropped\n"));
611 sc->sc_arpcom.ac_if.if_oerrors++;
612 }
613 sc->sc_arpcom.ac_if.if_collisions +=
614 sc->eg_pcb[8] & 0xf;
615 ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
616 egstart(&sc->sc_arpcom.ac_if);
617 break;
618
619 case EG_RSP_GETSTATS:
620 DPRINTF(("Card Statistics\n"));
621 bcopy(&sc->eg_pcb[2], &i, sizeof(i));
622 DPRINTF(("Receive Packets %d\n", i));
623 bcopy(&sc->eg_pcb[6], &i, sizeof(i));
624 DPRINTF(("Transmit Packets %d\n", i));
625 DPRINTF(("CRC errors %d\n", *(short *)&sc->eg_pcb[10]));
626 DPRINTF(("alignment errors %d\n",
627 *(short *)&sc->eg_pcb[12]));
628 DPRINTF(("no resources errors %d\n",
629 *(short *)&sc->eg_pcb[14]));
630 DPRINTF(("overrun errors %d\n",
631 *(short *)&sc->eg_pcb[16]));
632 break;
633
634 default:
635 DPRINTF(("egintr: Unknown response %x??\n",
636 sc->eg_pcb[0]));
637 egprintpcb(sc);
638 break;
639 }
640 }
641
642 return (ret);
643 }
644
645 /*
646 * Pass a packet up to the higher levels.
647 */
648 void
egread(struct eg_softc * sc,caddr_t buf,int len)649 egread(struct eg_softc *sc, caddr_t buf, int len)
650 {
651 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
652 struct mbuf_list ml = MBUF_LIST_INITIALIZER();
653 struct mbuf *m;
654
655 if (len <= sizeof(struct ether_header) ||
656 len > ETHER_MAX_LEN) {
657 printf("%s: invalid packet size %d; dropping\n",
658 sc->sc_dev.dv_xname, len);
659 ifp->if_ierrors++;
660 return;
661 }
662
663 /* Pull packet off interface. */
664 m = egget(sc, buf, len);
665 if (m == NULL) {
666 ifp->if_ierrors++;
667 return;
668 }
669
670 ml_enqueue(&ml, m);
671 if_input(ifp, &ml);
672 }
673
674 /*
675 * convert buf into mbufs
676 */
677 struct mbuf *
egget(struct eg_softc * sc,caddr_t buf,int totlen)678 egget(struct eg_softc *sc, caddr_t buf, int totlen)
679 {
680 struct mbuf *top, **mp, *m;
681 int len;
682
683 MGETHDR(m, M_DONTWAIT, MT_DATA);
684 if (m == NULL)
685 return (0);
686 m->m_pkthdr.len = totlen;
687 len = MHLEN;
688 top = 0;
689 mp = ⊤
690
691 while (totlen > 0) {
692 if (top) {
693 MGET(m, M_DONTWAIT, MT_DATA);
694 if (m == NULL) {
695 m_freem(top);
696 return (0);
697 }
698 len = MLEN;
699 }
700 if (totlen >= MINCLSIZE) {
701 MCLGET(m, M_DONTWAIT);
702 if (m->m_flags & M_EXT)
703 len = MCLBYTES;
704 }
705 m->m_len = len = min(totlen, len);
706 bcopy((caddr_t)buf, mtod(m, caddr_t), len);
707 buf += len;
708 totlen -= len;
709 *mp = m;
710 mp = &m->m_next;
711 }
712
713 return (top);
714 }
715
716 int
egioctl(register struct ifnet * ifp,u_long cmd,caddr_t data)717 egioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
718 {
719 struct eg_softc *sc = ifp->if_softc;
720 int s, error = 0;
721
722 s = splnet();
723
724 switch (cmd) {
725 case SIOCSIFADDR:
726 ifp->if_flags |= IFF_UP;
727 eginit(sc);
728 break;
729
730 case SIOCSIFFLAGS:
731 if ((ifp->if_flags & IFF_UP) == 0 &&
732 (ifp->if_flags & IFF_RUNNING) != 0) {
733 /*
734 * If interface is marked down and it is running, then
735 * stop it.
736 */
737 egstop(sc);
738 ifp->if_flags &= ~IFF_RUNNING;
739 } else if ((ifp->if_flags & IFF_UP) != 0 &&
740 (ifp->if_flags & IFF_RUNNING) == 0) {
741 /*
742 * If interface is marked up and it is stopped, then
743 * start it.
744 */
745 eginit(sc);
746 } else {
747 sc->eg_pcb[0] = EG_CMD_GETSTATS;
748 sc->eg_pcb[1] = 0;
749 if (egwritePCB(sc) != 0)
750 DPRINTF(("write error\n"));
751 /*
752 * XXX deal with flags changes:
753 * IFF_MULTICAST, IFF_PROMISC,
754 * IFF_LINK0, IFF_LINK1,
755 */
756 }
757 break;
758
759 default:
760 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
761 }
762
763 splx(s);
764 return (error);
765 }
766
767 void
egreset(struct eg_softc * sc)768 egreset(struct eg_softc *sc)
769 {
770 int s;
771
772 DPRINTF(("egreset()\n"));
773 s = splnet();
774 egstop(sc);
775 eginit(sc);
776 splx(s);
777 }
778
779 void
egwatchdog(struct ifnet * ifp)780 egwatchdog(struct ifnet *ifp)
781 {
782 struct eg_softc *sc = ifp->if_softc;
783
784 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
785 sc->sc_arpcom.ac_if.if_oerrors++;
786
787 egreset(sc);
788 }
789
790 void
egstop(register struct eg_softc * sc)791 egstop(register struct eg_softc *sc)
792 {
793 bus_space_tag_t bst = sc->sc_bst;
794 bus_space_handle_t bsh = sc->sc_bsh;
795
796 bus_space_write_1(bst, bsh, EG_CONTROL, 0);
797 }
798