xref: /openbsd/sys/dev/isa/if_eg.c (revision 67d07b9d)
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 = &top;
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