The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/if_iy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_iy.c,v 1.63 2003/10/30 01:58:17 simonb Exp $        */
    2 /* #define IYDEBUG */
    3 /* #define IYMEMDEBUG */
    4 
    5 /*-
    6  * Copyright (c) 1996,2001 The NetBSD Foundation, Inc.
    7  * All rights reserved.
    8  *
    9  * This code is derived from software contributed to The NetBSD Foundation
   10  * by Ignatios Souvatzis.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *        This product includes software developed by the NetBSD
   23  *        Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 /*
   42  * Supported hardware:
   43  *
   44  * - Intel EtherExpress Pro/10.
   45  * - possibly other boards using the i82595 chip and no special tweaks.
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __KERNEL_RCSID(0, "$NetBSD: if_iy.c,v 1.63 2003/10/30 01:58:17 simonb Exp $");
   50 
   51 #include "opt_inet.h"
   52 #include "opt_ns.h"
   53 #include "bpfilter.h"
   54 #include "rnd.h"
   55 
   56 #include <sys/param.h>
   57 #include <sys/systm.h>
   58 #include <sys/mbuf.h>
   59 #include <sys/buf.h>
   60 #include <sys/protosw.h>
   61 #include <sys/socket.h>
   62 #include <sys/ioctl.h>
   63 #include <sys/errno.h>
   64 #include <sys/syslog.h>
   65 #include <sys/device.h>
   66 #include <sys/endian.h>
   67 #if NRND > 0
   68 #include <sys/rnd.h>
   69 #endif
   70 
   71 #include <net/if.h>
   72 #include <net/if_types.h>
   73 #include <net/if_dl.h>
   74 
   75 #include <net/if_ether.h>
   76 
   77 #if NBPFILTER > 0
   78 #include <net/bpf.h>
   79 #include <net/bpfdesc.h>
   80 #endif
   81 
   82 #ifdef INET
   83 #include <netinet/in.h>
   84 #include <netinet/in_systm.h>
   85 #include <netinet/in_var.h>
   86 #include <netinet/ip.h>
   87 #include <netinet/if_inarp.h>
   88 #endif
   89 
   90 #ifdef NS
   91 #include <netns/ns.h>
   92 #include <netns/ns_if.h>
   93 #endif
   94 
   95 #if defined(SIOCSIFMEDIA)
   96 #include <net/if_media.h>
   97 #endif
   98 
   99 #include <machine/cpu.h>
  100 #include <machine/bus.h>
  101 #include <machine/intr.h>
  102 
  103 #include <dev/isa/isareg.h>
  104 #include <dev/isa/isavar.h>
  105 #include <dev/ic/i82595reg.h>
  106 
  107 /* XXX why isn't this centralized? */
  108 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
  109 #define bus_space_write_stream_2        bus_space_write_2
  110 #define bus_space_write_multi_stream_2  bus_space_write_multi_2
  111 #define bus_space_read_stream_2         bus_space_read_2
  112 #define bus_space_read_multi_stream_2   bus_space_read_multi_2
  113 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
  114 
  115 /*
  116  * Ethernet status, per interface.
  117  */
  118 struct iy_softc {
  119         struct device sc_dev;
  120         void *sc_ih;
  121 
  122         bus_space_tag_t sc_iot;
  123         bus_space_handle_t sc_ioh;
  124 
  125         struct ethercom sc_ethercom;
  126 
  127         struct ifmedia iy_ifmedia;
  128         int iy_media;
  129 
  130         int mappedirq;
  131 
  132         int hard_vers;
  133 
  134         int promisc;
  135 
  136         int sram, tx_size, rx_size;
  137 
  138         int tx_start, tx_end, tx_last;
  139         int rx_start;
  140 
  141         int doing_mc_setup;
  142 #ifdef IYDEBUG
  143         int sc_debug;
  144 #endif
  145 
  146 #if NRND > 0
  147         rndsource_element_t rnd_source;
  148 #endif
  149 };
  150 
  151 void iywatchdog __P((struct ifnet *));
  152 int iyioctl __P((struct ifnet *, u_long, caddr_t));
  153 int iyintr __P((void *));
  154 void iyinit __P((struct iy_softc *));
  155 void iystop __P((struct iy_softc *));
  156 void iystart __P((struct ifnet *));
  157 
  158 void iy_intr_rx __P((struct iy_softc *));
  159 void iy_intr_tx __P((struct iy_softc *));
  160 
  161 void iyreset __P((struct iy_softc *));
  162 void iy_readframe __P((struct iy_softc *, int));
  163 void iy_drop_packet_buffer __P((struct iy_softc *));
  164 void iy_find_mem_size __P((struct iy_softc *));
  165 void iyrint __P((struct iy_softc *));
  166 void iytint __P((struct iy_softc *));
  167 void iyxmit __P((struct iy_softc *));
  168 static void iy_mc_setup __P((struct iy_softc *));
  169 static void iy_mc_reset __P((struct iy_softc *));
  170 void iyget __P((struct iy_softc *, bus_space_tag_t, bus_space_handle_t, int));
  171 void iyprobemem __P((struct iy_softc *));
  172 static __inline void eepromwritebit __P((bus_space_tag_t, bus_space_handle_t,
  173     int));
  174 static __inline int eepromreadbit __P((bus_space_tag_t, bus_space_handle_t));
  175 
  176 #ifdef IYDEBUGX
  177 void print_rbd __P((volatile struct iy_recv_buf_desc *));
  178 
  179 int in_ifrint = 0;
  180 int in_iftint = 0;
  181 #endif
  182 
  183 int iy_mediachange __P((struct ifnet *));
  184 void iy_mediastatus __P((struct ifnet *, struct ifmediareq *));
  185 
  186 int iyprobe __P((struct device *, struct cfdata *, void *));
  187 void iyattach __P((struct device *, struct device *, void *));
  188 
  189 static u_int16_t eepromread __P((bus_space_tag_t, bus_space_handle_t, int));
  190 
  191 static int eepromreadall __P((bus_space_tag_t, bus_space_handle_t, u_int16_t *,
  192     int));
  193 
  194 CFATTACH_DECL(iy, sizeof(struct iy_softc),
  195     iyprobe, iyattach, NULL, NULL);
  196 
  197 static u_int8_t eepro_irqmap[] = EEPP_INTMAP;
  198 static u_int8_t eepro_revirqmap[] = EEPP_RINTMAP;
  199 
  200 int
  201 iyprobe(parent, match, aux)
  202         struct device *parent;
  203         struct cfdata *match;
  204         void *aux;
  205 {
  206         struct isa_attach_args *ia = aux;
  207         u_int16_t eaddr[8];
  208         bus_space_tag_t iot;
  209         bus_space_handle_t ioh;
  210         u_int8_t c, d;
  211         int irq;
  212 
  213         if (ia->ia_nio < 1)
  214                 return (0);
  215         if (ia->ia_nirq < 1)
  216                 return (0);
  217 
  218         if (ISA_DIRECT_CONFIG(ia))
  219                 return (0);
  220 
  221         iot = ia->ia_iot;
  222 
  223         if (ia->ia_io[0].ir_addr == ISACF_PORT_DEFAULT)
  224                 return 0;
  225 
  226         if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh))
  227                 return 0;
  228 
  229         /* try to find the round robin sig: */
  230 
  231         c = bus_space_read_1(iot, ioh, ID_REG);
  232         if ((c & ID_REG_MASK) != ID_REG_SIG)
  233                 goto out;
  234 
  235         d = bus_space_read_1(iot, ioh, ID_REG);
  236         if ((d & ID_REG_MASK) != ID_REG_SIG)
  237                 goto out;
  238 
  239         if (((d-c) & R_ROBIN_BITS) != 0x40)
  240                 goto out;
  241                 
  242         d = bus_space_read_1(iot, ioh, ID_REG);
  243         if ((d & ID_REG_MASK) != ID_REG_SIG)
  244                 goto out;
  245 
  246         if (((d-c) & R_ROBIN_BITS) != 0x80)
  247                 goto out;
  248                 
  249         d = bus_space_read_1(iot, ioh, ID_REG);
  250         if ((d & ID_REG_MASK) != ID_REG_SIG)
  251                 goto out;
  252 
  253         if (((d-c) & R_ROBIN_BITS) != 0xC0)
  254                 goto out;
  255                 
  256         d = bus_space_read_1(iot, ioh, ID_REG);
  257         if ((d & ID_REG_MASK) != ID_REG_SIG)
  258                 goto out;
  259 
  260         if (((d-c) & R_ROBIN_BITS) != 0x00)
  261                 goto out;
  262                 
  263 #ifdef IYDEBUG
  264                 printf("iyprobe verified working ID reg.\n");
  265 #endif
  266         
  267         if (eepromreadall(iot, ioh, eaddr, 8))
  268                 goto out;
  269         
  270         if (ia->ia_irq[0].ir_irq == ISACF_IRQ_DEFAULT)
  271                 irq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
  272         else
  273                 irq = ia->ia_irq[0].ir_irq;
  274 
  275         if (irq >= sizeof(eepro_revirqmap))
  276                 goto out;
  277 
  278         if (eepro_revirqmap[irq] == 0xff)
  279                 goto out;
  280 
  281         /* now lets reset the chip */
  282         
  283         bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
  284         delay(200);
  285         
  286         ia->ia_nio = 1;
  287         ia->ia_io[0].ir_size = 16;
  288 
  289         ia->ia_nirq = 1;
  290         ia->ia_irq[0].ir_irq = irq;
  291 
  292         ia->ia_niomem = 0;
  293         ia->ia_ndrq = 0;
  294 
  295         bus_space_unmap(iot, ioh, 16);
  296         return 1;               /* found */
  297 out:
  298         bus_space_unmap(iot, ioh, 16);
  299         return 0;
  300 }
  301 
  302 void
  303 iyattach(parent, self, aux)
  304         struct device *parent, *self;
  305         void *aux;
  306 {
  307         struct iy_softc *sc = (void *)self;
  308         struct isa_attach_args *ia = aux;
  309         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  310         bus_space_tag_t iot;
  311         bus_space_handle_t ioh;
  312         unsigned temp;
  313         u_int16_t eaddr[8];
  314         u_int8_t myaddr[ETHER_ADDR_LEN];
  315         int eirq;
  316 
  317         iot = ia->ia_iot;
  318         
  319         if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
  320                 printf(": can't map i/o space\n");
  321                 return;
  322         }
  323 
  324         sc->sc_iot = iot;
  325         sc->sc_ioh = ioh;
  326 
  327         sc->mappedirq = eepro_revirqmap[ia->ia_irq[0].ir_irq];
  328 
  329         /* now let's reset the chip */
  330         
  331         bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
  332         delay(200);
  333         
  334         iyprobemem(sc);
  335 
  336         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  337         ifp->if_softc = sc;
  338         ifp->if_start = iystart;
  339         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS
  340             | IFF_MULTICAST;
  341 
  342         sc->doing_mc_setup = 0;
  343 
  344         ifp->if_ioctl = iyioctl;
  345         ifp->if_watchdog = iywatchdog;
  346 
  347         IFQ_SET_READY(&ifp->if_snd);
  348 
  349         (void)eepromreadall(iot, ioh, eaddr, 8);
  350         sc->hard_vers = eaddr[EEPW6] & EEPP_BoardRev;
  351 
  352 #ifdef DIAGNOSTICS
  353         if ((eaddr[EEPPEther0] != 
  354              eepromread(iot, ioh, EEPPEther0a)) &&
  355             (eaddr[EEPPEther1] != 
  356              eepromread(iot, ioh, EEPPEther1a)) &&
  357             (eaddr[EEPPEther2] != 
  358              eepromread(iot, ioh, EEPPEther2a)))
  359 
  360                 printf("EEPROM Ethernet address differs from copy\n");
  361 #endif
  362 
  363         myaddr[1] = eaddr[EEPPEther0] & 0xFF;
  364         myaddr[0] = eaddr[EEPPEther0] >> 8;
  365         myaddr[3] = eaddr[EEPPEther1] & 0xFF;
  366         myaddr[2] = eaddr[EEPPEther1] >> 8;
  367         myaddr[5] = eaddr[EEPPEther2] & 0xFF;
  368         myaddr[4] = eaddr[EEPPEther2] >> 8;
  369         
  370         ifmedia_init(&sc->iy_ifmedia, 0, iy_mediachange, iy_mediastatus);
  371         ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
  372         ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
  373         ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
  374         ifmedia_add(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
  375         ifmedia_set(&sc->iy_ifmedia, IFM_ETHER | IFM_AUTO);
  376         /* Attach the interface. */
  377         if_attach(ifp);
  378         ether_ifattach(ifp, myaddr);
  379         printf(": address %s, rev. %d, %d kB\n",
  380             ether_sprintf(myaddr),
  381             sc->hard_vers, sc->sram/1024);
  382 
  383         eirq = eepro_irqmap[eaddr[EEPPW1] & EEPP_Int];
  384         if (eirq != ia->ia_irq[0].ir_irq)
  385                 printf("%s: EEPROM irq setting %d ignored\n",
  386                     sc->sc_dev.dv_xname, eirq);
  387 
  388         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
  389             IST_EDGE, IPL_NET, iyintr, sc);
  390 
  391 #if NRND > 0
  392         rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
  393                           RND_TYPE_NET, 0);
  394 #endif
  395 
  396         temp = bus_space_read_1(iot, ioh, INT_NO_REG);
  397         bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
  398 }
  399 
  400 void
  401 iystop(sc)
  402 struct iy_softc *sc;
  403 {
  404         bus_space_tag_t iot;
  405         bus_space_handle_t ioh;
  406 #ifdef IYDEBUG
  407         u_int p, v;
  408 #endif
  409 
  410         iot = sc->sc_iot;
  411         ioh = sc->sc_ioh;
  412         
  413         bus_space_write_1(iot, ioh, COMMAND_REG, RCV_DISABLE_CMD);
  414 
  415         bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
  416         bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS);
  417 
  418         bus_space_write_1(iot, ioh, COMMAND_REG, RESET_CMD);
  419         delay(200);
  420 #ifdef IYDEBUG 
  421         printf("%s: dumping tx chain (st 0x%x end 0x%x last 0x%x)\n", 
  422                     sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
  423         p = sc->tx_last;
  424         if (!p)
  425                 p = sc->tx_start;
  426         do {
  427                 char sbuf[128];
  428 
  429                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, p);
  430 
  431                 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
  432                 bitmask_snprintf(v, "\020\006Ab\010Dn", sbuf, sizeof(sbuf));
  433                 printf("0x%04x: %s ", p, sbuf);
  434 
  435                 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
  436                 bitmask_snprintf(v, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL",
  437                                  sbuf, sizeof(sbuf));
  438                 printf("0x%s", sbuf);
  439 
  440                 p = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
  441                 printf(" 0x%04x", p);
  442 
  443                 v = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
  444                 bitmask_snprintf(v, "\020\020Ch", sbuf, sizeof(sbuf));
  445                 printf(" 0x%s\n", sbuf);
  446 
  447         } while (v & 0x8000);
  448 #endif
  449         sc->tx_start = sc->tx_end = sc->rx_size;
  450         sc->tx_last = 0;
  451         sc->sc_ethercom.ec_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
  452 }
  453 
  454 void
  455 iyreset(sc)
  456 struct iy_softc *sc;
  457 {
  458         int s;
  459         s = splnet();
  460         iystop(sc);
  461         iyinit(sc);
  462         splx(s);
  463 }
  464 
  465 void
  466 iyinit(sc)
  467 struct iy_softc *sc;
  468 {
  469         int i;
  470         unsigned temp;
  471         struct ifnet *ifp;
  472         bus_space_tag_t iot;
  473         bus_space_handle_t ioh;
  474 
  475         iot = sc->sc_iot;
  476         ioh = sc->sc_ioh;
  477 
  478         ifp = &sc->sc_ethercom.ec_if;
  479 #ifdef IYDEBUG
  480         printf("ifp is %p\n", ifp);
  481 #endif
  482 
  483         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
  484 
  485         temp = bus_space_read_1(iot, ioh, EEPROM_REG);
  486         if (temp & 0x10)
  487                 bus_space_write_1(iot, ioh, EEPROM_REG, temp & ~0x10);
  488         
  489         for (i=0; i<6; ++i) {
  490                 bus_space_write_1(iot, ioh, I_ADD(i), LLADDR(ifp->if_sadl)[i]);
  491         }
  492 
  493         temp = bus_space_read_1(iot, ioh, REG1);
  494         bus_space_write_1(iot, ioh, REG1,
  495             temp | /* XMT_CHAIN_INT | XMT_CHAIN_ERRSTOP | */ RCV_DISCARD_BAD);
  496         
  497         if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
  498                 temp = MATCH_ALL;
  499         } else 
  500                 temp = MATCH_BRDCST;
  501 
  502         bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
  503 
  504 #ifdef IYDEBUG
  505         {
  506                 char sbuf[128];
  507 
  508                 bitmask_snprintf(temp, "\020\1PRMSC\2NOBRDST\3SEECRC\4LENGTH\5NOSaIns\6MultiIA",
  509                                  sbuf, sizeof(sbuf));
  510                 printf("%s: RECV_MODES set to %s\n", sc->sc_dev.dv_xname, sbuf);
  511         }
  512 #endif
  513         /* XXX VOODOO */
  514         temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
  515         bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
  516         /* XXX END OF VOODOO */
  517 
  518 
  519         delay(500000); /* for the hardware to test for the connector */
  520 
  521         temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
  522 #ifdef IYDEBUG
  523         {
  524                 char sbuf[128];
  525 
  526                 bitmask_snprintf(temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
  527                                  sbuf, sizeof(sbuf));
  528                 printf("%s: media select was 0x%s ", sc->sc_dev.dv_xname, sbuf);
  529         }
  530 #endif
  531         temp = (temp & TEST_MODE_MASK);
  532  
  533         switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
  534         case IFM_10_5:
  535                 temp &= ~ (BNC_BIT | TPE_BIT);
  536                 break;
  537 
  538         case IFM_10_2:
  539                 temp = (temp & ~TPE_BIT) | BNC_BIT;
  540                 break;
  541  
  542         case IFM_10_T:
  543                 temp = (temp & ~BNC_BIT) | TPE_BIT;
  544                 break;
  545         default:
  546                 ;
  547                 /* nothing; leave as it is */
  548         }
  549         switch (temp & (BNC_BIT | TPE_BIT)) {
  550         case BNC_BIT:
  551                 sc->iy_media = IFM_ETHER | IFM_10_2;
  552                 break;
  553         case TPE_BIT:
  554                 sc->iy_media = IFM_ETHER | IFM_10_T;
  555                 break;
  556         default:
  557                 sc->iy_media = IFM_ETHER | IFM_10_5;
  558         }
  559 
  560         bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
  561 #ifdef IYDEBUG
  562         {
  563                 char sbuf[128];
  564 
  565                 bitmask_snprintf(temp, "\020\1LnkInDis\2PolCor\3TPE\4JabberDis\5NoAport\6BNC",
  566                                  sbuf, sizeof(sbuf));
  567                 printf("changed to 0x%s\n", sbuf);
  568         }
  569 #endif
  570 
  571         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
  572         bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS);
  573         bus_space_write_1(iot, ioh, 0, BANK_SEL(1));
  574 
  575         temp = bus_space_read_1(iot, ioh, INT_NO_REG);
  576         bus_space_write_1(iot, ioh, INT_NO_REG, (temp & 0xf8) | sc->mappedirq);
  577 
  578 #ifdef IYDEBUG
  579         {
  580                 char sbuf[128];
  581 
  582                 bitmask_snprintf(temp, "\020\4bad_irq\010flash/boot present",
  583                                  sbuf, sizeof(sbuf));
  584                 printf("%s: int no was %s\n", sc->sc_dev.dv_xname, sbuf);
  585 
  586                 temp = bus_space_read_1(iot, ioh, INT_NO_REG);
  587                 bitmask_snprintf(temp, "\020\4bad_irq\010flash/boot present",
  588                                  sbuf, sizeof(sbuf));
  589                 printf("%s: int no now %s\n", sc->sc_dev.dv_xname, sbuf);
  590         }
  591 #endif
  592 
  593         bus_space_write_1(iot, ioh, RCV_LOWER_LIMIT_REG, 0);
  594         bus_space_write_1(iot, ioh, RCV_UPPER_LIMIT_REG, (sc->rx_size -2) >>8);
  595         bus_space_write_1(iot, ioh, XMT_LOWER_LIMIT_REG, sc->rx_size >>8);
  596         bus_space_write_1(iot, ioh, XMT_UPPER_LIMIT_REG, (sc->sram - 2) >>8);
  597 
  598         temp = bus_space_read_1(iot, ioh, REG1);
  599 #ifdef IYDEBUG
  600         {
  601                 char sbuf[128];
  602 
  603                 bitmask_snprintf(temp, "\020\2WORD_WIDTH\010INT_ENABLE",
  604                                  sbuf, sizeof(sbuf));
  605                 printf("%s: HW access is %s\n", sc->sc_dev.dv_xname, sbuf);
  606         }
  607 #endif
  608         bus_space_write_1(iot, ioh, REG1, temp | INT_ENABLE); /* XXX what about WORD_WIDTH? */
  609 
  610 #ifdef IYDEBUG
  611         {
  612                 char sbuf[128];
  613 
  614                 temp = bus_space_read_1(iot, ioh, REG1);
  615                 bitmask_snprintf(temp, "\020\2WORD_WIDTH\010INT_ENABLE",
  616                                  sbuf, sizeof(sbuf));
  617                 printf("%s: HW access is %s\n", sc->sc_dev.dv_xname, sbuf);
  618         }
  619 #endif
  620 
  621         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
  622 
  623         bus_space_write_1(iot, ioh, INT_MASK_REG, ALL_INTS & ~(RX_BIT|TX_BIT));
  624         bus_space_write_1(iot, ioh, STATUS_REG, ALL_INTS); /* clear ints */
  625 
  626         bus_space_write_1(iot, ioh, RCV_COPY_THRESHOLD, 0);
  627 
  628         bus_space_write_2(iot, ioh, RCV_START_LOW, 0);
  629         bus_space_write_2(iot, ioh, RCV_STOP_LOW,  sc->rx_size - 2);
  630         sc->rx_start = 0;
  631 
  632         bus_space_write_1(iot, ioh, 0, SEL_RESET_CMD);
  633         delay(200);
  634 
  635         bus_space_write_2(iot, ioh, XMT_ADDR_REG, sc->rx_size);
  636 
  637         sc->tx_start = sc->tx_end = sc->rx_size;
  638         sc->tx_last = 0;
  639 
  640         bus_space_write_1(iot, ioh, 0, RCV_ENABLE_CMD);
  641 
  642         ifp->if_flags |= IFF_RUNNING;
  643         ifp->if_flags &= ~IFF_OACTIVE;
  644 }
  645 
  646 void
  647 iystart(ifp)
  648 struct ifnet *ifp;
  649 {
  650         struct iy_softc *sc;
  651 
  652 
  653         struct mbuf *m0, *m;
  654         u_int len, pad, last, end;
  655         u_int llen, residual;
  656         int avail;
  657         caddr_t data;
  658         unsigned temp;
  659         u_int16_t resval, stat;
  660         bus_space_tag_t iot;
  661         bus_space_handle_t ioh;
  662 
  663 #ifdef IYDEBUG
  664         printf("iystart called\n");
  665 #endif
  666         sc = ifp->if_softc;
  667 
  668         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
  669                 return;
  670 
  671         iy_intr_tx(sc);
  672 
  673         iot = sc->sc_iot;
  674         ioh = sc->sc_ioh;
  675 
  676         for (;;) {
  677                 IFQ_POLL(&ifp->if_snd, m0);
  678                 if (m0 == NULL)
  679                         break;
  680 #ifdef IYDEBUG
  681                 printf("%s: trying to write another packet to the hardware\n",
  682                     sc->sc_dev.dv_xname);
  683 #endif
  684 
  685                 /* We need to use m->m_pkthdr.len, so require the header */
  686                 if ((m0->m_flags & M_PKTHDR) == 0)
  687                         panic("iystart: no header mbuf");
  688 
  689                 len = m0->m_pkthdr.len;
  690                 pad = len & 1;
  691 
  692 #ifdef IYDEBUG
  693                 printf("%s: length is %d.\n", sc->sc_dev.dv_xname, len);
  694 #endif
  695                 if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
  696                         pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
  697                 }
  698 
  699                 if (len + pad > ETHER_MAX_LEN) {
  700                         /* packet is obviously too large: toss it */
  701                         ++ifp->if_oerrors;
  702                         IFQ_DEQUEUE(&ifp->if_snd, m0);
  703                         m_freem(m0);
  704                         continue;
  705                 }
  706 
  707 #if NBPFILTER > 0
  708                 if (ifp->if_bpf)
  709                         bpf_mtap(ifp->if_bpf, m0);
  710 #endif
  711 
  712                 avail = sc->tx_start - sc->tx_end;
  713                 if (avail <= 0)
  714                         avail += sc->tx_size;
  715 
  716 #ifdef IYDEBUG
  717                 printf("%s: avail is %d.\n", sc->sc_dev.dv_xname, avail);
  718 #endif
  719                 /* 
  720                  * we MUST RUN at splnet here  --- 
  721                  * XXX todo: or even turn off the boards ints ??? hm... 
  722                  */
  723         
  724                 /* See if there is room to put another packet in the buffer. */
  725         
  726                 if ((len+pad+2*I595_XMT_HDRLEN) > avail) {
  727 #ifdef IYDEBUG
  728                         printf("%s: len = %d, avail = %d, setting OACTIVE\n",
  729                             sc->sc_dev.dv_xname, len, avail);
  730 #endif
  731                         /* mark interface as full ... */
  732                         ifp->if_flags |= IFF_OACTIVE;
  733 
  734                         /* and wait for any transmission result */
  735                         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
  736 
  737                         temp = bus_space_read_1(iot, ioh, REG1);
  738                         bus_space_write_1(iot, ioh, REG1,
  739                                 temp & ~XMT_CHAIN_INT);
  740 
  741                         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
  742 
  743                         return;
  744                 }
  745         
  746                 /* we know it fits in the hardware now, so dequeue it */
  747                 IFQ_DEQUEUE(&ifp->if_snd, m0);
  748                 
  749                 last = sc->tx_end;
  750                 end = last + pad + len + I595_XMT_HDRLEN; 
  751                 
  752                 if (end >= sc->sram) {
  753                         if ((sc->sram - last) <= I595_XMT_HDRLEN) {
  754                                 /* keep header in one piece */
  755                                 last = sc->rx_size;
  756                                 end = last + pad + len + I595_XMT_HDRLEN;
  757                         } else
  758                                 end -= sc->tx_size;
  759                 }
  760 
  761                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
  762                 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
  763                         htole16(XMT_CMD));
  764 
  765                 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
  766                 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
  767 
  768                 bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, 
  769                         htole16(len + pad));
  770 
  771                 residual = resval = 0;
  772 
  773                 while ((m = m0)!=0) {
  774                         data = mtod(m, caddr_t);
  775                         llen = m->m_len;
  776                         if (residual) {
  777 #ifdef IYDEBUG
  778                                 printf("%s: merging residual with next mbuf.\n",
  779                                     sc->sc_dev.dv_xname);
  780 #endif
  781                                 resval |= *data << 8;
  782                                 bus_space_write_stream_2(iot, ioh,
  783                                         MEM_PORT_REG, resval);
  784                                 --llen;
  785                                 ++data;
  786                         }
  787                         if (llen > 1)
  788                                 bus_space_write_multi_stream_2(iot, ioh,
  789                                         MEM_PORT_REG, data, llen>>1);
  790                         residual = llen & 1;
  791                         if (residual) {
  792                                 resval = *(data + llen - 1);
  793 #ifdef IYDEBUG
  794                                 printf("%s: got odd mbuf to send.\n",
  795                                     sc->sc_dev.dv_xname);
  796 #endif
  797                         }
  798 
  799                         MFREE(m, m0);
  800                 }
  801 
  802                 if (residual)
  803                         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
  804                                 resval);
  805 
  806                 pad >>= 1;
  807                 while (pad-- > 0)
  808                         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, 0);
  809                         
  810 #ifdef IYDEBUG
  811                 printf("%s: new last = 0x%x, end = 0x%x.\n",
  812                     sc->sc_dev.dv_xname, last, end);
  813                 printf("%s: old start = 0x%x, end = 0x%x, last = 0x%x\n",
  814                     sc->sc_dev.dv_xname, sc->tx_start, sc->tx_end, sc->tx_last);
  815 #endif
  816 
  817                 if (sc->tx_start != sc->tx_end) {
  818                         bus_space_write_2(iot, ioh, HOST_ADDR_REG,
  819                                 sc->tx_last + XMT_COUNT);
  820 
  821                         /*
  822                          * XXX We keep stat in le order, to potentially save
  823                          * a byte swap.
  824                          */
  825                         stat = bus_space_read_stream_2(iot, ioh, MEM_PORT_REG);
  826 
  827                         bus_space_write_2(iot, ioh, HOST_ADDR_REG,
  828                                 sc->tx_last + XMT_CHAIN);
  829 
  830                         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
  831                                 htole16(last));
  832 
  833                         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG,
  834                                 stat | htole16(CHAIN));
  835 #ifdef IYDEBUG
  836                         printf("%s: setting 0x%x to 0x%x\n",
  837                             sc->sc_dev.dv_xname, sc->tx_last + XMT_COUNT, 
  838                             le16toh(stat) | CHAIN);
  839 #endif
  840                 }
  841                 stat = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
  842 
  843                 /* XXX todo: enable ints here if disabled */
  844                 
  845                 ++ifp->if_opackets;
  846 
  847                 if (sc->tx_start == sc->tx_end) {
  848                         bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
  849                         bus_space_write_1(iot, ioh, 0, XMT_CMD);
  850                         sc->tx_start = last;
  851 #ifdef IYDEBUG
  852                         printf("%s: writing 0x%x to XAR and giving XCMD\n",
  853                             sc->sc_dev.dv_xname, last);
  854 #endif
  855                 } else {
  856                         bus_space_write_1(iot, ioh, 0, RESUME_XMT_CMD);
  857 #ifdef IYDEBUG
  858                         printf("%s: giving RESUME_XCMD\n",
  859                             sc->sc_dev.dv_xname);
  860 #endif
  861                 }
  862                 sc->tx_last = last;
  863                 sc->tx_end = end;
  864         }
  865         /* and wait only for end of transmission chain */
  866         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
  867 
  868         temp = bus_space_read_1(iot, ioh, REG1);
  869         bus_space_write_1(iot, ioh, REG1, temp | XMT_CHAIN_INT);
  870 
  871         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
  872 }
  873 
  874 
  875 static __inline void
  876 eepromwritebit(iot, ioh, what) 
  877         bus_space_tag_t iot;
  878         bus_space_handle_t ioh;
  879         int what;
  880 {
  881         bus_space_write_1(iot, ioh, EEPROM_REG, what);
  882         delay(1);
  883         bus_space_write_1(iot, ioh, EEPROM_REG, what|EESK);
  884         delay(1);
  885         bus_space_write_1(iot, ioh, EEPROM_REG, what);
  886         delay(1);
  887 }
  888 
  889 static __inline int
  890 eepromreadbit(iot, ioh) 
  891         bus_space_tag_t iot;
  892         bus_space_handle_t ioh;
  893 {
  894         int b; 
  895 
  896         bus_space_write_1(iot, ioh, EEPROM_REG, EECS|EESK); 
  897         delay(1);
  898         b = bus_space_read_1(iot, ioh, EEPROM_REG);
  899         bus_space_write_1(iot, ioh, EEPROM_REG, EECS);
  900         delay(1);
  901 
  902         return ((b & EEDO) != 0);
  903 }
  904 
  905 static u_int16_t
  906 eepromread(iot, ioh, offset)
  907         bus_space_tag_t iot;
  908         bus_space_handle_t ioh;
  909         int offset;
  910 {
  911         volatile int i;
  912         volatile int j;
  913         volatile u_int16_t readval;
  914 
  915         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
  916         delay(1);
  917         bus_space_write_1(iot, ioh, EEPROM_REG, EECS); /* XXXX??? */
  918         delay(1);
  919         
  920         eepromwritebit(iot, ioh, EECS|EEDI);
  921         eepromwritebit(iot, ioh, EECS|EEDI);
  922         eepromwritebit(iot, ioh, EECS);
  923         
  924         for (j=5; j>=0; --j) {
  925                 if ((offset>>j) & 1) 
  926                         eepromwritebit(iot, ioh, EECS|EEDI);
  927                 else
  928                         eepromwritebit(iot, ioh, EECS);
  929         }
  930 
  931         for (readval=0, i=0; i<16; ++i) {
  932                 readval<<=1;
  933                 readval |= eepromreadbit(iot, ioh);
  934         }
  935 
  936         bus_space_write_1(iot, ioh, EEPROM_REG, 0|EESK);
  937         delay(1);
  938         bus_space_write_1(iot, ioh, EEPROM_REG, 0);
  939 
  940         bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
  941 
  942         return readval;
  943 }
  944 
  945 /*
  946  * Device timeout/watchdog routine.  Entered if the device neglects to generate
  947  * an interrupt after a transmit has been started on it.
  948  */
  949 void
  950 iywatchdog(ifp)
  951         struct ifnet *ifp;
  952 {
  953         struct iy_softc *sc = ifp->if_softc;
  954 
  955         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
  956         ++sc->sc_ethercom.ec_if.if_oerrors;
  957         iyreset(sc);
  958 }
  959 
  960 /*
  961  * What to do upon receipt of an interrupt.
  962  */
  963 int
  964 iyintr(arg)
  965         void *arg;
  966 {
  967         struct iy_softc *sc;
  968         struct ifnet *ifp;
  969         bus_space_tag_t iot;
  970         bus_space_handle_t ioh;
  971 
  972         u_short status;
  973 
  974         sc = arg;
  975         iot = sc->sc_iot;
  976         ioh = sc->sc_ioh;
  977 
  978         ifp = &sc->sc_ethercom.ec_if;
  979 
  980         status = bus_space_read_1(iot, ioh, STATUS_REG);
  981 #ifdef IYDEBUG
  982         if (status & ALL_INTS) {
  983                 char sbuf[128];
  984 
  985                 bitmask_snprintf(status, "\020\1RX_STP\2RX\3TX\4EXEC",
  986                                  sbuf, sizeof(sbuf));
  987                 printf("%s: got interrupt %s", sc->sc_dev.dv_xname, sbuf);
  988 
  989                 if (status & EXEC_INT) {
  990                         bitmask_snprintf(bus_space_read_1(iot, ioh, 0),
  991                                          "\020\6ABORT", sbuf, sizeof(sbuf));
  992                         printf(" event %s\n", sbuf);
  993                 } else
  994                         printf("\n");
  995         }
  996 #endif
  997         if ((status & (RX_INT | TX_INT)) == 0)
  998                 return 0;
  999 
 1000         if (status & RX_INT) {
 1001                 iy_intr_rx(sc);
 1002                 bus_space_write_1(iot, ioh, STATUS_REG, RX_INT);
 1003         }
 1004         if (status & TX_INT) {
 1005                 /* Tell feeders we may be able to accept more data... */
 1006                 ifp->if_flags &= ~IFF_OACTIVE;
 1007                 /* and get more data. */
 1008                 iystart(ifp);
 1009                 bus_space_write_1(iot, ioh, STATUS_REG, TX_INT);
 1010         }
 1011 
 1012 #if NRND > 0
 1013         rnd_add_uint32(&sc->rnd_source, status);
 1014 #endif
 1015 
 1016         return 1;
 1017 }
 1018 
 1019 void
 1020 iyget(sc, iot, ioh, rxlen)
 1021         struct iy_softc *sc;
 1022         bus_space_tag_t iot;
 1023         bus_space_handle_t ioh;
 1024         int rxlen;
 1025 {
 1026         struct mbuf *m, *top, **mp;
 1027         struct ifnet *ifp;
 1028         int len;
 1029 
 1030         ifp = &sc->sc_ethercom.ec_if;
 1031 
 1032         MGETHDR(m, M_DONTWAIT, MT_DATA);
 1033         if (m == 0)
 1034                 goto dropped;
 1035         m->m_pkthdr.rcvif = ifp;
 1036         m->m_pkthdr.len = rxlen;
 1037         len = MHLEN;
 1038         top = 0;
 1039         mp = &top;
 1040 
 1041         while (rxlen > 0) {
 1042                 if (top) {
 1043                         MGET(m, M_DONTWAIT, MT_DATA);
 1044                         if (m == 0) {
 1045                                 m_freem(top);
 1046                                 goto dropped;
 1047                         }
 1048                         len = MLEN;
 1049                 }
 1050                 if (rxlen >= MINCLSIZE) {
 1051                         MCLGET(m, M_DONTWAIT);
 1052                         if ((m->m_flags & M_EXT) == 0) {
 1053                                 m_free(m);
 1054                                 m_freem(top);
 1055                                 goto dropped;
 1056                         }
 1057                         len = MCLBYTES;
 1058                 }
 1059                 len = min(rxlen, len);
 1060                 if (len > 1) {
 1061                         len &= ~1;
 1062 
 1063                         bus_space_read_multi_stream_2(iot, ioh, MEM_PORT_REG, 
 1064                             mtod(m, caddr_t), len/2);
 1065                 } else {
 1066 #ifdef IYDEBUG
 1067                         printf("%s: received odd mbuf\n", sc->sc_dev.dv_xname);
 1068 #endif
 1069                         *(mtod(m, caddr_t)) = bus_space_read_stream_2(iot, ioh, 
 1070                             MEM_PORT_REG);
 1071                 }
 1072                 m->m_len = len;
 1073                 rxlen -= len;
 1074                 *mp = m;
 1075                 mp = &m->m_next;
 1076         }
 1077         /* XXX receive the top here */  
 1078         ++ifp->if_ipackets;
 1079 
 1080 #if NBPFILTER > 0
 1081         if (ifp->if_bpf)
 1082                 bpf_mtap(ifp->if_bpf, top);
 1083 #endif
 1084         (*ifp->if_input)(ifp, top);
 1085         return;
 1086 
 1087 dropped:
 1088         ++ifp->if_ierrors;
 1089         return;
 1090 }
 1091 
 1092 void
 1093 iy_intr_rx(sc)
 1094 struct iy_softc *sc;
 1095 {
 1096         bus_space_tag_t iot;
 1097         bus_space_handle_t ioh;
 1098 
 1099         u_int rxadrs, rxevnt, rxstatus, rxnext, rxlen;
 1100 
 1101         iot = sc->sc_iot;
 1102         ioh = sc->sc_ioh;
 1103 
 1104         rxadrs = sc->rx_start;
 1105         bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxadrs);
 1106         rxevnt = le16toh(bus_space_read_stream_2(iot, ioh, MEM_PORT_REG));
 1107         rxnext = 0;
 1108         
 1109         while (rxevnt == RCV_DONE) {
 1110                 rxstatus = le16toh(bus_space_read_stream_2(iot, ioh,
 1111                                 MEM_PORT_REG));
 1112                 rxnext = le16toh(bus_space_read_stream_2(iot, ioh,
 1113                                 MEM_PORT_REG));
 1114                 rxlen = le16toh(bus_space_read_stream_2(iot, ioh,
 1115                                 MEM_PORT_REG));
 1116 #ifdef IYDEBUG
 1117                 {
 1118                         char sbuf[128];
 1119 
 1120                         bitmask_snprintf(rxstatus, "\020\1RCLD\2IA_MCH\010SHORT\011OVRN\013ALGERR\014CRCERR\015LENERR\016RCVOK\020TYP",
 1121                                          sbuf, sizeof(sbuf));
 1122                         printf("%s: pck at 0x%04x stat %s next 0x%x len 0x%x\n",
 1123                             sc->sc_dev.dv_xname, rxadrs, sbuf, rxnext, rxlen);
 1124                 }
 1125 #endif
 1126                 iyget(sc, iot, ioh, rxlen);
 1127 
 1128                 /* move stop address */
 1129                 bus_space_write_2(iot, ioh, RCV_STOP_LOW,
 1130                             rxnext == 0 ? sc->rx_size - 2 : rxnext - 2);
 1131 
 1132                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, rxnext);
 1133                 rxadrs = rxnext;
 1134                 rxevnt = le16toh(bus_space_read_stream_2(iot, ioh,
 1135                                 MEM_PORT_REG));
 1136         }
 1137         sc->rx_start = rxnext;
 1138 }
 1139 
 1140 void
 1141 iy_intr_tx(sc)
 1142 struct iy_softc *sc;
 1143 {
 1144         bus_space_tag_t iot;
 1145         bus_space_handle_t ioh;
 1146         struct ifnet *ifp;
 1147         u_int txstatus, txstat2, txlen, txnext;
 1148 
 1149         ifp = &sc->sc_ethercom.ec_if;
 1150         iot = sc->sc_iot;
 1151         ioh = sc->sc_ioh;
 1152 
 1153         while (sc->tx_start != sc->tx_end) {
 1154                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, sc->tx_start);
 1155                 txstatus = le16toh(bus_space_read_stream_2(iot, ioh,
 1156                         MEM_PORT_REG));
 1157 
 1158                 if ((txstatus & (TX_DONE|CMD_MASK)) != (TX_DONE|XMT_CMD))
 1159                         break;
 1160 
 1161                 txstat2 = le16toh(bus_space_read_stream_2(iot, ioh,
 1162                                 MEM_PORT_REG));
 1163                 txnext = le16toh(bus_space_read_stream_2(iot, ioh,
 1164                                 MEM_PORT_REG));
 1165                 txlen = le16toh(bus_space_read_stream_2(iot, ioh,
 1166                                 MEM_PORT_REG));
 1167 #ifdef IYDEBUG
 1168                 {
 1169                         char sbuf[128];
 1170 
 1171                         bitmask_snprintf(txstat2, "\020\6MAX_COL\7HRT_BEAT\010TX_DEF\011UND_RUN\012JERR\013LST_CRS\014LTCOL\016TX_OK\020COLL",
 1172                                          sbuf, sizeof(sbuf));
 1173                         printf("txstat 0x%x stat2 0x%s next 0x%x len 0x%x\n",
 1174                                txstatus, sbuf, txnext, txlen);
 1175                 }
 1176 #endif
 1177                 if (txlen & CHAIN)
 1178                         sc->tx_start = txnext;
 1179                 else
 1180                         sc->tx_start = sc->tx_end;
 1181                 ifp->if_flags &= ~IFF_OACTIVE;
 1182                 
 1183                 if (txstat2 & 0x0020)
 1184                         ifp->if_collisions += 16;
 1185                 else
 1186                         ifp->if_collisions += txstat2 & 0x000f;
 1187 
 1188                 if ((txstat2 & 0x2000) == 0)
 1189                         ++ifp->if_oerrors;
 1190         }
 1191 }
 1192 
 1193 int
 1194 iyioctl(ifp, cmd, data)
 1195         struct ifnet *ifp;
 1196         u_long cmd;
 1197         caddr_t data;
 1198 {
 1199         struct iy_softc *sc;
 1200         struct ifaddr *ifa;
 1201         struct ifreq *ifr;
 1202         int s, error = 0;
 1203 
 1204         sc = ifp->if_softc;
 1205         ifa = (struct ifaddr *)data;
 1206         ifr = (struct ifreq *)data;
 1207 
 1208 #ifdef IYDEBUG
 1209         printf("iyioctl called with ifp 0x%p (%s) cmd 0x%lx data 0x%p\n", 
 1210             ifp, ifp->if_xname, cmd, data);
 1211 #endif
 1212 
 1213         s = splnet();
 1214 
 1215         switch (cmd) {
 1216 
 1217         case SIOCSIFADDR:
 1218                 ifp->if_flags |= IFF_UP;
 1219 
 1220                 switch (ifa->ifa_addr->sa_family) {
 1221 #ifdef INET
 1222                 case AF_INET:
 1223                         iyinit(sc);
 1224                         arp_ifinit(ifp, ifa);
 1225                         break;
 1226 #endif
 1227 #ifdef NS
 1228                 /* XXX - This code is probably wrong. */
 1229                 case AF_NS:
 1230                     {
 1231                         struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
 1232 
 1233                         if (ns_nullhost(*ina))
 1234                                 ina->x_host = *(union ns_host *)
 1235                                     LLADDR(ifp->if_sadl);
 1236                         else
 1237                                 memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
 1238                                     ETHER_ADDR_LEN);
 1239                         /* Set new address. */
 1240                         iyinit(sc);
 1241                         break;
 1242                     }
 1243 #endif /* NS */
 1244                 default:
 1245                         iyinit(sc);
 1246                         break;
 1247                 }
 1248                 break;
 1249 
 1250         case SIOCSIFFLAGS:
 1251                 sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
 1252                 if ((ifp->if_flags & IFF_UP) == 0 &&
 1253                     (ifp->if_flags & IFF_RUNNING) != 0) {
 1254                         /*
 1255                          * If interface is marked down and it is running, then
 1256                          * stop it.
 1257                          */
 1258                         iystop(sc);
 1259                         ifp->if_flags &= ~IFF_RUNNING;
 1260                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
 1261                            (ifp->if_flags & IFF_RUNNING) == 0) {
 1262                         /*
 1263                          * If interface is marked up and it is stopped, then
 1264                          * start it.
 1265                          */
 1266                         iyinit(sc);
 1267                 } else {
 1268                         /*
 1269                          * Reset the interface to pick up changes in any other
 1270                          * flags that affect hardware registers.
 1271                          */
 1272                         iystop(sc);
 1273                         iyinit(sc);
 1274                 }
 1275 #ifdef IYDEBUGX
 1276                 if (ifp->if_flags & IFF_DEBUG)
 1277                         sc->sc_debug = IFY_ALL;
 1278                 else
 1279                         sc->sc_debug = 0;
 1280 #endif
 1281                 break;
 1282 
 1283         case SIOCADDMULTI:
 1284         case SIOCDELMULTI:
 1285                 error = (cmd == SIOCADDMULTI) ?
 1286                     ether_addmulti(ifr, &sc->sc_ethercom):
 1287                     ether_delmulti(ifr, &sc->sc_ethercom);
 1288 
 1289                 if (error == ENETRESET) {
 1290                         /*
 1291                          * Multicast list has changed; set the hardware filter
 1292                          * accordingly.
 1293                          */
 1294                         iyreset(sc); /* XXX can't make it work otherwise */
 1295                         iy_mc_reset(sc);
 1296                         error = 0;
 1297                 }
 1298                 break;
 1299 
 1300         case SIOCSIFMEDIA:
 1301         case SIOCGIFMEDIA:
 1302                 error = ifmedia_ioctl(ifp, ifr, &sc->iy_ifmedia, cmd);
 1303                 break;
 1304         default:
 1305                 error = EINVAL;
 1306         }
 1307         splx(s);
 1308         return error;
 1309 }
 1310 
 1311 int
 1312 iy_mediachange(ifp)
 1313         struct ifnet *ifp;
 1314 {
 1315         struct iy_softc *sc = ifp->if_softc;
 1316 
 1317         if (IFM_TYPE(sc->iy_ifmedia.ifm_media) != IFM_ETHER)
 1318             return EINVAL;
 1319         switch(IFM_SUBTYPE(sc->iy_ifmedia.ifm_media)) {
 1320         case IFM_10_5:
 1321         case IFM_10_2:
 1322         case IFM_10_T:
 1323         case IFM_AUTO:
 1324             iystop(sc);
 1325             iyinit(sc);
 1326             return 0;
 1327         default:
 1328             return EINVAL;
 1329         }
 1330 }
 1331 
 1332 void
 1333 iy_mediastatus(ifp, ifmr)
 1334         struct ifnet *ifp;
 1335         struct ifmediareq *ifmr;
 1336 {
 1337         struct iy_softc *sc = ifp->if_softc;
 1338 
 1339         ifmr->ifm_active = sc->iy_media;
 1340         ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
 1341 }
 1342 
 1343 
 1344 static void
 1345 iy_mc_setup(sc)
 1346         struct iy_softc *sc;
 1347 {
 1348         struct ether_multi *enm;
 1349         struct ether_multistep step;
 1350         struct ethercom *ecp;
 1351         struct ifnet *ifp;
 1352         bus_space_tag_t iot;
 1353         bus_space_handle_t ioh;
 1354         int avail, last /*, end*/ , len;
 1355         int timeout;
 1356         volatile u_int16_t dum;
 1357         u_int8_t temp;
 1358         
 1359 
 1360         ecp = &sc->sc_ethercom;
 1361         ifp = &ecp->ec_if;
 1362 
 1363         iot = sc->sc_iot;
 1364         ioh = sc->sc_ioh;
 1365 
 1366         len = 6 * ecp->ec_multicnt;
 1367         
 1368         avail = sc->tx_start - sc->tx_end;
 1369         if (avail <= 0)
 1370                 avail += sc->tx_size;
 1371         if (ifp->if_flags & IFF_DEBUG)
 1372                 printf("%s: iy_mc_setup called, %d addresses, "
 1373                     "%d/%d bytes needed/avail\n", ifp->if_xname, 
 1374                     ecp->ec_multicnt, len + I595_XMT_HDRLEN, avail);
 1375 
 1376         last = sc->rx_size;
 1377 
 1378         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
 1379         bus_space_write_1(iot, ioh, RECV_MODES_REG, MATCH_BRDCST);
 1380         /* XXX VOODOO */
 1381         temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
 1382         bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
 1383         /* XXX END OF VOODOO */
 1384         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
 1385         bus_space_write_2(iot, ioh, HOST_ADDR_REG, last);
 1386         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(MC_SETUP_CMD));
 1387         bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
 1388         bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
 1389         bus_space_write_stream_2(iot, ioh, MEM_PORT_REG, htole16(len));
 1390         
 1391         ETHER_FIRST_MULTI(step, ecp, enm);
 1392         while(enm) {
 1393                 bus_space_write_multi_stream_2(iot, ioh, MEM_PORT_REG,
 1394                     enm->enm_addrlo, 3);
 1395 
 1396                 ETHER_NEXT_MULTI(step, enm);
 1397         }
 1398         dum = bus_space_read_2(iot, ioh, MEM_PORT_REG); /* dummy read */
 1399         bus_space_write_2(iot, ioh, XMT_ADDR_REG, last);
 1400         bus_space_write_1(iot, ioh, 0, MC_SETUP_CMD);
 1401         
 1402 
 1403         sc->tx_start =  sc->rx_size;
 1404         sc->tx_end = sc->rx_size + I595_XMT_HDRLEN + len;
 1405 
 1406         for (timeout=0; timeout<100; timeout++) {
 1407                 DELAY(2);
 1408                 if ((bus_space_read_1(iot, ioh, STATUS_REG) & EXEC_INT) == 0)
 1409                         continue;
 1410 
 1411                 temp = bus_space_read_1(iot, ioh, 0);
 1412                 bus_space_write_1(iot, ioh, STATUS_REG, EXEC_INT);
 1413 #ifdef DIAGNOSTIC
 1414                 if (temp & 0x20) {
 1415                         printf("%s: mc setup failed, %d usec\n",
 1416                             sc->sc_dev.dv_xname, timeout * 2);
 1417                 } else if (((temp & 0x0f) == 0x03) &&
 1418                             (ifp->if_flags & IFF_DEBUG)) {
 1419                                 printf("%s: mc setup done, %d usec\n",
 1420                             sc->sc_dev.dv_xname, timeout * 2);
 1421                 }
 1422 #endif
 1423                 break;
 1424         }
 1425         sc->tx_start = sc->tx_end;
 1426         ifp->if_flags &= ~IFF_OACTIVE;
 1427         
 1428 }
 1429 
 1430 static void
 1431 iy_mc_reset(sc)
 1432         struct iy_softc *sc;
 1433 {
 1434         struct ether_multi *enm;
 1435         struct ether_multistep step;
 1436         struct ethercom *ecp;
 1437         struct ifnet *ifp;
 1438         bus_space_tag_t iot;
 1439         bus_space_handle_t ioh;
 1440         u_int16_t temp;
 1441 
 1442         ecp = &sc->sc_ethercom;
 1443         ifp = &ecp->ec_if;
 1444 
 1445         iot = sc->sc_iot;
 1446         ioh = sc->sc_ioh;
 1447 
 1448         if (ecp->ec_multicnt > 63) {
 1449                 ifp->if_flags |= IFF_ALLMULTI;
 1450 
 1451         } else if (ecp->ec_multicnt > 0) {
 1452                 /*
 1453                  * Step through the list of addresses.
 1454                  */
 1455                 ETHER_FIRST_MULTI(step, ecp, enm);
 1456                 while(enm) {
 1457                         if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
 1458                                 ifp->if_flags |= IFF_ALLMULTI;
 1459                                 goto setupmulti;
 1460                         }
 1461                         ETHER_NEXT_MULTI(step, enm);
 1462                 } 
 1463                 /* OK, we really need to do it now: */
 1464 #if 0
 1465                 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE))
 1466                     != IFF_RUNNING) {
 1467                         ifp->if_flags |= IFF_OACTIVE;
 1468                         sc->want_mc_setup = 1;
 1469                         return;
 1470                 }
 1471 #endif
 1472                 iy_mc_setup(sc);
 1473         } else {
 1474                 ifp->if_flags &= ~IFF_ALLMULTI;
 1475         }
 1476 
 1477 setupmulti:
 1478         bus_space_write_1(iot, ioh, 0, BANK_SEL(2));
 1479         if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) {
 1480                 temp = MATCH_ALL;
 1481         } else 
 1482                 temp = MATCH_BRDCST;
 1483 
 1484         bus_space_write_1(iot, ioh, RECV_MODES_REG, temp);
 1485         /* XXX VOODOO */
 1486         temp = bus_space_read_1(iot, ioh, MEDIA_SELECT);
 1487         bus_space_write_1(iot, ioh, MEDIA_SELECT, temp);
 1488         /* XXX END OF VOODOO */
 1489 
 1490         /* XXX TBD: setup hardware for all multicasts */
 1491         bus_space_write_1(iot, ioh, 0, BANK_SEL(0));
 1492         return;
 1493 }
 1494 
 1495 #ifdef IYDEBUGX
 1496 void
 1497 print_rbd(rbd)
 1498         volatile struct ie_recv_buf_desc *rbd;
 1499 {
 1500         printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
 1501             "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
 1502             rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
 1503             rbd->mbz);
 1504 }
 1505 #endif
 1506 
 1507 void
 1508 iyprobemem(sc)
 1509         struct iy_softc *sc;
 1510 {
 1511         bus_space_tag_t iot;
 1512         bus_space_handle_t ioh;
 1513         int testing;
 1514 
 1515         iot = sc->sc_iot;
 1516         ioh = sc->sc_ioh;
 1517 
 1518         bus_space_write_1(iot, ioh, COMMAND_REG, BANK_SEL(0));
 1519         delay(1);
 1520         bus_space_write_2(iot, ioh, HOST_ADDR_REG, 4096-2);
 1521         bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
 1522 
 1523         for (testing=65536; testing >= 4096; testing >>= 1) {
 1524                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
 1525                 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xdead);
 1526                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
 1527                 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xdead) {
 1528 #ifdef IYMEMDEBUG
 1529                         printf("%s: Didn't keep 0xdead at 0x%x\n",
 1530                             sc->sc_dev.dv_xname, testing-2);
 1531 #endif
 1532                         continue;
 1533                 }
 1534 
 1535                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
 1536                 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0xbeef);
 1537                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing-2);
 1538                 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) != 0xbeef) {
 1539 #ifdef IYMEMDEBUG
 1540                         printf("%s: Didn't keep 0xbeef at 0x%x\n",
 1541                             sc->sc_dev.dv_xname, testing-2);
 1542 #endif
 1543                         continue;
 1544                 }
 1545 
 1546                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
 1547                 bus_space_write_2(iot, ioh, MEM_PORT_REG, 0);
 1548                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, testing >> 1);
 1549                 bus_space_write_2(iot, ioh, MEM_PORT_REG, testing >> 1);
 1550                 bus_space_write_2(iot, ioh, HOST_ADDR_REG, 0);
 1551                 if (bus_space_read_2(iot, ioh, MEM_PORT_REG) == (testing >> 1)) {
 1552 #ifdef IYMEMDEBUG
 1553                         printf("%s: 0x%x alias of 0x0\n",
 1554                             sc->sc_dev.dv_xname, testing >> 1);
 1555 #endif
 1556                         continue;
 1557                 }
 1558 
 1559                 break;
 1560         }
 1561 
 1562         sc->sram = testing;
 1563 
 1564         switch(testing) {
 1565                 case 65536:
 1566                         /* 4 NFS packets + overhead RX, 2 NFS + overhead TX  */
 1567                         sc->rx_size = 44*1024;
 1568                         break;
 1569 
 1570                 case 32768:
 1571                         /* 2 NFS packets + overhead RX, 1 NFS + overhead TX  */
 1572                         sc->rx_size = 22*1024;
 1573                         break;
 1574 
 1575                 case 16384:
 1576                         /* 1 NFS packet + overhead RX, 4 big packets TX */
 1577                         sc->rx_size = 10*1024;
 1578                         break;
 1579                 default:        
 1580                         sc->rx_size = testing/2;
 1581                         break;
 1582         }
 1583         sc->tx_size = testing - sc->rx_size;
 1584 }
 1585 
 1586 static int
 1587 eepromreadall(iot, ioh, wordp, maxi)
 1588         bus_space_tag_t iot;
 1589         bus_space_handle_t ioh;
 1590         u_int16_t *wordp;
 1591         int maxi;
 1592 {
 1593         int i;
 1594         u_int16_t checksum, tmp;
 1595 
 1596         checksum = 0;
 1597 
 1598         for (i=0; i<EEPP_LENGTH; ++i) {
 1599                 tmp = eepromread(iot, ioh, i);
 1600                 checksum += tmp;
 1601                 if (i<maxi)
 1602                         wordp[i] = tmp;
 1603         }
 1604 
 1605         if (checksum != EEPP_CHKSUM) {
 1606 #ifdef IYDEBUG
 1607                 printf("wrong EEPROM checksum 0x%x should be 0x%x\n",
 1608                     checksum, EEPP_CHKSUM);
 1609 #endif
 1610                 return 1;
 1611         }
 1612         return 0;
 1613 }

Cache object: 160455e45d1dc253a67107f04a4cb3db


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.