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