if_eg.c revision 1.69 1 /* $NetBSD: if_eg.c,v 1.69 2006/10/04 15:51:49 christos Exp $ */
2
3 /*
4 * Copyright (c) 1993 Dean Huxley <dean (at) fsa.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Dean Huxley.
18 * 4. The name of Dean Huxley may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * Support for 3Com 3c505 Etherlink+ card.
34 */
35
36 /*
37 * To do:
38 * - multicast
39 * - promiscuous
40 */
41
42 #include <sys/cdefs.h>
43 __KERNEL_RCSID(0, "$NetBSD: if_eg.c,v 1.69 2006/10/04 15:51:49 christos Exp $");
44
45 #include "opt_inet.h"
46 #include "bpfilter.h"
47 #include "rnd.h"
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/ioctl.h>
54 #include <sys/errno.h>
55 #include <sys/syslog.h>
56 #include <sys/select.h>
57 #include <sys/device.h>
58 #if NRND > 0
59 #include <sys/rnd.h>
60 #endif
61
62 #include <net/if.h>
63 #include <net/if_dl.h>
64 #include <net/if_types.h>
65
66 #include <net/if_ether.h>
67
68 #ifdef INET
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in_var.h>
72 #include <netinet/ip.h>
73 #include <netinet/if_inarp.h>
74 #endif
75
76
77 #if NBPFILTER > 0
78 #include <net/bpf.h>
79 #include <net/bpfdesc.h>
80 #endif
81
82 #include <machine/cpu.h>
83 #include <machine/intr.h>
84 #include <machine/bus.h>
85
86 #include <dev/isa/isavar.h>
87 #include <dev/isa/if_egreg.h>
88 #include <dev/isa/elink.h>
89
90 /* for debugging convenience */
91 #ifdef EGDEBUG
92 #define DPRINTF(x) printf x
93 #else
94 #define DPRINTF(x)
95 #endif
96
97 #define EG_INLEN 10
98 #define EG_BUFLEN 0x0670
99
100 #define EG_PCBLEN 64
101
102 /*
103 * Ethernet software status per interface.
104 */
105 struct eg_softc {
106 struct device sc_dev;
107 void *sc_ih;
108 struct ethercom sc_ethercom; /* Ethernet common part */
109 bus_space_tag_t sc_iot; /* bus space identifier */
110 bus_space_handle_t sc_ioh; /* i/o handle */
111 u_int8_t eg_rom_major; /* Cards ROM version (major number) */
112 u_int8_t eg_rom_minor; /* Cards ROM version (minor number) */
113 short eg_ram; /* Amount of RAM on the card */
114 u_int8_t eg_pcb[EG_PCBLEN]; /* Primary Command Block buffer */
115 u_int8_t eg_incount; /* Number of buffers currently used */
116 caddr_t eg_inbuf; /* Incoming packet buffer */
117 caddr_t eg_outbuf; /* Outgoing packet buffer */
118
119 #if NRND > 0
120 rndsource_element_t rnd_source;
121 #endif
122 };
123
124 int egprobe(struct device *, struct cfdata *, void *);
125 void egattach(struct device *, struct device *, void *);
126
127 CFATTACH_DECL(eg, sizeof(struct eg_softc),
128 egprobe, egattach, NULL, NULL);
129
130 int egintr(void *);
131 void eginit(struct eg_softc *);
132 int egioctl(struct ifnet *, u_long, caddr_t);
133 void egrecv(struct eg_softc *);
134 void egstart(struct ifnet *);
135 void egwatchdog(struct ifnet *);
136 void egreset(struct eg_softc *);
137 void egread(struct eg_softc *, caddr_t, int);
138 struct mbuf *egget(struct eg_softc *, caddr_t, int);
139 void egstop(struct eg_softc *);
140
141 static inline void egprintpcb(u_int8_t *);
142 static inline void egprintstat(u_char);
143 static int egoutPCB(bus_space_tag_t, bus_space_handle_t, u_int8_t);
144 static int egreadPCBstat(bus_space_tag_t, bus_space_handle_t, u_int8_t);
145 static int egreadPCBready(bus_space_tag_t, bus_space_handle_t);
146 static int egwritePCB(bus_space_tag_t, bus_space_handle_t, u_int8_t *);
147 static int egreadPCB(bus_space_tag_t, bus_space_handle_t, u_int8_t *);
148
149 /*
150 * Support stuff
151 */
152
153 static inline void
154 egprintpcb(pcb)
155 u_int8_t *pcb;
156 {
157 int i;
158
159 for (i = 0; i < pcb[1] + 2; i++)
160 DPRINTF(("pcb[%2d] = %x\n", i, pcb[i]));
161 }
162
163
164 static inline void
165 egprintstat(b)
166 u_char b;
167 {
168 DPRINTF(("%s %s %s %s %s %s %s\n",
169 (b & EG_STAT_HCRE)?"HCRE":"",
170 (b & EG_STAT_ACRF)?"ACRF":"",
171 (b & EG_STAT_DIR )?"DIR ":"",
172 (b & EG_STAT_DONE)?"DONE":"",
173 (b & EG_STAT_ASF3)?"ASF3":"",
174 (b & EG_STAT_ASF2)?"ASF2":"",
175 (b & EG_STAT_ASF1)?"ASF1":""));
176 }
177
178 static int
179 egoutPCB(iot, ioh, b)
180 bus_space_tag_t iot;
181 bus_space_handle_t ioh;
182 u_int8_t b;
183 {
184 int i;
185
186 for (i=0; i < 4000; i++) {
187 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) {
188 bus_space_write_1(iot, ioh, EG_COMMAND, b);
189 return 0;
190 }
191 delay(10);
192 }
193 DPRINTF(("egoutPCB failed\n"));
194 return 1;
195 }
196
197 static int
198 egreadPCBstat(iot, ioh, statb)
199 bus_space_tag_t iot;
200 bus_space_handle_t ioh;
201 u_int8_t statb;
202 {
203 int i;
204
205 for (i=0; i < 5000; i++) {
206 if ((bus_space_read_1(iot, ioh, EG_STATUS) &
207 EG_PCB_STAT) != EG_PCB_NULL)
208 break;
209 delay(10);
210 }
211 if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) == statb)
212 return 0;
213 return 1;
214 }
215
216 static int
217 egreadPCBready(iot, ioh)
218 bus_space_tag_t iot;
219 bus_space_handle_t ioh;
220 {
221 int i;
222
223 for (i=0; i < 10000; i++) {
224 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF)
225 return 0;
226 delay(5);
227 }
228 DPRINTF(("PCB read not ready\n"));
229 return 1;
230 }
231
232 static int
233 egwritePCB(iot, ioh, pcb)
234 bus_space_tag_t iot;
235 bus_space_handle_t ioh;
236 u_int8_t *pcb;
237 {
238 int i;
239 u_int8_t len;
240
241 bus_space_write_1(iot, ioh, EG_CONTROL,
242 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
243
244 len = pcb[1] + 2;
245 for (i = 0; i < len; i++)
246 egoutPCB(iot, ioh, pcb[i]);
247
248 for (i=0; i < 4000; i++) {
249 if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE)
250 break;
251 delay(10);
252 }
253
254 bus_space_write_1(iot, ioh, EG_CONTROL,
255 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_DONE);
256
257 egoutPCB(iot, ioh, len);
258
259 if (egreadPCBstat(iot, ioh, EG_PCB_ACCEPT))
260 return 1;
261 return 0;
262 }
263
264 static int
265 egreadPCB(iot, ioh, pcb)
266 bus_space_tag_t iot;
267 bus_space_handle_t ioh;
268 u_int8_t *pcb;
269 {
270 int i;
271
272 bus_space_write_1(iot, ioh, EG_CONTROL,
273 (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
274
275 memset(pcb, 0, EG_PCBLEN);
276
277 if (egreadPCBready(iot, ioh))
278 return 1;
279
280 pcb[0] = bus_space_read_1(iot, ioh, EG_COMMAND);
281
282 if (egreadPCBready(iot, ioh))
283 return 1;
284
285 pcb[1] = bus_space_read_1(iot, ioh, EG_COMMAND);
286
287 if (pcb[1] > 62) {
288 DPRINTF(("len %d too large\n", pcb[1]));
289 return 1;
290 }
291
292 for (i = 0; i < pcb[1]; i++) {
293 if (egreadPCBready(iot, ioh))
294 return 1;
295 pcb[2+i] = bus_space_read_1(iot, ioh, EG_COMMAND);
296 }
297 if (egreadPCBready(iot, ioh))
298 return 1;
299 if (egreadPCBstat(iot, ioh, EG_PCB_DONE))
300 return 1;
301 if (bus_space_read_1(iot, ioh, EG_COMMAND) != pcb[1] + 2) {
302 return 1;
303 }
304
305 bus_space_write_1(iot, ioh, EG_CONTROL,
306 (bus_space_read_1(iot, ioh, EG_CONTROL) &
307 ~EG_PCB_STAT) | EG_PCB_ACCEPT);
308
309 return 0;
310 }
311
312 /*
313 * Real stuff
314 */
315
316 int
317 egprobe(parent, match, aux)
318 struct device *parent;
319 struct cfdata *match;
320 void *aux;
321 {
322 struct isa_attach_args *ia = aux;
323 bus_space_tag_t iot = ia->ia_iot;
324 bus_space_handle_t ioh;
325 int i, rval;
326 static u_int8_t pcb[EG_PCBLEN];
327
328 rval = 0;
329
330 if (ia->ia_nio < 1)
331 return (0);
332 if (ia->ia_nirq < 1)
333 return (0);
334
335 if (ISA_DIRECT_CONFIG(ia))
336 return (0);
337
338 /* Disallow wildcarded i/o address. */
339 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
340 return (0);
341
342 /* Disallow wildcarded IRQ. */
343 if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ)
344 return (0);
345
346 if ((ia->ia_io[0].ir_addr & ~0x07f0) != 0) {
347 DPRINTF(("Weird iobase %x\n", ia->ia_io[0].ir_addr));
348 return 0;
349 }
350
351 /* Map i/o space. */
352 if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
353 DPRINTF(("egprobe: can't map i/o space in probe\n"));
354 return 0;
355 }
356
357 /* hard reset card */
358 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_RESET);
359 bus_space_write_1(iot, ioh, EG_CONTROL, 0);
360 for (i = 0; i < 5000; i++) {
361 delay(1000);
362 if ((bus_space_read_1(iot, ioh, EG_STATUS) &
363 EG_PCB_STAT) == EG_PCB_NULL)
364 break;
365 }
366 if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) != EG_PCB_NULL) {
367 DPRINTF(("egprobe: Reset failed\n"));
368 goto out;
369 }
370 pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
371 pcb[1] = 0;
372 if (egwritePCB(iot, ioh, pcb) != 0)
373 goto out;
374
375 if ((egreadPCB(iot, ioh, pcb) != 0) ||
376 pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
377 pcb[1] != 0x0a) {
378 egprintpcb(pcb);
379 goto out;
380 }
381
382 ia->ia_nio = 1;
383 ia->ia_io[0].ir_size = 0x08;
384
385 ia->ia_nirq = 1;
386
387 ia->ia_niomem = 0;
388 ia->ia_ndrq = 0;
389
390 rval = 1;
391
392 out:
393 bus_space_unmap(iot, ioh, 0x08);
394 return rval;
395 }
396
397 void
398 egattach(parent, self, aux)
399 struct device *parent, *self;
400 void *aux;
401 {
402 struct eg_softc *sc = (void *)self;
403 struct isa_attach_args *ia = aux;
404 bus_space_tag_t iot = ia->ia_iot;
405 bus_space_handle_t ioh;
406 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
407 u_int8_t myaddr[ETHER_ADDR_LEN];
408
409 printf("\n");
410
411 /* Map i/o space. */
412 if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
413 printf("%s: can't map i/o space\n", self->dv_xname);
414 return;
415 }
416
417 sc->sc_iot = iot;
418 sc->sc_ioh = ioh;
419
420 sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
421 sc->eg_pcb[1] = 0;
422 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
423 printf("%s: error requesting adapter info\n", self->dv_xname);
424 return;
425 }
426 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
427 egprintpcb(sc->eg_pcb);
428 printf("%s: error reading adapter info\n", self->dv_xname);
429 return;
430 }
431
432 if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
433 sc->eg_pcb[1] != 0x0a) {
434 egprintpcb(sc->eg_pcb);
435 printf("%s: bogus adapter info\n", self->dv_xname);
436 return;
437 }
438
439 sc->eg_rom_major = sc->eg_pcb[3];
440 sc->eg_rom_minor = sc->eg_pcb[2];
441 sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
442
443 egstop(sc);
444
445 sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
446 sc->eg_pcb[1] = 0;
447 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
448 printf("%s: can't send Get Station Address\n", self->dv_xname);
449 return;
450 }
451 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
452 printf("%s: can't read station address\n", self->dv_xname);
453 egprintpcb(sc->eg_pcb);
454 return;
455 }
456
457 /* check Get station address response */
458 if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
459 printf("%s: card responded with garbage (1)\n",
460 self->dv_xname);
461 egprintpcb(sc->eg_pcb);
462 return;
463 }
464 memcpy(myaddr, &sc->eg_pcb[2], ETHER_ADDR_LEN);
465
466 printf("%s: ROM v%d.%02d %dk address %s\n", self->dv_xname,
467 sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
468 ether_sprintf(myaddr));
469
470 sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
471 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
472 printf("%s: can't send Set Station Address\n", self->dv_xname);
473 return;
474 }
475 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
476 printf("%s: can't read Set Station Address status\n",
477 self->dv_xname);
478 egprintpcb(sc->eg_pcb);
479 return;
480 }
481 if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
482 sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
483 printf("%s: card responded with garbage (2)\n",
484 self->dv_xname);
485 egprintpcb(sc->eg_pcb);
486 return;
487 }
488
489 /* Initialize ifnet structure. */
490 strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
491 ifp->if_softc = sc;
492 ifp->if_start = egstart;
493 ifp->if_ioctl = egioctl;
494 ifp->if_watchdog = egwatchdog;
495 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
496 IFQ_SET_READY(&ifp->if_snd);
497
498 /* Now we can attach the interface. */
499 if_attach(ifp);
500 ether_ifattach(ifp, myaddr);
501
502 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
503 IST_EDGE, IPL_NET, egintr, sc);
504
505 #if NRND > 0
506 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
507 RND_TYPE_NET, 0);
508 #endif
509 }
510
511 void
512 eginit(sc)
513 struct eg_softc *sc;
514 {
515 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
516 bus_space_tag_t iot = sc->sc_iot;
517 bus_space_handle_t ioh = sc->sc_ioh;
518
519 /* soft reset the board */
520 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_FLSH);
521 delay(100);
522 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_ATTN);
523 delay(100);
524 bus_space_write_1(iot, ioh, EG_CONTROL, 0);
525 delay(200);
526
527 sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
528 sc->eg_pcb[1] = 2;
529 sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
530 sc->eg_pcb[3] = 0;
531 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0)
532 printf("%s: can't send Configure 82586\n",
533 sc->sc_dev.dv_xname);
534
535 if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
536 printf("%s: can't read Configure 82586 status\n",
537 sc->sc_dev.dv_xname);
538 egprintpcb(sc->eg_pcb);
539 } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
540 printf("%s: configure card command failed\n",
541 sc->sc_dev.dv_xname);
542
543 if (sc->eg_inbuf == NULL) {
544 sc->eg_inbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
545 if (sc->eg_inbuf == NULL) {
546 printf("%s: can't allocate inbuf\n",
547 sc->sc_dev.dv_xname);
548 panic("eginit");
549 }
550 }
551 sc->eg_incount = 0;
552
553 if (sc->eg_outbuf == NULL) {
554 sc->eg_outbuf = malloc(EG_BUFLEN, M_TEMP, M_NOWAIT);
555 if (sc->eg_outbuf == NULL) {
556 printf("%s: can't allocate outbuf\n",
557 sc->sc_dev.dv_xname);
558 panic("eginit");
559 }
560 }
561
562 bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_CMDE);
563
564 sc->eg_incount = 0;
565 egrecv(sc);
566
567 /* Interface is now `running', with no output active. */
568 ifp->if_flags |= IFF_RUNNING;
569 ifp->if_flags &= ~IFF_OACTIVE;
570
571 /* Attempt to start output, if any. */
572 egstart(ifp);
573 }
574
575 void
576 egrecv(sc)
577 struct eg_softc *sc;
578 {
579
580 while (sc->eg_incount < EG_INLEN) {
581 sc->eg_pcb[0] = EG_CMD_RECVPACKET;
582 sc->eg_pcb[1] = 0x08;
583 sc->eg_pcb[2] = 0; /* address not used.. we send zero */
584 sc->eg_pcb[3] = 0;
585 sc->eg_pcb[4] = 0;
586 sc->eg_pcb[5] = 0;
587 sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
588 sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
589 sc->eg_pcb[8] = 0; /* timeout, 0 == none */
590 sc->eg_pcb[9] = 0;
591 if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0)
592 break;
593 sc->eg_incount++;
594 }
595 }
596
597 void
598 egstart(ifp)
599 struct ifnet *ifp;
600 {
601 struct eg_softc *sc = ifp->if_softc;
602 bus_space_tag_t iot = sc->sc_iot;
603 bus_space_handle_t ioh = sc->sc_ioh;
604 struct mbuf *m0, *m;
605 caddr_t buffer;
606 int len;
607 u_int16_t *ptr;
608
609 /* Don't transmit if interface is busy or not running */
610 if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
611 return;
612
613 loop:
614 /* Dequeue the next datagram. */
615 IFQ_DEQUEUE(&ifp->if_snd, m0);
616 if (m0 == 0)
617 return;
618
619 ifp->if_flags |= IFF_OACTIVE;
620
621 /* We need to use m->m_pkthdr.len, so require the header */
622 if ((m0->m_flags & M_PKTHDR) == 0) {
623 printf("%s: no header mbuf\n", sc->sc_dev.dv_xname);
624 panic("egstart");
625 }
626 len = max(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
627
628 #if NBPFILTER > 0
629 if (ifp->if_bpf)
630 bpf_mtap(ifp->if_bpf, m0);
631 #endif
632
633 sc->eg_pcb[0] = EG_CMD_SENDPACKET;
634 sc->eg_pcb[1] = 0x06;
635 sc->eg_pcb[2] = 0; /* address not used, we send zero */
636 sc->eg_pcb[3] = 0;
637 sc->eg_pcb[4] = 0;
638 sc->eg_pcb[5] = 0;
639 sc->eg_pcb[6] = len; /* length of packet */
640 sc->eg_pcb[7] = len >> 8;
641 if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
642 printf("%s: can't send Send Packet command\n",
643 sc->sc_dev.dv_xname);
644 ifp->if_oerrors++;
645 ifp->if_flags &= ~IFF_OACTIVE;
646 m_freem(m0);
647 goto loop;
648 }
649
650 buffer = sc->eg_outbuf;
651 for (m = m0; m != 0; m = m->m_next) {
652 memcpy(buffer, mtod(m, caddr_t), m->m_len);
653 buffer += m->m_len;
654 }
655 if (len > m0->m_pkthdr.len)
656 memset(buffer, 0, len - m0->m_pkthdr.len);
657
658 /* set direction bit: host -> adapter */
659 bus_space_write_1(iot, ioh, EG_CONTROL,
660 bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_CTL_DIR);
661
662 for (ptr = (u_int16_t *) sc->eg_outbuf; len > 0; len -= 2) {
663 bus_space_write_2(iot, ioh, EG_DATA, *ptr++);
664 while (!(bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HRDY))
665 ; /* XXX need timeout here */
666 }
667
668 m_freem(m0);
669 }
670
671 int
672 egintr(arg)
673 void *arg;
674 {
675 struct eg_softc *sc = arg;
676 bus_space_tag_t iot = sc->sc_iot;
677 bus_space_handle_t ioh = sc->sc_ioh;
678 int i, len, serviced;
679 u_int16_t *ptr;
680
681 serviced = 0;
682
683 while (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) {
684 egreadPCB(iot, ioh, sc->eg_pcb);
685 switch (sc->eg_pcb[0]) {
686 case EG_RSP_RECVPACKET:
687 len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
688
689 /* Set direction bit : Adapter -> host */
690 bus_space_write_1(iot, ioh, EG_CONTROL,
691 bus_space_read_1(iot, ioh, EG_CONTROL) | EG_CTL_DIR);
692
693 for (ptr = (u_int16_t *) sc->eg_inbuf;
694 len > 0; len -= 2) {
695 while (!(bus_space_read_1(iot, ioh, EG_STATUS) &
696 EG_STAT_HRDY))
697 ;
698 *ptr++ = bus_space_read_2(iot, ioh, EG_DATA);
699 }
700
701 len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
702 egread(sc, sc->eg_inbuf, len);
703
704 sc->eg_incount--;
705 egrecv(sc);
706 serviced = 1;
707 break;
708
709 case EG_RSP_SENDPACKET:
710 if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
711 DPRINTF(("%s: packet dropped\n",
712 sc->sc_dev.dv_xname));
713 sc->sc_ethercom.ec_if.if_oerrors++;
714 } else
715 sc->sc_ethercom.ec_if.if_opackets++;
716 sc->sc_ethercom.ec_if.if_collisions +=
717 sc->eg_pcb[8] & 0xf;
718 sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE;
719 egstart(&sc->sc_ethercom.ec_if);
720 serviced = 1;
721 break;
722
723 /* XXX byte-order and type-size bugs here... */
724 case EG_RSP_GETSTATS:
725 DPRINTF(("%s: Card Statistics\n",
726 sc->sc_dev.dv_xname));
727 memcpy(&i, &sc->eg_pcb[2], sizeof(i));
728 DPRINTF(("Receive Packets %d\n", i));
729 memcpy(&i, &sc->eg_pcb[6], sizeof(i));
730 DPRINTF(("Transmit Packets %d\n", i));
731 DPRINTF(("CRC errors %d\n",
732 *(short *) &sc->eg_pcb[10]));
733 DPRINTF(("alignment errors %d\n",
734 *(short *) &sc->eg_pcb[12]));
735 DPRINTF(("no resources errors %d\n",
736 *(short *) &sc->eg_pcb[14]));
737 DPRINTF(("overrun errors %d\n",
738 *(short *) &sc->eg_pcb[16]));
739 serviced = 1;
740 break;
741
742 default:
743 printf("%s: egintr: Unknown response %x??\n",
744 sc->sc_dev.dv_xname, sc->eg_pcb[0]);
745 egprintpcb(sc->eg_pcb);
746 break;
747 }
748
749 #if NRND > 0
750 rnd_add_uint32(&sc->rnd_source, sc->eg_pcb[0]);
751 #endif
752 }
753
754 return serviced;
755 }
756
757 /*
758 * Pass a packet up to the higher levels.
759 */
760 void
761 egread(sc, buf, len)
762 struct eg_softc *sc;
763 caddr_t buf;
764 int len;
765 {
766 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
767 struct mbuf *m;
768
769 if (len <= sizeof(struct ether_header) ||
770 len > ETHER_MAX_LEN) {
771 printf("%s: invalid packet size %d; dropping\n",
772 sc->sc_dev.dv_xname, len);
773 ifp->if_ierrors++;
774 return;
775 }
776
777 /* Pull packet off interface. */
778 m = egget(sc, buf, len);
779 if (m == 0) {
780 ifp->if_ierrors++;
781 return;
782 }
783
784 ifp->if_ipackets++;
785
786 #if NBPFILTER > 0
787 /*
788 * Check if there's a BPF listener on this interface.
789 * If so, hand off the raw packet to BPF.
790 */
791 if (ifp->if_bpf)
792 bpf_mtap(ifp->if_bpf, m);
793 #endif
794
795 (*ifp->if_input)(ifp, m);
796 }
797
798 /*
799 * convert buf into mbufs
800 */
801 struct mbuf *
802 egget(sc, buf, totlen)
803 struct eg_softc *sc;
804 caddr_t buf;
805 int totlen;
806 {
807 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
808 struct mbuf *m, *m0, *newm;
809 int len;
810
811 MGETHDR(m0, M_DONTWAIT, MT_DATA);
812 if (m0 == 0)
813 return (0);
814 m0->m_pkthdr.rcvif = ifp;
815 m0->m_pkthdr.len = totlen;
816 len = MHLEN;
817 m = m0;
818
819 while (totlen > 0) {
820 if (totlen >= MINCLSIZE) {
821 MCLGET(m, M_DONTWAIT);
822 if ((m->m_flags & M_EXT) == 0)
823 goto bad;
824 len = MCLBYTES;
825 }
826
827 m->m_len = len = min(totlen, len);
828 memcpy(mtod(m, caddr_t), (caddr_t)buf, len);
829 buf += len;
830
831 totlen -= len;
832 if (totlen > 0) {
833 MGET(newm, M_DONTWAIT, MT_DATA);
834 if (newm == 0)
835 goto bad;
836 len = MLEN;
837 m = m->m_next = newm;
838 }
839 }
840
841 return (m0);
842
843 bad:
844 m_freem(m0);
845 return (0);
846 }
847
848 int
849 egioctl(ifp, cmd, data)
850 struct ifnet *ifp;
851 u_long cmd;
852 caddr_t data;
853 {
854 struct eg_softc *sc = ifp->if_softc;
855 struct ifaddr *ifa = (struct ifaddr *)data;
856 int s, error = 0;
857
858 s = splnet();
859
860 switch (cmd) {
861
862 case SIOCSIFADDR:
863 ifp->if_flags |= IFF_UP;
864
865 switch (ifa->ifa_addr->sa_family) {
866 #ifdef INET
867 case AF_INET:
868 eginit(sc);
869 arp_ifinit(ifp, ifa);
870 break;
871 #endif
872 default:
873 eginit(sc);
874 break;
875 }
876 break;
877
878 case SIOCSIFFLAGS:
879 if ((ifp->if_flags & IFF_UP) == 0 &&
880 (ifp->if_flags & IFF_RUNNING) != 0) {
881 /*
882 * If interface is marked down and it is running, then
883 * stop it.
884 */
885 egstop(sc);
886 ifp->if_flags &= ~IFF_RUNNING;
887 } else if ((ifp->if_flags & IFF_UP) != 0 &&
888 (ifp->if_flags & IFF_RUNNING) == 0) {
889 /*
890 * If interface is marked up and it is stopped, then
891 * start it.
892 */
893 eginit(sc);
894 } else {
895 sc->eg_pcb[0] = EG_CMD_GETSTATS;
896 sc->eg_pcb[1] = 0;
897 if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) {
898 DPRINTF(("write error\n"));
899 }
900 /*
901 * XXX deal with flags changes:
902 * IFF_MULTICAST, IFF_PROMISC,
903 * IFF_LINK0, IFF_LINK1,
904 */
905 }
906 break;
907
908 default:
909 error = EINVAL;
910 break;
911 }
912
913 splx(s);
914 return error;
915 }
916
917 void
918 egreset(sc)
919 struct eg_softc *sc;
920 {
921 int s;
922
923 DPRINTF(("%s: egreset()\n", sc->sc_dev.dv_xname));
924 s = splnet();
925 egstop(sc);
926 eginit(sc);
927 splx(s);
928 }
929
930 void
931 egwatchdog(ifp)
932 struct ifnet *ifp;
933 {
934 struct eg_softc *sc = ifp->if_softc;
935
936 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
937 sc->sc_ethercom.ec_if.if_oerrors++;
938
939 egreset(sc);
940 }
941
942 void
943 egstop(sc)
944 struct eg_softc *sc;
945 {
946
947 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EG_CONTROL, 0);
948 }
949