1 /*        $NetBSD: if_eg.c,v 1.103 2022/09/17 17:00:02 thorpej Exp $  */
2 
3 /*
4  * Copyright (c) 1993 Dean Huxley <dean@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.103 2022/09/17 17:00:02 thorpej Exp $");
44 
45 #include "opt_inet.h"
46 
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kmem.h>
50 #include <sys/mbuf.h>
51 #include <sys/socket.h>
52 #include <sys/ioctl.h>
53 #include <sys/errno.h>
54 #include <sys/syslog.h>
55 #include <sys/select.h>
56 #include <sys/device.h>
57 #include <sys/rndsource.h>
58 
59 #include <net/if.h>
60 #include <net/if_dl.h>
61 #include <net/if_types.h>
62 #include <net/bpf.h>
63 
64 #include <net/if_ether.h>
65 
66 #ifdef INET
67 #include <netinet/in.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in_var.h>
70 #include <netinet/ip.h>
71 #include <netinet/if_inarp.h>
72 #endif
73 
74 #include <sys/cpu.h>
75 #include <sys/intr.h>
76 #include <sys/bus.h>
77 
78 #include <dev/isa/isavar.h>
79 #include <dev/isa/if_egreg.h>
80 #include <dev/isa/elink.h>
81 
82 /* for debugging convenience */
83 #ifdef EGDEBUG
84 #define DPRINTF(x) printf x
85 #else
86 #define DPRINTF(x)
87 #endif
88 
89 #define EG_INLEN    10
90 #define EG_BUFLEN   0x0670
91 
92 #define EG_PCBLEN 64
93 
94 /*
95  * Ethernet software status per interface.
96  */
97 struct eg_softc {
98           device_t sc_dev;
99           void *sc_ih;
100           struct ethercom sc_ethercom;  /* Ethernet common part */
101           bus_space_tag_t sc_iot;                 /* bus space identifier */
102           bus_space_handle_t sc_ioh;    /* i/o handle */
103           uint8_t eg_rom_major;                   /* Cards ROM version (major number) */
104           uint8_t eg_rom_minor;                   /* Cards ROM version (minor number) */
105           short      eg_ram;            /* Amount of RAM on the card */
106           uint8_t eg_pcb[EG_PCBLEN];    /* Primary Command Block buffer */
107           uint8_t eg_incount;           /* Number of buffers currently used */
108           bool      eg_txbusy;                    /* transmitter is busy */
109           void *    eg_inbuf;           /* Incoming packet buffer */
110           void *    eg_outbuf;                    /* Outgoing packet buffer */
111 
112           krndsource_t rnd_source;
113 };
114 
115 static int          egprobe(device_t, cfdata_t, void *);
116 static void         egattach(device_t, device_t, void *);
117 
118 CFATTACH_DECL_NEW(eg, sizeof(struct eg_softc),
119     egprobe, egattach, NULL, NULL);
120 
121 static int          egintr(void *);
122 static void         eginit(struct eg_softc *);
123 static int          egioctl(struct ifnet *, u_long, void *);
124 static void         egrecv(struct eg_softc *);
125 static void         egstart(struct ifnet *);
126 static void         egwatchdog(struct ifnet *);
127 static void         egreset(struct eg_softc *);
128 static void         egread(struct eg_softc *, void *, int);
129 static struct mbuf *egget(struct eg_softc *, void *, int);
130 static void         egstop(struct eg_softc *);
131 
132 static inline void egprintpcb(uint8_t *);
133 static int egoutPCB(bus_space_tag_t, bus_space_handle_t, uint8_t);
134 static int egreadPCBstat(bus_space_tag_t, bus_space_handle_t, uint8_t);
135 static int egreadPCBready(bus_space_tag_t, bus_space_handle_t);
136 static int egwritePCB(bus_space_tag_t, bus_space_handle_t, uint8_t *);
137 static int egreadPCB(bus_space_tag_t, bus_space_handle_t, uint8_t *);
138 
139 /*
140  * Support stuff
141  */
142 
143 static inline void
egprintpcb(uint8_t * pcb)144 egprintpcb(uint8_t *pcb)
145 {
146           int i;
147 
148           for (i = 0; i < pcb[1] + 2; i++)
149                     DPRINTF(("pcb[%2d] = %x\n", i, pcb[i]));
150 }
151 
152 static int
egoutPCB(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t b)153 egoutPCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t b)
154 {
155           int i;
156 
157           for (i=0; i < 4000; i++) {
158                     if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE) {
159                               bus_space_write_1(iot, ioh, EG_COMMAND, b);
160                               return 0;
161                     }
162                     delay(10);
163           }
164           DPRINTF(("egoutPCB failed\n"));
165           return 1;
166 }
167 
168 static int
egreadPCBstat(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t statb)169 egreadPCBstat(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t statb)
170 {
171           int i;
172 
173           for (i=0; i < 5000; i++) {
174                     if ((bus_space_read_1(iot, ioh, EG_STATUS) &
175                         EG_PCB_STAT) != EG_PCB_NULL)
176                               break;
177                     delay(10);
178           }
179           if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) == statb)
180                     return 0;
181           return 1;
182 }
183 
184 static int
egreadPCBready(bus_space_tag_t iot,bus_space_handle_t ioh)185 egreadPCBready(bus_space_tag_t iot, bus_space_handle_t ioh)
186 {
187           int i;
188 
189           for (i=0; i < 10000; i++) {
190                     if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF)
191                               return 0;
192                     delay(5);
193           }
194           DPRINTF(("PCB read not ready\n"));
195           return 1;
196 }
197 
198 static int
egwritePCB(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t * pcb)199 egwritePCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t *pcb)
200 {
201           int i;
202           uint8_t len;
203 
204           bus_space_write_1(iot, ioh, EG_CONTROL,
205               (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
206 
207           len = pcb[1] + 2;
208           for (i = 0; i < len; i++)
209                     egoutPCB(iot, ioh, pcb[i]);
210 
211           for (i=0; i < 4000; i++) {
212                     if (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HCRE)
213                               break;
214                     delay(10);
215           }
216 
217           bus_space_write_1(iot, ioh, EG_CONTROL,
218               (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_DONE);
219 
220           egoutPCB(iot, ioh, len);
221 
222           if (egreadPCBstat(iot, ioh, EG_PCB_ACCEPT))
223                     return 1;
224           return 0;
225 }
226 
227 static int
egreadPCB(bus_space_tag_t iot,bus_space_handle_t ioh,uint8_t * pcb)228 egreadPCB(bus_space_tag_t iot, bus_space_handle_t ioh, uint8_t *pcb)
229 {
230           int i;
231 
232           bus_space_write_1(iot, ioh, EG_CONTROL,
233               (bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_PCB_STAT) | EG_PCB_NULL);
234 
235           memset(pcb, 0, EG_PCBLEN);
236 
237           if (egreadPCBready(iot, ioh))
238                     return 1;
239 
240           pcb[0] = bus_space_read_1(iot, ioh, EG_COMMAND);
241 
242           if (egreadPCBready(iot, ioh))
243                     return 1;
244 
245           pcb[1] = bus_space_read_1(iot, ioh, EG_COMMAND);
246 
247           if (pcb[1] > 62) {
248                     DPRINTF(("len %d too large\n", pcb[1]));
249                     return 1;
250           }
251 
252           for (i = 0; i < pcb[1]; i++) {
253                     if (egreadPCBready(iot, ioh))
254                               return 1;
255                     pcb[2+i] = bus_space_read_1(iot, ioh, EG_COMMAND);
256           }
257           if (egreadPCBready(iot, ioh))
258                     return 1;
259           if (egreadPCBstat(iot, ioh, EG_PCB_DONE))
260                     return 1;
261           if (bus_space_read_1(iot, ioh, EG_COMMAND) != pcb[1] + 2) {
262                     return 1;
263           }
264 
265           bus_space_write_1(iot, ioh, EG_CONTROL,
266               (bus_space_read_1(iot, ioh, EG_CONTROL) &
267               ~EG_PCB_STAT) | EG_PCB_ACCEPT);
268 
269           return 0;
270 }
271 
272 /*
273  * Real stuff
274  */
275 
276 static int
egprobe(device_t parent,cfdata_t match,void * aux)277 egprobe(device_t parent, cfdata_t match, void *aux)
278 {
279           struct isa_attach_args *ia = aux;
280           bus_space_tag_t iot = ia->ia_iot;
281           bus_space_handle_t ioh;
282           int i, rval;
283           static uint8_t pcb[EG_PCBLEN];
284 
285           rval = 0;
286 
287           /*
288            * XXX This probe is slow.  If there are no ISA expansion slots,
289            * then skip it.
290            */
291           if (isa_get_slotcount() == 0)
292                     return (0);
293 
294           if (ia->ia_nio < 1)
295                     return (0);
296           if (ia->ia_nirq < 1)
297                     return (0);
298 
299           if (ISA_DIRECT_CONFIG(ia))
300                     return (0);
301 
302           /* Disallow wildcarded i/o address. */
303           if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
304                     return (0);
305 
306           /* Disallow wildcarded IRQ. */
307           if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ)
308                     return (0);
309 
310           if ((ia->ia_io[0].ir_addr & ~0x07f0) != 0) {
311                     DPRINTF(("Weird iobase %x\n", ia->ia_io[0].ir_addr));
312                     return 0;
313           }
314 
315           /* Map i/o space. */
316           if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
317                     DPRINTF(("egprobe: can't map i/o space in probe\n"));
318                     return 0;
319           }
320 
321           /* hard reset card */
322           bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_RESET);
323           bus_space_write_1(iot, ioh, EG_CONTROL, 0);
324           for (i = 0; i < 500; i++) {
325                     delay(1000);
326                     if ((bus_space_read_1(iot, ioh, EG_STATUS) &
327                         EG_PCB_STAT) == EG_PCB_NULL)
328                               break;
329           }
330           if ((bus_space_read_1(iot, ioh, EG_STATUS) & EG_PCB_STAT) != EG_PCB_NULL) {
331                     DPRINTF(("egprobe: Reset failed\n"));
332                     goto out;
333           }
334           pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
335           pcb[1] = 0;
336           if (egwritePCB(iot, ioh, pcb) != 0)
337                     goto out;
338 
339           if ((egreadPCB(iot, ioh, pcb) != 0) ||
340               pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
341               pcb[1] != 0x0a) {
342                     egprintpcb(pcb);
343                     goto out;
344           }
345 
346           ia->ia_nio = 1;
347           ia->ia_io[0].ir_size = 0x08;
348 
349           ia->ia_nirq = 1;
350 
351           ia->ia_niomem = 0;
352           ia->ia_ndrq = 0;
353 
354           rval = 1;
355 
356  out:
357           bus_space_unmap(iot, ioh, 0x08);
358           return rval;
359 }
360 
361 static void
egattach(device_t parent,device_t self,void * aux)362 egattach(device_t parent, device_t self, void *aux)
363 {
364           struct eg_softc *sc = device_private(self);
365           struct isa_attach_args *ia = aux;
366           bus_space_tag_t iot = ia->ia_iot;
367           bus_space_handle_t ioh;
368           struct ifnet *ifp = &sc->sc_ethercom.ec_if;
369           uint8_t myaddr[ETHER_ADDR_LEN];
370 
371           sc->sc_dev = self;
372 
373           printf("\n");
374 
375           /* Map i/o space. */
376           if (bus_space_map(iot, ia->ia_io[0].ir_addr, 0x08, 0, &ioh)) {
377                     aprint_error_dev(self, "can't map i/o space\n");
378                     return;
379           }
380 
381           sc->sc_iot = iot;
382           sc->sc_ioh = ioh;
383 
384           sc->eg_pcb[0] = EG_CMD_GETINFO; /* Get Adapter Info */
385           sc->eg_pcb[1] = 0;
386           if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
387                     aprint_error_dev(self, "error requesting adapter info\n");
388                     return;
389           }
390           if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
391                     egprintpcb(sc->eg_pcb);
392                     aprint_error_dev(self, "error reading adapter info\n");
393                     return;
394           }
395 
396           if (sc->eg_pcb[0] != EG_RSP_GETINFO || /* Get Adapter Info Response */
397               sc->eg_pcb[1] != 0x0a) {
398                     egprintpcb(sc->eg_pcb);
399                     aprint_error_dev(self, "bogus adapter info\n");
400                     return;
401           }
402 
403           sc->eg_rom_major = sc->eg_pcb[3];
404           sc->eg_rom_minor = sc->eg_pcb[2];
405           sc->eg_ram = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
406 
407           egstop(sc);
408 
409           sc->eg_pcb[0] = EG_CMD_GETEADDR; /* Get Station address */
410           sc->eg_pcb[1] = 0;
411           if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
412                     aprint_error_dev(self, "can't send Get Station Address\n");
413                     return;
414           }
415           if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
416                     aprint_error_dev(self, "can't read station address\n");
417                     egprintpcb(sc->eg_pcb);
418                     return;
419           }
420 
421           /* check Get station address response */
422           if (sc->eg_pcb[0] != EG_RSP_GETEADDR || sc->eg_pcb[1] != 0x06) {
423                     aprint_error_dev(self, "card responded with garbage (1)\n");
424                     egprintpcb(sc->eg_pcb);
425                     return;
426           }
427           memcpy(myaddr, &sc->eg_pcb[2], ETHER_ADDR_LEN);
428 
429           aprint_normal_dev(self, "ROM v%d.%02d %dk address %s\n",
430               sc->eg_rom_major, sc->eg_rom_minor, sc->eg_ram,
431               ether_sprintf(myaddr));
432 
433           sc->eg_pcb[0] = EG_CMD_SETEADDR; /* Set station address */
434           if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
435                     aprint_error_dev(self, "can't send Set Station Address\n");
436                     return;
437           }
438           if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
439                     aprint_error_dev(self,
440                         "can't read Set Station Address status\n");
441                     egprintpcb(sc->eg_pcb);
442                     return;
443           }
444           if (sc->eg_pcb[0] != EG_RSP_SETEADDR || sc->eg_pcb[1] != 0x02 ||
445               sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0) {
446                     aprint_error_dev(self, "card responded with garbage (2)\n");
447                     egprintpcb(sc->eg_pcb);
448                     return;
449           }
450 
451           /* Initialize ifnet structure. */
452           strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
453           ifp->if_softc = sc;
454           ifp->if_start = egstart;
455           ifp->if_ioctl = egioctl;
456           ifp->if_watchdog = egwatchdog;
457           ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
458           IFQ_SET_READY(&ifp->if_snd);
459 
460           /* Now we can attach the interface. */
461           if_attach(ifp);
462           ether_ifattach(ifp, myaddr);
463 
464           sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
465               IST_EDGE, IPL_NET, egintr, sc);
466 
467           rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
468                                 RND_TYPE_NET, RND_FLAG_DEFAULT);
469 }
470 
471 static void
eginit(struct eg_softc * sc)472 eginit(struct eg_softc *sc)
473 {
474           struct ifnet *ifp = &sc->sc_ethercom.ec_if;
475           bus_space_tag_t iot = sc->sc_iot;
476           bus_space_handle_t ioh = sc->sc_ioh;
477 
478           /* soft reset the board */
479           bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_FLSH);
480           delay(100);
481           bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_ATTN);
482           delay(100);
483           bus_space_write_1(iot, ioh, EG_CONTROL, 0);
484           delay(200);
485 
486           sc->eg_pcb[0] = EG_CMD_CONFIG82586; /* Configure 82586 */
487           sc->eg_pcb[1] = 2;
488           sc->eg_pcb[2] = 3; /* receive broadcast & multicast */
489           sc->eg_pcb[3] = 0;
490           if (egwritePCB(iot, ioh, sc->eg_pcb) != 0)
491                     aprint_error_dev(sc->sc_dev, "can't send Configure 82586\n");
492 
493           if (egreadPCB(iot, ioh, sc->eg_pcb) != 0) {
494                     aprint_error_dev(sc->sc_dev,
495                         "can't read Configure 82586 status\n");
496                     egprintpcb(sc->eg_pcb);
497           } else if (sc->eg_pcb[2] != 0 || sc->eg_pcb[3] != 0)
498                     aprint_error_dev(sc->sc_dev,"configure card command failed\n");
499 
500           if (sc->eg_inbuf == NULL) {
501                     sc->eg_inbuf = kmem_alloc(EG_BUFLEN, KM_NOSLEEP);
502                     if (sc->eg_inbuf == NULL) {
503                               aprint_error_dev(sc->sc_dev, "can't allocate inbuf\n");
504                               panic("eginit");
505                     }
506           }
507           sc->eg_incount = 0;
508 
509           if (sc->eg_outbuf == NULL) {
510                     sc->eg_outbuf = kmem_alloc(EG_BUFLEN, KM_NOSLEEP);
511                     if (sc->eg_outbuf == NULL) {
512                               aprint_error_dev(sc->sc_dev,"can't allocate outbuf\n");
513                               panic("eginit");
514                     }
515           }
516 
517           bus_space_write_1(iot, ioh, EG_CONTROL, EG_CTL_CMDE);
518 
519           sc->eg_incount = 0;
520           egrecv(sc);
521 
522           /* Interface is now `running', with no output active. */
523           ifp->if_flags |= IFF_RUNNING;
524           sc->eg_txbusy = false;
525 
526           /* Attempt to start output, if any. */
527           egstart(ifp);
528 }
529 
530 static void
egrecv(struct eg_softc * sc)531 egrecv(struct eg_softc *sc)
532 {
533 
534           while (sc->eg_incount < EG_INLEN) {
535                     sc->eg_pcb[0] = EG_CMD_RECVPACKET;
536                     sc->eg_pcb[1] = 0x08;
537                     sc->eg_pcb[2] = 0; /* address not used.. we send zero */
538                     sc->eg_pcb[3] = 0;
539                     sc->eg_pcb[4] = 0;
540                     sc->eg_pcb[5] = 0;
541                     sc->eg_pcb[6] = EG_BUFLEN & 0xff; /* our buffer size */
542                     sc->eg_pcb[7] = (EG_BUFLEN >> 8) & 0xff;
543                     sc->eg_pcb[8] = 0; /* timeout, 0 == none */
544                     sc->eg_pcb[9] = 0;
545                     if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0)
546                               break;
547                     sc->eg_incount++;
548           }
549 }
550 
551 static void
egstart(struct ifnet * ifp)552 egstart(struct ifnet *ifp)
553 {
554           struct eg_softc *sc = ifp->if_softc;
555           bus_space_tag_t iot = sc->sc_iot;
556           bus_space_handle_t ioh = sc->sc_ioh;
557           struct mbuf *m0;
558           int len;
559           uint16_t *ptr;
560 
561           /* Don't transmit if interface is busy or not running */
562           if ((ifp->if_flags & IFF_RUNNING) == 0)
563                     return;
564 
565           if (sc->eg_txbusy)
566                     return;
567 
568 loop:
569           /* Dequeue the next datagram. */
570           IFQ_DEQUEUE(&ifp->if_snd, m0);
571           if (m0 == 0)
572                     return;
573 
574           sc->eg_txbusy = true;
575 
576           /* We need to use m->m_pkthdr.len, so require the header */
577           KASSERT(m0->m_flags & M_PKTHDR);
578           len = uimax(m0->m_pkthdr.len, ETHER_MIN_LEN - ETHER_CRC_LEN);
579 
580           bpf_mtap(ifp, m0, BPF_D_OUT);
581 
582           sc->eg_pcb[0] = EG_CMD_SENDPACKET;
583           sc->eg_pcb[1] = 0x06;
584           sc->eg_pcb[2] = 0; /* address not used, we send zero */
585           sc->eg_pcb[3] = 0;
586           sc->eg_pcb[4] = 0;
587           sc->eg_pcb[5] = 0;
588           sc->eg_pcb[6] = len; /* length of packet */
589           sc->eg_pcb[7] = len >> 8;
590           if (egwritePCB(iot, ioh, sc->eg_pcb) != 0) {
591                     aprint_error_dev(sc->sc_dev,
592                         "can't send Send Packet command\n");
593                     if_statinc(ifp, if_oerrors);
594                     sc->eg_txbusy = false;
595                     m_freem(m0);
596                     goto loop;
597           }
598 
599           m_copydata(m0, 0, m0->m_pkthdr.len, sc->eg_outbuf);
600           if (len > m0->m_pkthdr.len) {
601                     memset((uint8_t *)sc->eg_outbuf + m0->m_pkthdr.len, 0,
602                         len - m0->m_pkthdr.len);
603           }
604 
605           /* set direction bit: host -> adapter */
606           bus_space_write_1(iot, ioh, EG_CONTROL,
607               bus_space_read_1(iot, ioh, EG_CONTROL) & ~EG_CTL_DIR);
608 
609           for (ptr = (uint16_t *) sc->eg_outbuf; len > 0; len -= 2) {
610                     bus_space_write_2(iot, ioh, EG_DATA, *ptr++);
611                     while (!(bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_HRDY))
612                               ; /* XXX need timeout here */
613           }
614 
615           m_freem(m0);
616 }
617 
618 static int
egintr(void * arg)619 egintr(void *arg)
620 {
621           struct eg_softc *sc = arg;
622           struct ifnet *ifp = &sc->sc_ethercom.ec_if;
623           bus_space_tag_t iot = sc->sc_iot;
624           bus_space_handle_t ioh = sc->sc_ioh;
625           int i, len, serviced;
626           uint16_t *ptr;
627 
628           serviced = 0;
629 
630           while (bus_space_read_1(iot, ioh, EG_STATUS) & EG_STAT_ACRF) {
631                     egreadPCB(iot, ioh, sc->eg_pcb);
632                     switch (sc->eg_pcb[0]) {
633                     case EG_RSP_RECVPACKET:
634                               len = sc->eg_pcb[6] | (sc->eg_pcb[7] << 8);
635 
636                               /* Set direction bit : Adapter -> host */
637                               bus_space_write_1(iot, ioh, EG_CONTROL,
638                                   bus_space_read_1(iot, ioh, EG_CONTROL) | EG_CTL_DIR);
639 
640                               for (ptr = (uint16_t *) sc->eg_inbuf;
641                                   len > 0; len -= 2) {
642                                         while (!(bus_space_read_1(iot, ioh, EG_STATUS) &
643                                             EG_STAT_HRDY))
644                                                   ;
645                                         *ptr++ = bus_space_read_2(iot, ioh, EG_DATA);
646                               }
647 
648                               len = sc->eg_pcb[8] | (sc->eg_pcb[9] << 8);
649                               egread(sc, sc->eg_inbuf, len);
650 
651                               sc->eg_incount--;
652                               egrecv(sc);
653                               serviced = 1;
654                               break;
655 
656                     case EG_RSP_SENDPACKET:
657                               if (sc->eg_pcb[6] || sc->eg_pcb[7]) {
658                                         DPRINTF(("%s: packet dropped\n",
659                                             device_xname(sc->sc_dev)));
660                                         if_statinc(ifp, if_oerrors);
661                               } else
662                                         if_statinc(ifp, if_opackets);
663                               if (sc->eg_pcb[8] & 0xf)
664                                         if_statadd(ifp, if_collisions,
665                                             sc->eg_pcb[8] & 0xf);
666                               sc->eg_txbusy = false;
667                               egstart(&sc->sc_ethercom.ec_if);
668                               serviced = 1;
669                               break;
670 
671                     /* XXX byte-order and type-size bugs here... */
672                     case EG_RSP_GETSTATS:
673                               DPRINTF(("%s: Card Statistics\n",
674                                   device_xname(sc->sc_dev)));
675                               memcpy(&i, &sc->eg_pcb[2], sizeof(i));
676                               DPRINTF(("Receive Packets %d\n", i));
677                               memcpy(&i, &sc->eg_pcb[6], sizeof(i));
678                               DPRINTF(("Transmit Packets %d\n", i));
679                               DPRINTF(("CRC errors %d\n",
680                                   *(short *) &sc->eg_pcb[10]));
681                               DPRINTF(("alignment errors %d\n",
682                                   *(short *) &sc->eg_pcb[12]));
683                               DPRINTF(("no resources errors %d\n",
684                                   *(short *) &sc->eg_pcb[14]));
685                               DPRINTF(("overrun errors %d\n",
686                                   *(short *) &sc->eg_pcb[16]));
687                               serviced = 1;
688                               break;
689 
690                     default:
691                               printf("%s: egintr: Unknown response %x??\n",
692                                   device_xname(sc->sc_dev), sc->eg_pcb[0]);
693                               egprintpcb(sc->eg_pcb);
694                               break;
695                     }
696 
697                     rnd_add_uint32(&sc->rnd_source, sc->eg_pcb[0]);
698           }
699 
700           return serviced;
701 }
702 
703 /*
704  * Pass a packet up to the higher levels.
705  */
706 static void
egread(struct eg_softc * sc,void * buf,int len)707 egread(struct eg_softc *sc, void *buf, int len)
708 {
709           struct ifnet *ifp = &sc->sc_ethercom.ec_if;
710           struct mbuf *m;
711 
712           if (len <= sizeof(struct ether_header) ||
713               len > ETHER_MAX_LEN) {
714                     aprint_error_dev(sc->sc_dev,
715                         "invalid packet size %d; dropping\n", len);
716                     if_statinc(ifp, if_ierrors);
717                     return;
718           }
719 
720           /* Pull packet off interface. */
721           m = egget(sc, buf, len);
722           if (m == 0) {
723                     if_statinc(ifp, if_ierrors);
724                     return;
725           }
726 
727           if_percpuq_enqueue(ifp->if_percpuq, m);
728 }
729 
730 /*
731  * convert buf into mbufs
732  */
733 static struct mbuf *
egget(struct eg_softc * sc,void * buf,int totlen)734 egget(struct eg_softc *sc, void *buf, int totlen)
735 {
736           struct ifnet *ifp = &sc->sc_ethercom.ec_if;
737           struct mbuf *m, *m0, *newm;
738           int len;
739 
740           MGETHDR(m0, M_DONTWAIT, MT_DATA);
741           if (m0 == 0)
742                     return (0);
743           m_set_rcvif(m0, ifp);
744           m0->m_pkthdr.len = totlen;
745           len = MHLEN;
746           m = m0;
747 
748           while (totlen > 0) {
749                     if (totlen >= MINCLSIZE) {
750                               MCLGET(m, M_DONTWAIT);
751                               if ((m->m_flags & M_EXT) == 0)
752                                         goto bad;
753                               len = MCLBYTES;
754                     }
755 
756                     m->m_len = len = uimin(totlen, len);
757                     memcpy(mtod(m, void *), buf, len);
758                     buf = (char *)buf + len;
759 
760                     totlen -= len;
761                     if (totlen > 0) {
762                               MGET(newm, M_DONTWAIT, MT_DATA);
763                               if (newm == 0)
764                                         goto bad;
765                               len = MLEN;
766                               m = m->m_next = newm;
767                     }
768           }
769 
770           return (m0);
771 
772 bad:
773           m_freem(m0);
774           return (0);
775 }
776 
777 static int
egioctl(struct ifnet * ifp,unsigned long cmd,void * data)778 egioctl(struct ifnet *ifp, unsigned long cmd, void *data)
779 {
780           struct eg_softc *sc = ifp->if_softc;
781           struct ifaddr *ifa = (struct ifaddr *)data;
782           int s, error = 0;
783 
784           s = splnet();
785 
786           switch (cmd) {
787 
788           case SIOCINITIFADDR:
789                     ifp->if_flags |= IFF_UP;
790 
791                     eginit(sc);
792                     switch (ifa->ifa_addr->sa_family) {
793 #ifdef INET
794                     case AF_INET:
795                               arp_ifinit(ifp, ifa);
796                               break;
797 #endif
798                     default:
799                               break;
800                     }
801                     break;
802 
803           case SIOCSIFFLAGS:
804                     if ((error = ifioctl_common(ifp, cmd, data)) != 0)
805                               break;
806                     /* XXX re-use ether_ioctl() */
807                     switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
808                     case IFF_RUNNING:
809                               /*
810                                * If interface is marked down and it is running, then
811                                * stop it.
812                                */
813                               egstop(sc);
814                               ifp->if_flags &= ~IFF_RUNNING;
815                               break;
816                     case IFF_UP:
817                               /*
818                                * If interface is marked up and it is stopped, then
819                                * start it.
820                                */
821                               eginit(sc);
822                               break;
823                     default:
824                               sc->eg_pcb[0] = EG_CMD_GETSTATS;
825                               sc->eg_pcb[1] = 0;
826                               if (egwritePCB(sc->sc_iot, sc->sc_ioh, sc->eg_pcb) != 0) {
827                                         DPRINTF(("write error\n"));
828                               }
829                               /*
830                                * XXX deal with flags changes:
831                                * IFF_MULTICAST, IFF_PROMISC,
832                                * IFF_LINK0, IFF_LINK1,
833                                */
834                               break;
835                     }
836                     break;
837 
838           default:
839                     error = ether_ioctl(ifp, cmd, data);
840                     break;
841           }
842 
843           splx(s);
844           return error;
845 }
846 
847 static void
egreset(struct eg_softc * sc)848 egreset(struct eg_softc *sc)
849 {
850           int s;
851 
852           DPRINTF(("%s: egreset()\n", device_xname(sc->sc_dev)));
853           s = splnet();
854           egstop(sc);
855           eginit(sc);
856           splx(s);
857 }
858 
859 static void
egwatchdog(struct ifnet * ifp)860 egwatchdog(struct ifnet *ifp)
861 {
862           struct eg_softc *sc = ifp->if_softc;
863 
864           log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
865           if_statinc(ifp, if_oerrors);
866 
867           egreset(sc);
868 }
869 
870 static void
egstop(struct eg_softc * sc)871 egstop(struct eg_softc *sc)
872 {
873 
874           bus_space_write_1(sc->sc_iot, sc->sc_ioh, EG_CONTROL, 0);
875 }
876