Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / dev / netif / ep / if_ep.c
1 /*
2  * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Herb Peyerl.
16  * 4. The name of Herb Peyerl may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  *      if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp
31  */
32
33 /*
34  *      Modified from the FreeBSD 1.1.5.1 version by:
35  *                      Andres Vega Garcia
36  *                      INRIA - Sophia Antipolis, France
37  *                      avega@sophia.inria.fr
38  */
39
40 /*
41  * $FreeBSD: src/sys/dev/ep/if_ep.c,v 1.95.2.3 2002/03/06 07:26:35 imp Exp $
42  * $DragonFly: src/sys/dev/netif/ep/if_ep.c,v 1.26 2006/12/22 23:26:19 swildner Exp $
43  *
44  *  Promiscuous mode added and interrupt logic slightly changed
45  *  to reduce the number of adapter failures. Transceiver select
46  *  logic changed to use value from EEPROM. Autoconfiguration
47  *  features added.
48  *  Done by:
49  *          Serge Babkin
50  *          Chelindbank (Chelyabinsk, Russia)
51  *          babkin@hq.icb.chel.su
52  */
53
54 /*
55  * Pccard support for 3C589 by:
56  *              HAMADA Naoki
57  *              nao@tom-yam.or.jp
58  */
59
60 /*
61  * MAINTAINER: Matthew N. Dodd <winter@jurai.net>
62  *                             <mdodd@FreeBSD.org>
63  */
64
65 #include <sys/param.h>
66 #include <sys/kernel.h>
67 #include <sys/systm.h>
68 #include <sys/malloc.h>
69 #include <sys/mbuf.h>
70 #include <sys/socket.h>
71 #include <sys/sockio.h>
72 #include <sys/module.h>
73 #include <sys/bus.h>
74 #include <sys/rman.h> 
75 #include <sys/thread2.h>
76
77 #include <net/if.h>
78 #include <net/ifq_var.h>
79 #include <net/if_arp.h>
80 #include <net/if_media.h> 
81 #include <net/ethernet.h>
82 #include <net/bpf.h>
83
84 #include <netinet/in.h>
85 #include <netinet/if_ether.h>
86
87 #include <machine/clock.h>
88
89 #include "if_epreg.h"
90 #include "if_epvar.h"
91 #include "../elink_layer/elink.h"
92
93 /* Exported variables */
94 devclass_t ep_devclass;
95
96 #if 0
97 static char *   ep_conn_type[] = {"UTP", "AUI", "???", "BNC"};
98 static int      if_media2ep_media[] = { 0, 0, 0, UTP, BNC, AUI };
99 #endif
100
101 static int      ep_media2if_media[] =
102         { IFM_10_T, IFM_10_5, IFM_NONE, IFM_10_2, IFM_NONE };
103
104 /* if functions */
105 static void     ep_if_init      (void *);
106 static int      ep_if_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
107 static void     ep_if_start     (struct ifnet *);
108 static void     ep_if_watchdog  (struct ifnet *);
109
110 /* if_media functions */
111 static int      ep_ifmedia_upd  (struct ifnet *);
112 static void     ep_ifmedia_sts  (struct ifnet *, struct ifmediareq *);
113
114 static void     epstop          (struct ep_softc *);
115 static void     epread          (struct ep_softc *);
116 static int      eeprom_rdy      (struct ep_softc *);
117
118 DECLARE_DUMMY_MODULE(if_ep);
119
120 #define EP_FTST(sc, f)  (sc->stat &   (f))
121 #define EP_FSET(sc, f)  (sc->stat |=  (f))
122 #define EP_FRST(sc, f)  (sc->stat &= ~(f))
123
124 static int
125 eeprom_rdy(struct ep_softc *sc)
126 {
127     int i;
128
129     for (i = 0; is_eeprom_busy(BASE) && i < MAX_EEPROMBUSY; i++) {
130         DELAY(100);
131     }
132     if (i >= MAX_EEPROMBUSY) {
133         if_printf(&sc->arpcom.ac_if, "eeprom failed to come ready.\n");
134         return (0);
135     }
136     return (1);
137 }
138
139 /*
140  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
141  * before
142  */
143 u_int16_t
144 get_e(struct ep_softc *sc, int offset)
145 {
146     if (!eeprom_rdy(sc))
147         return (0);
148     outw(BASE + EP_W0_EEPROM_COMMAND, (EEPROM_CMD_RD << sc->epb.cmd_off) | offset);
149     if (!eeprom_rdy(sc))
150         return (0);
151     return (inw(BASE + EP_W0_EEPROM_DATA));
152 }
153
154 void
155 ep_get_macaddr(struct ep_softc *sc, uint8_t *addr)
156 {
157         int                     i;
158         u_int16_t *             macaddr = (u_int16_t *)addr;
159
160         GO_WINDOW(0);
161         for(i = EEPROM_NODE_ADDR_0; i <= EEPROM_NODE_ADDR_2; i++) {
162                 macaddr[i] = htons(get_e(sc, i));
163         }
164
165         return;
166 }
167
168 int
169 ep_alloc(device_t dev)
170 {
171         struct ep_softc *       sc = device_get_softc(dev);
172         int                     rid;
173         int                     error = 0;
174
175         rid = 0;
176         sc->iobase = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
177             RF_ACTIVE);
178         if (!sc->iobase) {
179                 device_printf(dev, "No I/O space?!\n");
180                 error = ENXIO;
181                 goto bad;
182         }
183
184         rid = 0;
185         sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
186         if (!sc->irq) {
187                 device_printf(dev, "No irq?!\n");
188                 error = ENXIO;
189                 goto bad;
190         }
191
192         if_initname(&sc->arpcom.ac_if,
193                     device_get_name(dev), device_get_unit(dev));
194         sc->stat = 0;   /* 16 bit access */
195
196         sc->ep_io_addr = rman_get_start(sc->iobase);
197
198         sc->ep_btag = rman_get_bustag(sc->iobase);
199         sc->ep_bhandle = rman_get_bushandle(sc->iobase);
200
201         sc->ep_connectors = 0;
202         sc->ep_connector = 0;
203
204         GO_WINDOW(0);
205         sc->epb.cmd_off = 0;
206         sc->epb.prod_id = get_e(sc, EEPROM_PROD_ID);
207         sc->epb.res_cfg = get_e(sc, EEPROM_RESOURCE_CFG);
208
209 bad:
210         return (error);
211 }
212
213 void
214 ep_get_media(struct ep_softc *sc)
215 {
216         u_int16_t               config;
217         
218         GO_WINDOW(0);
219         config = inw(BASE + EP_W0_CONFIG_CTRL);
220         if (config & IS_AUI)
221                 sc->ep_connectors |= AUI;
222         if (config & IS_BNC)
223                 sc->ep_connectors |= BNC;
224         if (config & IS_UTP)
225                 sc->ep_connectors |= UTP;
226
227         if (!(sc->ep_connectors & 7)) {
228                 if (bootverbose)
229                         if_printf(&sc->arpcom.ac_if, "no connectors!\n");
230         }
231
232         /*
233          * This works for most of the cards so we'll do it here.
234          * The cards that require something different can override
235          * this later on.
236          */
237         sc->ep_connector = inw(BASE + EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
238
239         return;
240 }
241
242 void
243 ep_free(device_t dev)
244 {
245         struct ep_softc *       sc = device_get_softc(dev);
246
247         if (sc->iobase)
248                 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
249         if (sc->irq)
250                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
251
252         return;
253 }
254         
255 int
256 ep_attach(struct ep_softc *sc)
257 {
258         struct ifnet *          ifp = NULL;
259         struct ifmedia *        ifm = NULL;
260         u_short *               p;
261         uint8_t                 ether_addr[ETHER_ADDR_LEN];
262         int                     i;
263
264         sc->gone = 0;
265
266         ep_get_macaddr(sc, ether_addr);
267
268         /*
269          * Setup the station address
270          */
271         p = (u_short*)ether_addr;
272         GO_WINDOW(2);
273         for (i = 0; i < 3; i++) {
274                 outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i]));
275         }
276   
277         ifp = &sc->arpcom.ac_if;
278
279         ifp->if_softc = sc;
280         ifp->if_mtu = ETHERMTU;
281         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
282         ifp->if_start = ep_if_start;
283         ifp->if_ioctl = ep_if_ioctl;
284         ifp->if_watchdog = ep_if_watchdog;
285         ifp->if_init = ep_if_init;
286         ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
287         ifq_set_ready(&ifp->if_snd);
288
289         if (!sc->epb.mii_trans) {
290                 ifmedia_init(&sc->ifmedia, 0, ep_ifmedia_upd, ep_ifmedia_sts);
291
292                 if (sc->ep_connectors & AUI)
293                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_5, 0, NULL);
294                 if (sc->ep_connectors & UTP)
295                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
296                 if (sc->ep_connectors & BNC)
297                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_10_2, 0, NULL);
298                 if (!sc->ep_connectors)
299                         ifmedia_add(&sc->ifmedia, IFM_ETHER|IFM_NONE, 0, NULL);
300         
301                 ifmedia_set(&sc->ifmedia, IFM_ETHER|ep_media2if_media[sc->ep_connector]);
302         
303                 ifm = &sc->ifmedia;
304                 ifm->ifm_media = ifm->ifm_cur->ifm_media;
305                 ep_ifmedia_upd(ifp);
306         }
307
308         ether_ifattach(ifp, ether_addr, NULL);
309
310 #ifdef EP_LOCAL_STATS
311         sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc =
312                 sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
313 #endif
314         EP_FSET(sc, F_RX_FIRST);
315         sc->top = sc->mcur = 0;
316
317         return 0;
318 }
319
320 /*
321  * The order in here seems important. Otherwise we may not receive
322  * interrupts. ?!
323  */
324 static void
325 ep_if_init(void *xsc)
326 {
327     struct ep_softc *sc = xsc;
328     struct ifnet *ifp = &sc->arpcom.ac_if;
329     int i;
330
331     if (sc->gone)
332         return;
333
334     crit_enter();
335
336     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
337
338     GO_WINDOW(0);
339     outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
340     GO_WINDOW(4);
341     outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
342     GO_WINDOW(0);
343
344     /* Disable the card */
345     outw(BASE + EP_W0_CONFIG_CTRL, 0);
346
347     /* Enable the card */
348     outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
349
350     GO_WINDOW(2);
351
352     /* Reload the ether_addr. */
353     for (i = 0; i < 6; i++)
354         outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
355
356     outw(BASE + EP_COMMAND, RX_RESET);
357     outw(BASE + EP_COMMAND, TX_RESET);
358     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
359
360     /* Window 1 is operating window */
361     GO_WINDOW(1);
362     for (i = 0; i < 31; i++)
363         inb(BASE + EP_W1_TX_STATUS);
364
365     /* get rid of stray intr's */
366     outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
367
368     outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
369
370     outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
371
372     if (ifp->if_flags & IFF_PROMISC)
373         outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
374          FIL_GROUP | FIL_BRDCST | FIL_ALL);
375     else
376         outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
377          FIL_GROUP | FIL_BRDCST);
378
379     if (!sc->epb.mii_trans) {
380         ep_ifmedia_upd(ifp);
381     }
382
383     outw(BASE + EP_COMMAND, RX_ENABLE);
384     outw(BASE + EP_COMMAND, TX_ENABLE);
385
386     ifp->if_flags |= IFF_RUNNING;
387     ifp->if_flags &= ~IFF_OACTIVE;      /* just in case */
388
389 #ifdef EP_LOCAL_STATS
390     sc->rx_no_first = sc->rx_no_mbuf =
391         sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
392 #endif
393     EP_FSET(sc, F_RX_FIRST);
394     if (sc->top) {
395         m_freem(sc->top);
396         sc->top = sc->mcur = 0;
397     }
398     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
399     outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16);
400
401     /*
402      * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up
403      * any that we had in case we're being called from intr or somewhere
404      * else.
405      */
406
407     GO_WINDOW(1);
408     ep_if_start(ifp);
409
410     crit_exit();
411 }
412
413 static const char padmap[] = {0, 3, 2, 1};
414
415 static void
416 ep_if_start(struct ifnet *ifp)
417 {
418     struct ep_softc *sc = ifp->if_softc;
419     u_int len;
420     struct mbuf *m;
421     struct mbuf *top;
422     int pad;
423
424     if (sc->gone) {
425         return;
426     }
427
428     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
429     if (ifp->if_flags & IFF_OACTIVE) {
430         return;
431     }
432
433     crit_enter();
434
435 startagain:
436     /* Sneak a peek at the next packet */
437     m = ifq_poll(&ifp->if_snd);
438     if (m == NULL) {
439         crit_exit();
440         return;
441     }
442
443     for (len = 0, top = m; m; m = m->m_next)
444         len += m->m_len;
445     m = top;
446
447     pad = padmap[len & 3];
448
449     /*
450      * The 3c509 automatically pads short packets to minimum ethernet length,
451      * but we drop packets that are too large. Perhaps we should truncate
452      * them instead?
453      */
454     if (len + pad > ETHER_MAX_LEN) {
455         /* packet is obviously too large: toss it */
456         ++ifp->if_oerrors;
457         ifq_dequeue(&ifp->if_snd, m);
458         m_freem(m);
459         goto readcheck;
460     }
461     if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
462         /* no room in FIFO */
463         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
464         /* make sure */
465         if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
466             ifp->if_flags |= IFF_OACTIVE;
467             crit_exit();
468             return;
469         }
470     } else {
471         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
472     }
473
474     ifq_dequeue(&ifp->if_snd, m);
475
476     outw(BASE + EP_W1_TX_PIO_WR_1, len); 
477     outw(BASE + EP_W1_TX_PIO_WR_1, 0x0);        /* Second dword meaningless */
478
479     if (EP_FTST(sc, F_ACCESS_32_BITS)) {
480         for (top = m; m != 0; m = m->m_next) {
481             outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
482                   m->m_len / 4);
483             if (m->m_len & 3)
484                 outsb(BASE + EP_W1_TX_PIO_WR_1,
485                       mtod(m, caddr_t) + (m->m_len & (~3)),
486                       m->m_len & 3);
487         }
488     } else {
489         for (top = m; m != 0; m = m->m_next) {
490             outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2);
491             if (m->m_len & 1)
492                 outb(BASE + EP_W1_TX_PIO_WR_1,
493                      *(mtod(m, caddr_t) + m->m_len - 1));
494         }
495     }
496
497     while (pad--)
498         outb(BASE + EP_W1_TX_PIO_WR_1, 0);      /* Padding */
499
500     BPF_MTAP(ifp, top);
501
502     ifp->if_timer = 2;
503     ifp->if_opackets++;
504     m_freem(top);
505
506     /*
507      * Is another packet coming in? We don't want to overflow the tiny RX
508      * fifo.
509      */
510 readcheck:
511     if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
512         /*
513          * we check if we have packets left, in that case we prepare to come
514          * back later
515          */
516         if (!ifq_is_empty(&ifp->if_snd))
517             outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
518
519         crit_exit();
520         return;
521     }
522     goto startagain;
523 }
524
525 void
526 ep_intr(void *arg)
527 {
528     struct ep_softc *sc = arg;
529     struct ifnet *ifp = &sc->arpcom.ac_if;
530     int status;
531
532      /*
533       * quick fix: Try to detect an interrupt when the card goes away.
534       */
535     if (sc->gone || inw(BASE + EP_STATUS) == 0xffff) {
536             return;
537     }
538
539     outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */
540
541 rescan:
542
543     while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) {
544
545         /* first acknowledge all interrupt sources */
546         outw(BASE + EP_COMMAND, ACK_INTR | (status & S_MASK));
547
548         if (status & (S_RX_COMPLETE | S_RX_EARLY))
549             epread(sc);
550         if (status & S_TX_AVAIL) {
551             /* we need ACK */
552             ifp->if_timer = 0;
553             ifp->if_flags &= ~IFF_OACTIVE;
554             GO_WINDOW(1);
555             inw(BASE + EP_W1_FREE_TX);
556             ep_if_start(ifp);
557         }
558         if (status & S_CARD_FAILURE) {
559             ifp->if_timer = 0;
560 #ifdef EP_LOCAL_STATS
561             kprintf("\n");
562             if_printf(ifp, "\n\tStatus: %x\n", status);
563             GO_WINDOW(4);
564             kprintf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG));
565             kprintf("\tStat: %x\n", sc->stat);
566             kprintf("\tIpackets=%d, Opackets=%d\n",
567                 ifp->if_ipackets, ifp->if_opackets);
568             kprintf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
569                    sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf,
570                    sc->rx_overrunl, sc->tx_underrun);
571 #else
572
573 #ifdef DIAGNOSTIC
574             if_printf(ifp, "Status: %x (input buffer overflow)\n", status);
575 #else
576             ++ifp->if_ierrors;
577 #endif
578
579 #endif
580             ep_if_init(sc);
581             return;
582         }
583         if (status & S_TX_COMPLETE) {
584             ifp->if_timer = 0;
585             /* we  need ACK. we do it at the end */
586             /*
587              * We need to read TX_STATUS until we get a 0 status in order to
588              * turn off the interrupt flag.
589              */
590             while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
591                 if (status & TXS_SUCCES_INTR_REQ);
592                 else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) {
593                     outw(BASE + EP_COMMAND, TX_RESET);
594                     if (status & TXS_UNDERRUN) {
595 #ifdef EP_LOCAL_STATS
596                         sc->tx_underrun++;
597 #endif
598                     } else {
599                         if (status & TXS_JABBER);
600                         else    /* TXS_MAX_COLLISION - we shouldn't get here */
601                             ++ifp->if_collisions;
602                     }
603                     ++ifp->if_oerrors;
604                     outw(BASE + EP_COMMAND, TX_ENABLE);
605                     /*
606                      * To have a tx_avail_int but giving the chance to the
607                      * Reception
608                      */
609                     if (!ifq_is_empty(&ifp->if_snd))
610                         outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
611                 }
612                 outb(BASE + EP_W1_TX_STATUS, 0x0);      /* pops up the next
613                                                          * status */
614             }                   /* while */
615             ifp->if_flags &= ~IFF_OACTIVE;
616             GO_WINDOW(1);
617             inw(BASE + EP_W1_FREE_TX);
618             ep_if_start(ifp);
619         }                       /* end TX_COMPLETE */
620     }
621
622     outw(BASE + EP_COMMAND, C_INTR_LATCH);      /* ACK int Latch */
623
624     if ((status = inw(BASE + EP_STATUS)) & S_5_INTS)
625         goto rescan;
626
627     /* re-enable Ints */
628     outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS);
629 }
630
631 static void
632 epread(struct ep_softc *sc)
633 {
634     struct mbuf *top, *mcur, *m;
635     struct ifnet *ifp;
636     int lenthisone;
637
638     short rx_fifo2, status;
639     short rx_fifo;
640
641     ifp = &sc->arpcom.ac_if;
642     status = inw(BASE + EP_W1_RX_STATUS);
643
644 read_again:
645
646     if (status & ERR_RX) {
647         ++ifp->if_ierrors;
648         if (status & ERR_RX_OVERRUN) {
649             /*
650              * we can think the rx latency is actually greather than we
651              * expect
652              */
653 #ifdef EP_LOCAL_STATS
654             if (EP_FTST(sc, F_RX_FIRST))
655                 sc->rx_overrunf++;
656             else
657                 sc->rx_overrunl++;
658 #endif
659         }
660         goto out;
661     }
662     rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;
663
664     if (EP_FTST(sc, F_RX_FIRST)) {
665         m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, M_PKTHDR, NULL);
666         if (!m)
667             goto out;
668         sc->top = sc->mcur = top = m;
669 #define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
670 #define EOFF    (EROUND - sizeof(struct ether_header))
671         top->m_data += EOFF;
672
673         /* Read what should be the header. */
674         insw(BASE + EP_W1_RX_PIO_RD_1,
675              mtod(top, caddr_t), sizeof(struct ether_header) / 2);
676         top->m_len = sizeof(struct ether_header);
677         rx_fifo -= sizeof(struct ether_header);
678         sc->cur_len = rx_fifo2;
679     } else {
680         /* come here if we didn't have a complete packet last time */
681         top = sc->top;
682         m = sc->mcur;
683         sc->cur_len += rx_fifo2;
684     }
685
686     /* Reads what is left in the RX FIFO */
687     while (rx_fifo > 0) {
688         lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
689         if (lenthisone == 0) {  /* no room in this one */
690             mcur = m;
691             m = m_getl(rx_fifo, MB_DONTWAIT, MT_DATA, 0, NULL);
692             if (!m)
693                 goto out;
694             m->m_len = 0;
695             mcur->m_next = m;
696             lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
697         }
698         if (EP_FTST(sc, F_ACCESS_32_BITS)) { /* default for EISA configured cards*/
699             insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
700                  lenthisone / 4);
701             m->m_len += (lenthisone & ~3);
702             if (lenthisone & 3)
703                 insb(BASE + EP_W1_RX_PIO_RD_1,
704                      mtod(m, caddr_t) + m->m_len,
705                      lenthisone & 3);
706             m->m_len += (lenthisone & 3);
707         } else {
708             insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
709                  lenthisone / 2);
710             m->m_len += lenthisone;
711             if (lenthisone & 1)
712                 *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
713         }
714         rx_fifo -= lenthisone;
715     }
716
717     if (status & ERR_RX_INCOMPLETE) {   /* we haven't received the complete
718                                          * packet */
719         sc->mcur = m;
720 #ifdef EP_LOCAL_STATS
721         sc->rx_no_first++;      /* to know how often we come here */
722 #endif
723         EP_FRST(sc, F_RX_FIRST);
724         if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) {
725             /* we see if by now, the packet has completly arrived */
726             goto read_again;
727         }
728         outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
729         return;
730     }
731     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
732     ++ifp->if_ipackets;
733     EP_FSET(sc, F_RX_FIRST);
734     top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
735     top->m_pkthdr.len = sc->cur_len;
736
737     ifp->if_input(ifp, top);
738     sc->top = 0;
739     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
740     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
741     return;
742
743 out:
744     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
745     if (sc->top) {
746         m_freem(sc->top);
747         sc->top = 0;
748 #ifdef EP_LOCAL_STATS
749         sc->rx_no_mbuf++;
750 #endif
751     }
752     EP_FSET(sc, F_RX_FIRST);
753     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
754     outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
755 }
756
757 static int 
758 ep_ifmedia_upd(struct ifnet *ifp)
759 {
760         struct ep_softc *       sc = ifp->if_softc;
761         int                     i = 0, j;
762
763         GO_WINDOW(0);
764         outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
765         GO_WINDOW(4);
766         outw(BASE + EP_W4_MEDIA_TYPE, DISABLE_UTP);
767         GO_WINDOW(0);
768
769         switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) {
770                 case IFM_10_T:
771                         if (sc->ep_connectors & UTP) {
772                                 i = ACF_CONNECTOR_UTP;
773                                 GO_WINDOW(4);
774                                 outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
775                         }
776                         break;
777                 case IFM_10_2:
778                         if (sc->ep_connectors & BNC) {
779                                 i = ACF_CONNECTOR_BNC;
780                                 outw(BASE + EP_COMMAND, START_TRANSCEIVER);
781                                 DELAY(DELAY_MULTIPLE * 1000);
782                         }
783                         break;
784                 case IFM_10_5:
785                         if (sc->ep_connectors & AUI)
786                                 i = ACF_CONNECTOR_AUI;
787                         break;
788                 default:
789                         i = sc->ep_connector;
790                         if_printf(ifp, "strange connector type in EEPROM: "
791                                   "assuming AUI\n");
792                         break;
793         }
794
795         GO_WINDOW(0);
796         j = inw(BASE + EP_W0_ADDRESS_CFG) & 0x3fff;
797         outw(BASE + EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));
798
799         return (0);
800 }
801
802 static void
803 ep_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
804 {
805         struct ep_softc *       sc = ifp->if_softc;
806
807         ifmr->ifm_active = sc->ifmedia.ifm_media;
808
809         return;
810 }
811
812 static int
813 ep_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
814 {
815         struct ep_softc *       sc = ifp->if_softc;
816         struct ifreq *          ifr = (struct ifreq *)data;
817         int error = 0;
818
819         crit_enter();
820
821         switch (cmd) {
822         case SIOCSIFFLAGS:
823                 if (((ifp->if_flags & IFF_UP) == 0) &&
824                     (ifp->if_flags & IFF_RUNNING)) {
825                         ifp->if_flags &= ~IFF_RUNNING;
826                         epstop(sc);
827                 } else {
828                         /* reinitialize card on any parameter change */
829                         ep_if_init(sc);
830                 }
831                 break;
832 #ifdef notdef
833         case SIOCGHWADDR:
834                 bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data,
835                       sizeof(sc->sc_addr));
836                 break;
837 #endif
838         case SIOCADDMULTI:
839         case SIOCDELMULTI:
840                 /*
841                  * The Etherlink III has no programmable multicast
842                  * filter.  We always initialize the card to be
843                  * promiscuous to multicast, since we're always a
844                  * member of the ALL-SYSTEMS group, so there's no
845                  * need to process SIOC*MULTI requests.
846                  */
847                 error = 0;
848                 break;
849         case SIOCSIFMEDIA:
850         case SIOCGIFMEDIA:
851                 if (!sc->epb.mii_trans) {
852                         error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
853                 } else {
854                         error = EINVAL;
855                 }
856                 break;
857         default:
858                 error = ether_ioctl(ifp, cmd, data);
859                 break;
860         }
861
862         crit_exit();
863
864         return (error);
865 }
866
867 static void
868 ep_if_watchdog(struct ifnet *ifp)
869 {
870     struct ep_softc *sc = ifp->if_softc;
871
872     /*
873     if_printf(ifp, "watchdog\n");
874
875     log(LOG_ERR, "%s: watchdog\n", ifp->if_xname);
876     ifp->if_oerrors++;
877     */
878
879     if (sc->gone) {
880         return;
881     }
882
883     ifp->if_flags &= ~IFF_OACTIVE;
884     ep_if_start(ifp);
885     ep_intr(ifp->if_softc);
886 }
887
888 static void
889 epstop(struct ep_softc *sc)
890 {
891     if (sc->gone) {
892         return;
893     }
894
895     outw(BASE + EP_COMMAND, RX_DISABLE);
896     outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
897     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
898     outw(BASE + EP_COMMAND, TX_DISABLE);
899     outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
900     outw(BASE + EP_COMMAND, RX_RESET);
901     outw(BASE + EP_COMMAND, TX_RESET);
902     while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
903     outw(BASE + EP_COMMAND, C_INTR_LATCH);
904     outw(BASE + EP_COMMAND, SET_RD_0_MASK);
905     outw(BASE + EP_COMMAND, SET_INTR_MASK);
906     outw(BASE + EP_COMMAND, SET_RX_FILTER);
907 }