LCOV - code coverage report
Current view: top level - dev/pcmcia - if_xe.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 606 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_xe.c,v 1.59 2017/01/22 10:17:39 dlg Exp $  */
       2             : 
       3             : /*
       4             :  * Copyright (c) 1999 Niklas Hallqvist, Brandon Creighton, Job de Haas
       5             :  * All rights reserved.
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 3. All advertising materials mentioning features or use of this software
      16             :  *    must display the following acknowledgement:
      17             :  *      This product includes software developed by Niklas Hallqvist,
      18             :  *      C Stone and Job de Haas.
      19             :  * 4. The name of the author may not be used to endorse or promote products
      20             :  *    derived from this software without specific prior written permission
      21             :  *
      22             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      23             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      24             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      25             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      26             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      27             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      28             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      29             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      30             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      31             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      32             :  */
      33             : 
      34             : /*
      35             :  * A driver for Xircom ethernet PC-cards.
      36             :  *
      37             :  * The driver has been inspired by the xirc2ps_cs.c driver found in Linux'
      38             :  * PCMCIA package written by Werner Koch <werner.koch@guug.de>:
      39             :  * [xirc2ps_cs.c wk 14.04.97] (1.31 1998/12/09 19:32:55)
      40             :  * I will note that no code was used verbatim from that driver as it is under
      41             :  * the much too strong GNU General Public License, it was only used as a
      42             :  * "specification" of sorts.
      43             :  * Other inspirations have been if_fxp.c, if_ep_pcmcia.c and elink3.c as
      44             :  * they were found in OpenBSD 2.4.
      45             :  */
      46             : 
      47             : #include "bpfilter.h"
      48             : 
      49             : #include <sys/param.h>
      50             : #include <sys/systm.h>
      51             : #include <sys/device.h>
      52             : #include <sys/ioctl.h>
      53             : #include <sys/mbuf.h>
      54             : #include <sys/malloc.h>
      55             : #include <sys/kernel.h>
      56             : #include <sys/socket.h>
      57             : #include <sys/syslog.h>
      58             : 
      59             : #include <net/if.h>
      60             : #include <net/if_media.h>
      61             : 
      62             : #include <netinet/in.h>
      63             : #include <netinet/if_ether.h>
      64             : 
      65             : #if NBPFILTER > 0
      66             : #include <net/bpf.h>
      67             : #endif
      68             : 
      69             : /*
      70             :  * Maximum number of bytes to read per interrupt.  Linux recommends
      71             :  * somewhere between 2000-22000.
      72             :  * XXX This is currently a hard maximum.
      73             :  */
      74             : #define MAX_BYTES_INTR 12000
      75             : 
      76             : #include <dev/mii/miivar.h>
      77             : 
      78             : #include <dev/pcmcia/pcmciareg.h>
      79             : #include <dev/pcmcia/pcmciavar.h>
      80             : #include <dev/pcmcia/pcmciadevs.h>
      81             : #include <dev/pcmcia/if_xereg.h>
      82             : 
      83             : #ifdef __GNUC__
      84             : #define INLINE  __inline
      85             : #else
      86             : #define INLINE
      87             : #endif  /* __GNUC__ */
      88             : 
      89             : #ifdef XEDEBUG
      90             : 
      91             : #define XED_CONFIG      0x1
      92             : #define XED_MII         0x2
      93             : #define XED_INTR        0x4
      94             : #define XED_FIFO        0x8
      95             : 
      96             : #ifndef XEDEBUG_DEF
      97             : #define XEDEBUG_DEF     (XED_CONFIG|XED_INTR)
      98             : #endif  /* XEDEBUG_DEF */
      99             : 
     100             : int xedebug = XEDEBUG_DEF;
     101             : 
     102             : #define DPRINTF(cat, x) if (xedebug & (cat)) printf x
     103             : 
     104             : #else   /* XEDEBUG */
     105             : #define DPRINTF(cat, x) (void)0
     106             : #endif  /* XEDEBUG */
     107             : 
     108             : int     xe_pcmcia_match(struct device *, void *, void *);
     109             : void    xe_pcmcia_attach(struct device *, struct device *, void *);
     110             : int     xe_pcmcia_detach(struct device *, int);
     111             : int     xe_pcmcia_activate(struct device *, int);
     112             : 
     113             : /*
     114             :  * In case this chipset ever turns up out of pcmcia attachments (very
     115             :  * unlikely) do the driver splitup.
     116             :  */
     117             : struct xe_softc {
     118             :         struct  device sc_dev;                  /* Generic device info */
     119             :         u_int32_t       sc_flags;               /* Misc. flags */
     120             :         void    *sc_ih;                         /* Interrupt handler */
     121             :         struct  arpcom sc_arpcom;               /* Ethernet common part */
     122             :         struct  ifmedia sc_media;               /* Media control */
     123             :         struct  mii_data sc_mii;                /* MII media information */
     124             :         int     sc_all_mcasts;                  /* Receive all multicasts */
     125             :         bus_space_tag_t sc_bst;                 /* Bus cookie */
     126             :         bus_space_handle_t      sc_bsh;         /* Bus I/O handle */
     127             :         bus_size_t      sc_offset;              /* Offset of registers */
     128             :         u_int8_t        sc_rev;                 /* Chip revision */
     129             : };
     130             : 
     131             : #define XEF_MOHAWK      0x001
     132             : #define XEF_DINGO       0x002
     133             : #define XEF_MODEM       0x004
     134             : #define XEF_UNSUPPORTED 0x008
     135             : #define XEF_CE          0x010
     136             : #define XEF_CE2         0x020
     137             : #define XEF_CE3         0x040
     138             : #define XEF_CE33        0x080
     139             : #define XEF_CE56        0x100
     140             : 
     141             : struct xe_pcmcia_softc {
     142             :         struct  xe_softc sc_xe;                 /* Generic device info */
     143             :         struct  pcmcia_mem_handle sc_pcmh;      /* PCMCIA memspace info */
     144             :         int     sc_mem_window;                  /* mem window */
     145             :         struct  pcmcia_io_handle sc_pcioh;      /* iospace info */
     146             :         int     sc_io_window;                   /* io window info */
     147             :         struct  pcmcia_function *sc_pf;         /* PCMCIA function */
     148             : };
     149             : 
     150             : /* Autoconfig definition of driver back-end */
     151             : struct cfdriver xe_cd = {
     152             :         NULL, "xe", DV_IFNET
     153             : };
     154             : 
     155             : struct cfattach xe_pcmcia_ca = {
     156             :         sizeof (struct xe_pcmcia_softc), xe_pcmcia_match, xe_pcmcia_attach,
     157             :         xe_pcmcia_detach, xe_pcmcia_activate
     158             : };
     159             : 
     160             : void    xe_cycle_power(struct xe_softc *);
     161             : void    xe_full_reset(struct xe_softc *);
     162             : void    xe_init(struct xe_softc *);
     163             : int     xe_intr(void *);
     164             : int     xe_ioctl(struct ifnet *, u_long, caddr_t);
     165             : int     xe_mdi_read(struct device *, int, int);
     166             : void    xe_mdi_write(struct device *, int, int, int);
     167             : int     xe_mediachange(struct ifnet *);
     168             : void    xe_mediastatus(struct ifnet *, struct ifmediareq *);
     169             : int     xe_pcmcia_funce_enaddr(struct device *, u_int8_t *);
     170             : u_int32_t xe_pcmcia_interpret_manfid(struct device *);
     171             : int     xe_pcmcia_lan_nid_ciscallback(struct pcmcia_tuple *, void *);
     172             : int     xe_pcmcia_manfid_ciscallback(struct pcmcia_tuple *, void *);
     173             : u_int16_t xe_get(struct xe_softc *);
     174             : void    xe_reset(struct xe_softc *);
     175             : void    xe_set_address(struct xe_softc *);
     176             : void    xe_start(struct ifnet *);
     177             : void    xe_statchg(struct device *);
     178             : void    xe_stop(struct xe_softc *);
     179             : void    xe_watchdog(struct ifnet *);
     180             : #ifdef XEDEBUG
     181             : void    xe_reg_dump(struct xe_softc *);
     182             : #endif  /* XEDEBUG */
     183             : 
     184             : int
     185           0 : xe_pcmcia_match(parent, match, aux)
     186             :         struct device *parent;
     187             :         void *match, *aux;
     188             : {
     189           0 :         struct pcmcia_attach_args *pa = aux;
     190             :         
     191           0 :         if (pa->pf->function != PCMCIA_FUNCTION_NETWORK)
     192           0 :                 return (0);
     193             : 
     194           0 :         switch (pa->manufacturer) {
     195             :         case PCMCIA_VENDOR_COMPAQ:
     196             :         case PCMCIA_VENDOR_COMPAQ2:
     197           0 :                 return (0);
     198             : 
     199             :         case PCMCIA_VENDOR_INTEL:
     200             :         case PCMCIA_VENDOR_XIRCOM:
     201             :                 /* XXX Per-productid checking here. */
     202           0 :                 return (1);
     203             : 
     204             :         default:
     205           0 :                 return (0);
     206             :         }
     207           0 : }
     208             : 
     209             : void
     210           0 : xe_pcmcia_attach(parent, self, aux)
     211             :         struct device *parent, *self;
     212             :         void *aux;
     213             : {
     214           0 :         struct xe_pcmcia_softc *psc = (struct xe_pcmcia_softc *)self;
     215           0 :         struct xe_softc *sc = &psc->sc_xe;
     216           0 :         struct pcmcia_attach_args *pa = aux;
     217           0 :         struct pcmcia_function *pf = pa->pf;
     218             :         struct pcmcia_config_entry *cfe = NULL;
     219             :         struct ifnet *ifp;
     220           0 :         u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
     221             :         int state = 0;
     222           0 :         struct pcmcia_mem_handle pcmh;
     223           0 :         int ccr_window;
     224           0 :         bus_size_t ccr_offset;
     225             :         const char *intrstr;
     226             : 
     227           0 :         psc->sc_pf = pf;
     228             : 
     229             : #if 0
     230             :         /* Figure out what card we are. */
     231             :         sc->sc_flags = xe_pcmcia_interpret_manfid(parent);
     232             : #endif
     233           0 :         if (sc->sc_flags & XEF_UNSUPPORTED) {
     234           0 :                 printf(": card unsupported\n");
     235           0 :                 goto bad;
     236             :         }
     237             : 
     238             :         /* Tell the pcmcia framework where the CCR is. */
     239           0 :         pf->ccr_base = 0x800;
     240           0 :         pf->ccr_mask = 0x67;
     241             : 
     242             :         /* Fake a cfe. */
     243           0 :         SIMPLEQ_FIRST(&pa->pf->cfe_head) = cfe = (struct pcmcia_config_entry *)
     244           0 :             malloc(sizeof *cfe, M_DEVBUF, M_NOWAIT | M_ZERO);
     245           0 :         if (!cfe) {
     246           0 :                 printf(": function enable failed\n");
     247           0 :                 return;
     248             :         }
     249             : 
     250             :         /*
     251             :          * XXX Use preprocessor symbols instead.
     252             :          * Enable ethernet & its interrupts, wiring them to -INT
     253             :          * No I/O base.
     254             :          */
     255           0 :         cfe->number = 0x5;
     256           0 :         cfe->flags = 0;              /* XXX Check! */
     257           0 :         cfe->iftype = PCMCIA_IFTYPE_IO;
     258           0 :         cfe->num_iospace = 0;
     259           0 :         cfe->num_memspace = 0;
     260           0 :         cfe->irqmask = 0x8eb0;
     261             : 
     262             :         /* Enable the card. */
     263           0 :         pcmcia_function_init(pa->pf, cfe);
     264           0 :         if (pcmcia_function_enable(pa->pf)) {
     265           0 :                 printf(": function enable failed\n");
     266           0 :                 goto bad;
     267             :         }
     268             : 
     269             :         state++;
     270             : 
     271           0 :         if (pcmcia_io_alloc(pa->pf, 0, 16, 16, &psc->sc_pcioh)) {
     272           0 :                 printf(": io allocation failed\n");
     273           0 :                 goto bad;
     274             :         }
     275             : 
     276             :         state++;
     277             : 
     278           0 :         if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_IO16, 0, 16, &psc->sc_pcioh,
     279           0 :                 &psc->sc_io_window)) {
     280           0 :                 printf(": can't map io space\n");
     281           0 :                 goto bad;
     282             :         }
     283           0 :         sc->sc_bst = psc->sc_pcioh.iot;
     284           0 :         sc->sc_bsh = psc->sc_pcioh.ioh;
     285           0 :         sc->sc_offset = 0;
     286             : 
     287           0 :         printf(" port 0x%lx/%d", psc->sc_pcioh.addr, 16);
     288             : 
     289             : #if 0
     290             :         if (pcmcia_mem_alloc(pf, 16, &psc->sc_pcmh)) {
     291             :                 printf(": pcmcia memory allocation failed\n");
     292             :                 goto bad;
     293             :         }
     294             :         state++;
     295             : 
     296             :         if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0x300, 16, &psc->sc_pcmh,
     297             :             &sc->sc_offset, &psc->sc_mem_window)) {
     298             :                 printf(": pcmcia memory mapping failed\n");
     299             :                 goto bad;
     300             :         }
     301             : 
     302             :         sc->sc_bst = psc->sc_pcmh.memt;
     303             :         sc->sc_bsh = psc->sc_pcmh.memh;
     304             : #endif
     305             : 
     306             :         /* Figure out what card we are. */
     307           0 :         sc->sc_flags = xe_pcmcia_interpret_manfid(parent);
     308             : 
     309             :         /*
     310             :          * Configuration as advised by DINGO documentation.
     311             :          * We only know about this flag after the manfid interpretation.
     312             :          * Dingo has some extra configuration registers in the CCR space.
     313             :          */
     314           0 :         if (sc->sc_flags & XEF_DINGO) {
     315           0 :                 if (pcmcia_mem_alloc(pf, PCMCIA_CCR_SIZE_DINGO, &pcmh)) {
     316             :                         DPRINTF(XED_CONFIG, ("bad mem alloc\n"));
     317             :                         goto bad;
     318             :                 }
     319             : 
     320           0 :                 if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, pf->ccr_base,
     321             :                     PCMCIA_CCR_SIZE_DINGO, &pcmh, &ccr_offset,
     322             :                     &ccr_window)) {
     323             :                         DPRINTF(XED_CONFIG, ("bad mem map\n"));
     324           0 :                         pcmcia_mem_free(pf, &pcmh);
     325           0 :                         goto bad;
     326             :                 }
     327             : 
     328           0 :                 bus_space_write_1(pcmh.memt, pcmh.memh,
     329             :                     ccr_offset + PCMCIA_CCR_DCOR0, PCMCIA_CCR_DCOR0_SFINT);
     330           0 :                 bus_space_write_1(pcmh.memt, pcmh.memh,
     331             :                     ccr_offset + PCMCIA_CCR_DCOR1,
     332             :                     PCMCIA_CCR_DCOR1_FORCE_LEVIREQ | PCMCIA_CCR_DCOR1_D6);
     333           0 :                 bus_space_write_1(pcmh.memt, pcmh.memh,
     334             :                     ccr_offset + PCMCIA_CCR_DCOR2, 0);
     335           0 :                 bus_space_write_1(pcmh.memt, pcmh.memh,
     336             :                     ccr_offset + PCMCIA_CCR_DCOR3, 0);
     337           0 :                 bus_space_write_1(pcmh.memt, pcmh.memh,
     338             :                     ccr_offset + PCMCIA_CCR_DCOR4, 0);
     339             : 
     340             :                 /* We don't need them anymore and can free them (I think). */
     341           0 :                 pcmcia_mem_unmap(pf, ccr_window);
     342           0 :                 pcmcia_mem_free(pf, &pcmh);
     343           0 :         }
     344             : 
     345             :         /*
     346             :          * Try to get the ethernet address from FUNCE/LAN_NID tuple.
     347             :          */
     348           0 :         if (xe_pcmcia_funce_enaddr(parent, myla))
     349           0 :                 enaddr = myla;
     350           0 :         ifp = &sc->sc_arpcom.ac_if;
     351           0 :         if (enaddr)
     352           0 :                 bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
     353             :         else {
     354           0 :                 printf(", unable to get ethernet address\n");
     355           0 :                 goto bad;
     356             :         }
     357             : 
     358           0 :         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
     359           0 :         ifp->if_softc = sc;
     360           0 :         ifp->if_flags =
     361             :             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     362           0 :         ifp->if_ioctl = xe_ioctl;
     363           0 :         ifp->if_start = xe_start;
     364           0 :         ifp->if_watchdog = xe_watchdog;
     365             : 
     366             :         /* Establish the interrupt. */
     367           0 :         sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, xe_intr, sc,
     368             :             sc->sc_dev.dv_xname);
     369           0 :         if (sc->sc_ih == NULL) {
     370           0 :                 printf(", couldn't establish interrupt\n");
     371           0 :                 goto bad;
     372             :         }
     373           0 :         intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
     374           0 :         printf("%s%s: address %s\n", *intrstr ? ", " : "", intrstr,
     375           0 :             ether_sprintf(sc->sc_arpcom.ac_enaddr));
     376             : 
     377             :         /* Reset and initialize the card. */
     378           0 :         xe_full_reset(sc);
     379             : 
     380             :         /* Initialize our media structures and probe the phy. */
     381           0 :         sc->sc_mii.mii_ifp = ifp;
     382           0 :         sc->sc_mii.mii_readreg = xe_mdi_read;
     383           0 :         sc->sc_mii.mii_writereg = xe_mdi_write;
     384           0 :         sc->sc_mii.mii_statchg = xe_statchg;
     385           0 :         ifmedia_init(&sc->sc_mii.mii_media, IFM_IMASK, xe_mediachange,
     386             :             xe_mediastatus);
     387             :         DPRINTF(XED_MII | XED_CONFIG,
     388             :             ("bmsr %x\n", xe_mdi_read(&sc->sc_dev, 0, 1)));
     389           0 :         mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
     390             :             0);
     391           0 :         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL)
     392           0 :                 ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO, 0,
     393             :                     NULL);
     394           0 :         ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
     395             : 
     396             :         /*
     397             :          * Attach the interface.
     398             :          */
     399           0 :         if_attach(ifp);
     400           0 :         ether_ifattach(ifp);
     401             : 
     402             :         /*
     403             :          * Reset and initialize the card again for DINGO (as found in Linux
     404             :          * driver).  Without this Dingo will get a watchdog timeout the first
     405             :          * time.  The ugly media tickling seems to be necessary for getting
     406             :          * autonegotiation to work too.
     407             :          */
     408           0 :         if (sc->sc_flags & XEF_DINGO) {
     409           0 :                 xe_full_reset(sc);
     410           0 :                 xe_init(sc);
     411           0 :                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
     412           0 :                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
     413           0 :                 xe_stop(sc);
     414           0 :         }
     415           0 :         return;
     416             : 
     417             : bad:
     418           0 :         if (state > 2)
     419           0 :                 pcmcia_io_unmap(pf, psc->sc_io_window);
     420           0 :         if (state > 1)
     421           0 :                 pcmcia_io_free(pf, &psc->sc_pcioh);
     422           0 :         if (state > 0)
     423           0 :                 pcmcia_function_disable(pa->pf);
     424           0 :         free(cfe, M_DEVBUF, 0);
     425           0 : }
     426             : 
     427             : int
     428           0 : xe_pcmcia_detach(dev, flags)
     429             :         struct device *dev;
     430             :         int flags;
     431             : {
     432           0 :         struct xe_pcmcia_softc *psc = (struct xe_pcmcia_softc *)dev;
     433           0 :         struct xe_softc *sc = &psc->sc_xe;
     434           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     435             :         int rv = 0;
     436             : 
     437           0 :         mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
     438           0 :         ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
     439             : 
     440           0 :         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
     441           0 :         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
     442             : 
     443           0 :         ether_ifdetach(ifp);
     444           0 :         if_detach(ifp);
     445             : 
     446           0 :         return (rv);
     447             : }
     448             : 
     449             : int
     450           0 : xe_pcmcia_activate(dev, act)
     451             :         struct device *dev;
     452             :         int act;
     453             : {
     454           0 :         struct xe_pcmcia_softc *sc = (struct xe_pcmcia_softc *)dev;
     455           0 :         struct ifnet *ifp = &sc->sc_xe.sc_arpcom.ac_if;
     456             : 
     457           0 :         switch (act) {
     458             :         case DVACT_SUSPEND:
     459           0 :                 if (ifp->if_flags & IFF_RUNNING)
     460           0 :                         xe_stop(&sc->sc_xe);
     461           0 :                 ifp->if_flags &= ~IFF_RUNNING;
     462           0 :                 if (sc->sc_xe.sc_ih)
     463           0 :                         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
     464           0 :                 sc->sc_xe.sc_ih = NULL;
     465           0 :                 pcmcia_function_disable(sc->sc_pf);
     466           0 :                 break;
     467             :         case DVACT_RESUME:
     468           0 :                 pcmcia_function_enable(sc->sc_pf);
     469           0 :                 sc->sc_xe.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
     470           0 :                     xe_intr, sc, sc->sc_xe.sc_dev.dv_xname);
     471             :                 /* XXX this is a ridiculous */
     472           0 :                 xe_reset(&sc->sc_xe);
     473           0 :                 if ((ifp->if_flags & IFF_UP) == 0)
     474           0 :                         xe_stop(&sc->sc_xe);
     475             :                 break;
     476             :         case DVACT_DEACTIVATE:
     477           0 :                 ifp->if_timer = 0;
     478           0 :                 ifp->if_flags &= ~IFF_RUNNING;
     479           0 :                 if (sc->sc_xe.sc_ih)
     480           0 :                         pcmcia_intr_disestablish(sc->sc_pf, sc->sc_xe.sc_ih);
     481           0 :                 sc->sc_xe.sc_ih = NULL;
     482           0 :                 pcmcia_function_disable(sc->sc_pf);
     483           0 :                 break;
     484             :         }
     485           0 :         return (0);
     486             : }
     487             : 
     488             : /*
     489             :  * XXX These two functions might be OK to factor out into pcmcia.c since
     490             :  * if_sm_pcmcia.c uses similar ones.
     491             :  */
     492             : int
     493           0 : xe_pcmcia_funce_enaddr(parent, myla)
     494             :         struct device *parent;
     495             :         u_int8_t *myla;
     496             : {
     497             :         /* XXX The Linux driver has more ways to do this in case of failure. */
     498           0 :         return (pcmcia_scan_cis(parent, xe_pcmcia_lan_nid_ciscallback, myla));
     499             : }
     500             : 
     501             : int
     502           0 : xe_pcmcia_lan_nid_ciscallback(tuple, arg)
     503             :         struct pcmcia_tuple *tuple;
     504             :         void *arg;
     505             : {
     506             :         u_int8_t *myla = arg;
     507             :         int i;
     508             : 
     509           0 :         if (tuple->code == PCMCIA_CISTPL_FUNCE) {
     510           0 :                 if (tuple->length < 2)
     511           0 :                         return (0);
     512             : 
     513           0 :                 switch (pcmcia_tuple_read_1(tuple, 0)) {
     514             :                 case PCMCIA_TPLFE_TYPE_LAN_NID:
     515           0 :                         if (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
     516           0 :                                 return (0);
     517             :                         break;
     518             : 
     519             :                 case 0x02:
     520             :                         /*
     521             :                          * Not sure about this, I don't have a CE2
     522             :                          * that puts the ethernet addr here.
     523             :                          */
     524           0 :                         if (pcmcia_tuple_read_1(tuple, 1) != 13)
     525           0 :                                 return (0);
     526             :                         break;
     527             : 
     528             :                 default:
     529           0 :                         return (0);
     530             :                 }
     531             : 
     532           0 :                 for (i = 0; i < ETHER_ADDR_LEN; i++)
     533           0 :                         myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
     534           0 :                 return (1);
     535             :         }
     536             : 
     537             :         /* Yet another spot where this might be. */
     538           0 :         if (tuple->code == 0x89) {
     539           0 :                 pcmcia_tuple_read_1(tuple, 1);
     540           0 :                 for (i = 0; i < ETHER_ADDR_LEN; i++)
     541           0 :                         myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
     542           0 :                 return (1);
     543             :         }
     544           0 :         return (0);
     545           0 : }
     546             : 
     547             : u_int32_t
     548           0 : xe_pcmcia_interpret_manfid (parent)
     549             :         struct device *parent;
     550             : {
     551           0 :         u_int32_t flags = 0;
     552           0 :         struct pcmcia_softc *psc = (struct pcmcia_softc *)parent;
     553             :         char *tptr;
     554             : 
     555           0 :         if (!pcmcia_scan_cis(parent, xe_pcmcia_manfid_ciscallback, &flags))
     556           0 :                 return (XEF_UNSUPPORTED);
     557             : 
     558           0 :         if (flags & XEF_CE) {
     559           0 :                 tptr = memchr(psc->card.cis1_info[2], 'C',
     560           0 :                     strlen(psc->card.cis1_info[2]));
     561             :                 /* XXX not sure if other CE2s hide "CE2" in different places */
     562           0 :                 if (tptr && *(tptr + 1) == 'E' && *(tptr + 2) == '2') {
     563           0 :                         flags ^= (XEF_CE | XEF_UNSUPPORTED);
     564           0 :                         flags |= XEF_CE2;
     565           0 :                 }
     566             :         }
     567           0 :         return (flags);
     568           0 : }
     569             : 
     570             : int
     571           0 : xe_pcmcia_manfid_ciscallback(tuple, arg)
     572             :         struct pcmcia_tuple *tuple;
     573             :         void *arg;
     574             : {
     575           0 :         u_int32_t *flagsp = arg;
     576             :         u_int8_t media, product;
     577             : 
     578           0 :         if (tuple->code == PCMCIA_CISTPL_MANFID) {
     579           0 :                 if (tuple->length < 2)
     580           0 :                         return (0);
     581             : 
     582           0 :                 media = pcmcia_tuple_read_1(tuple, 3);
     583           0 :                 product = pcmcia_tuple_read_1(tuple, 4);
     584             : 
     585           0 :                 if (!(product & XEPROD_CREDITCARD) ||
     586           0 :                     !(media & XEMEDIA_ETHER)) {
     587           0 :                         *flagsp |= XEF_UNSUPPORTED;
     588           0 :                         return (1);
     589             :                 }
     590             : 
     591           0 :                 if (media & XEMEDIA_MODEM)
     592           0 :                         *flagsp |= XEF_MODEM;
     593             : 
     594           0 :                 switch (product & XEPROD_IDMASK) {
     595             :                 case 1:
     596             :                         /* XXX Can be CE2 too (we double-check later). */
     597           0 :                         *flagsp |= XEF_CE | XEF_UNSUPPORTED;
     598           0 :                         break;
     599             :                 case 2:
     600           0 :                         *flagsp |= XEF_CE2;
     601           0 :                         break;
     602             :                 case 3:
     603           0 :                         if (!(*flagsp & XEF_MODEM))
     604           0 :                                 *flagsp |= XEF_MOHAWK;
     605           0 :                         *flagsp |= XEF_CE3;
     606           0 :                         break;
     607             :                 case 4:
     608           0 :                         *flagsp |= XEF_CE33;
     609           0 :                         break;
     610             :                 case 5:
     611           0 :                         *flagsp |= XEF_CE56 | XEF_MOHAWK;
     612           0 :                         break;
     613             :                 case 6:
     614             :                 case 7:
     615           0 :                         *flagsp |= XEF_CE56 | XEF_MOHAWK | XEF_DINGO;
     616           0 :                         break;
     617             :                 default:
     618           0 :                         *flagsp |= XEF_UNSUPPORTED;
     619           0 :                         break;
     620             :                 }
     621             : 
     622           0 :                 return (1);
     623             :         }
     624           0 :         return (0);
     625           0 : }
     626             : 
     627             : int
     628           0 : xe_intr(arg)
     629             :         void *arg;
     630             : {
     631           0 :         struct xe_softc *sc = arg;
     632           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     633             :         u_int8_t esr, rsr, isr, rx_status, savedpage;
     634             :         u_int16_t tx_status, recvcount = 0, tempint;
     635             : 
     636           0 :         ifp->if_timer = 0;   /* turn watchdog timer off */
     637             : 
     638           0 :         if (sc->sc_flags & XEF_MOHAWK) {
     639             :                 /* Disable interrupt (Linux does it). */
     640           0 :                 bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
     641             :                     0);
     642           0 :         }
     643             : 
     644             :         savedpage =
     645           0 :             bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + PR);
     646             : 
     647           0 :         PAGE(sc, 0);
     648           0 :         esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ESR);
     649           0 :         isr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + ISR0);
     650           0 :         rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
     651             :                                 
     652             :         /* Check to see if card has been ejected. */
     653           0 :         if (isr == 0xff) {
     654           0 :                 printf("%s: interrupt for dead card\n", sc->sc_dev.dv_xname);
     655           0 :                 goto end;
     656             :         }
     657             : 
     658           0 :         PAGE(sc, 40);
     659             :         rx_status =
     660           0 :             bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RXST0);
     661             :         tx_status =
     662           0 :             bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + TXST0);
     663             : 
     664             :         /*
     665             :          * XXX Linux writes to RXST0 and TXST* here.  My CE2 works just fine
     666             :          * without it, and I can't see an obvious reason for it.
     667             :          */
     668             : 
     669           0 :         PAGE(sc, 0);
     670           0 :         while (esr & FULL_PKT_RCV) {
     671           0 :                 if (!(rsr & RSR_RX_OK))
     672             :                         break;
     673             : 
     674             :                 /* Compare bytes read this interrupt to hard maximum. */
     675           0 :                 if (recvcount > MAX_BYTES_INTR) {
     676             :                         DPRINTF(XED_INTR,
     677             :                             ("%s: too many bytes this interrupt\n",
     678             :                             sc->sc_dev.dv_xname));
     679           0 :                         ifp->if_iqdrops++;
     680             :                         /* Drop packet. */
     681           0 :                         bus_space_write_2(sc->sc_bst, sc->sc_bsh,
     682             :                             sc->sc_offset + DO0, DO_SKIP_RX_PKT);
     683           0 :                 }
     684           0 :                 tempint = xe_get(sc);
     685           0 :                 recvcount += tempint;
     686           0 :                 esr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
     687             :                     sc->sc_offset + ESR);
     688           0 :                 rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
     689             :                     sc->sc_offset + RSR);
     690             :         }
     691             :         
     692             :         /* Packet too long? */
     693           0 :         if (rsr & RSR_TOO_LONG) {
     694           0 :                 ifp->if_ierrors++;
     695             :                 DPRINTF(XED_INTR,
     696             :                     ("%s: packet too long\n", sc->sc_dev.dv_xname));
     697           0 :         }
     698             : 
     699             :         /* CRC error? */
     700           0 :         if (rsr & RSR_CRCERR) {
     701           0 :                 ifp->if_ierrors++;
     702             :                 DPRINTF(XED_INTR,
     703             :                     ("%s: CRC error detected\n", sc->sc_dev.dv_xname));
     704           0 :         }
     705             : 
     706             :         /* Alignment error? */
     707           0 :         if (rsr & RSR_ALIGNERR) {
     708           0 :                 ifp->if_ierrors++;
     709             :                 DPRINTF(XED_INTR,
     710             :                     ("%s: alignment error detected\n", sc->sc_dev.dv_xname));
     711           0 :         }
     712             : 
     713             :         /* Check for rx overrun. */
     714           0 :         if (rx_status & RX_OVERRUN) {
     715           0 :                 bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
     716             :                     CLR_RX_OVERRUN);
     717             :                 DPRINTF(XED_INTR, ("overrun cleared\n"));
     718           0 :         }
     719             :                         
     720             :         /* Try to start more packets transmitting. */
     721           0 :         if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
     722           0 :                 xe_start(ifp);
     723             : 
     724             :         /* Detected excessive collisions? */
     725           0 :         if (tx_status & EXCESSIVE_COLL) {
     726             :                 DPRINTF(XED_INTR,
     727             :                     ("%s: excessive collisions\n", sc->sc_dev.dv_xname));
     728           0 :                 bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
     729             :                     RESTART_TX);
     730           0 :                 ifp->if_oerrors++;
     731           0 :         }
     732             :         
     733           0 :         if (tx_status & TX_ABORT)
     734           0 :                 ifp->if_oerrors++;
     735             : 
     736             : end:
     737             :         /* Reenable interrupts. */
     738           0 :         PAGE(sc, savedpage);
     739           0 :         bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR,
     740             :             ENABLE_INT);
     741             : 
     742           0 :         return (1);
     743             : }
     744             : 
     745             : u_int16_t
     746           0 : xe_get(sc)
     747             :         struct xe_softc *sc;
     748             : {
     749             :         u_int8_t rsr;
     750           0 :         struct mbuf *top, **mp, *m;
     751           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     752           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     753             :         u_int16_t pktlen, len, recvcount = 0;
     754             :         u_int8_t *data;
     755             :         
     756           0 :         PAGE(sc, 0);
     757           0 :         rsr = bus_space_read_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RSR);
     758             : 
     759             :         pktlen =
     760           0 :             bus_space_read_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + RBC0) &
     761             :             RBC_COUNT_MASK;
     762           0 :         if (pktlen == 0) {
     763             :                 /*
     764             :                  * XXX At least one CE2 sets RBC0 == 0 occasionally, and only
     765             :                  * when MPE is set.  It is not known why.
     766             :                  */
     767           0 :                 return (0);
     768             :         }
     769             :         recvcount += pktlen;
     770             : 
     771           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     772           0 :         if (m == NULL)
     773           0 :                 return (recvcount);
     774           0 :         m->m_pkthdr.len = pktlen;
     775             :         len = MHLEN;
     776           0 :         top = 0;
     777             :         mp = &top;
     778             :         
     779           0 :         while (pktlen > 0) {
     780           0 :                 if (top) {
     781           0 :                         MGET(m, M_DONTWAIT, MT_DATA);
     782           0 :                         if (m == NULL) {
     783           0 :                                 m_freem(top);
     784           0 :                                 return (recvcount);
     785             :                         }
     786             :                         len = MLEN;
     787           0 :                 }
     788           0 :                 if (pktlen >= MINCLSIZE) {
     789           0 :                         MCLGET(m, M_DONTWAIT);
     790           0 :                         if (!(m->m_flags & M_EXT)) {
     791           0 :                                 m_freem(m);
     792           0 :                                 m_freem(top);
     793           0 :                                 return (recvcount);
     794             :                         }
     795             :                         len = MCLBYTES;
     796           0 :                 }
     797           0 :                 if (!top) {
     798           0 :                         caddr_t newdata = (caddr_t)ALIGN(m->m_data +
     799           0 :                             sizeof (struct ether_header)) -
     800             :                             sizeof (struct ether_header);
     801           0 :                         len -= newdata - m->m_data;
     802           0 :                         m->m_data = newdata;
     803           0 :                 }
     804           0 :                 len = min(pktlen, len);
     805             : 
     806           0 :                 data = mtod(m, u_int8_t *);
     807           0 :                 if (len > 1) {
     808           0 :                         len &= ~1;
     809           0 :                         bus_space_read_raw_multi_2(sc->sc_bst, sc->sc_bsh,
     810             :                             sc->sc_offset + EDP, data, len);
     811           0 :                 } else
     812           0 :                         *data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
     813             :                             sc->sc_offset + EDP);
     814           0 :                 m->m_len = len;
     815           0 :                 pktlen -= len;
     816           0 :                 *mp = m;
     817           0 :                 mp = &m->m_next;
     818             :         }
     819             : 
     820             :         /* Skip Rx packet. */
     821           0 :         bus_space_write_2(sc->sc_bst, sc->sc_bsh, sc->sc_offset + DO0,
     822             :             DO_SKIP_RX_PKT);
     823             : 
     824           0 :         ml_enqueue(&ml, top);
     825           0 :         if_input(ifp, &ml);
     826             : 
     827           0 :         return (recvcount);
     828           0 : }
     829             : 
     830             : 
     831             : /*
     832             :  * Serial management for the MII.
     833             :  * The DELAY's below stem from the fact that the maximum frequency
     834             :  * acceptable on the MDC pin is 2.5 MHz and fast processors can easily
     835             :  * go much faster than that.
     836             :  */
     837             : 
     838             : /* Let the MII serial management be idle for one period. */
     839             : static INLINE void xe_mdi_idle(struct xe_softc *);
     840             : static INLINE void
     841           0 : xe_mdi_idle(sc)
     842             :         struct xe_softc *sc;
     843             : {
     844           0 :         bus_space_tag_t bst = sc->sc_bst;
     845           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     846           0 :         bus_size_t offset = sc->sc_offset;
     847             : 
     848             :         /* Drive MDC low... */
     849           0 :         bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
     850           0 :         DELAY(1);
     851             : 
     852             :         /* and high again. */
     853           0 :         bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
     854           0 :         DELAY(1);
     855           0 : }
     856             : 
     857             : /* Pulse out one bit of data. */
     858             : static INLINE void xe_mdi_pulse(struct xe_softc *, int);
     859             : static INLINE void
     860           0 : xe_mdi_pulse(sc, data)
     861             :         struct xe_softc *sc;
     862             :         int data;
     863             : {
     864           0 :         bus_space_tag_t bst = sc->sc_bst;
     865           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     866           0 :         bus_size_t offset = sc->sc_offset;
     867           0 :         u_int8_t bit = data ? MDIO_HIGH : MDIO_LOW;
     868             : 
     869             :         /* First latch the data bit MDIO with clock bit MDC low...*/
     870           0 :         bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_LOW);
     871           0 :         DELAY(1);
     872             : 
     873             :         /* then raise the clock again, preserving the data bit. */
     874           0 :         bus_space_write_1(bst, bsh, offset + GP2, bit | MDC_HIGH);
     875           0 :         DELAY(1);
     876           0 : }
     877             : 
     878             : /* Probe one bit of data. */
     879             : static INLINE int xe_mdi_probe(struct xe_softc *sc);
     880             : static INLINE int
     881           0 : xe_mdi_probe(sc)
     882             :         struct xe_softc *sc;
     883             : {
     884           0 :         bus_space_tag_t bst = sc->sc_bst;
     885           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     886           0 :         bus_size_t offset = sc->sc_offset;
     887             :         u_int8_t x;
     888             : 
     889             :         /* Pull clock bit MDCK low... */
     890           0 :         bus_space_write_1(bst, bsh, offset + GP2, MDC_LOW);
     891           0 :         DELAY(1);
     892             : 
     893             :         /* Read data and drive clock high again. */
     894           0 :         x = bus_space_read_1(bst, bsh, offset + GP2) & MDIO;
     895           0 :         bus_space_write_1(bst, bsh, offset + GP2, MDC_HIGH);
     896           0 :         DELAY(1);
     897             : 
     898           0 :         return (x);
     899             : }
     900             : 
     901             : /* Pulse out a sequence of data bits. */
     902             : static INLINE void xe_mdi_pulse_bits(struct xe_softc *, u_int32_t, int);
     903             : static INLINE void
     904           0 : xe_mdi_pulse_bits(sc, data, len)
     905             :         struct xe_softc *sc;
     906             :         u_int32_t data;
     907             :         int len;
     908             : {
     909             :         u_int32_t mask;
     910             : 
     911           0 :         for (mask = 1 << (len - 1); mask; mask >>= 1)
     912           0 :                 xe_mdi_pulse(sc, data & mask);
     913           0 : }
     914             : 
     915             : /* Read a PHY register. */
     916             : int
     917           0 : xe_mdi_read(self, phy, reg)
     918             :         struct device *self;
     919             :         int phy;
     920             :         int reg;
     921             : {
     922           0 :         struct xe_softc *sc = (struct xe_softc *)self;
     923             :         int i;
     924             :         u_int32_t mask;
     925             :         u_int32_t data = 0;
     926             : 
     927           0 :         PAGE(sc, 2);
     928           0 :         for (i = 0; i < 32; i++)     /* Synchronize. */
     929           0 :                 xe_mdi_pulse(sc, 1);
     930           0 :         xe_mdi_pulse_bits(sc, 0x06, 4); /* Start + Read opcode */
     931           0 :         xe_mdi_pulse_bits(sc, phy, 5);  /* PHY address */
     932           0 :         xe_mdi_pulse_bits(sc, reg, 5);  /* PHY register */
     933           0 :         xe_mdi_idle(sc);                /* Turn around. */
     934           0 :         xe_mdi_probe(sc);               /* Drop initial zero bit. */
     935             : 
     936           0 :         for (mask = 1 << 15; mask; mask >>= 1)
     937           0 :                 if (xe_mdi_probe(sc))
     938           0 :                         data |= mask;
     939           0 :         xe_mdi_idle(sc);
     940             : 
     941             :         DPRINTF(XED_MII,
     942             :             ("xe_mdi_read: phy %d reg %d -> %x\n", phy, reg, data));
     943           0 :         return (data);
     944             : }
     945             : 
     946             : /* Write a PHY register. */
     947             : void
     948           0 : xe_mdi_write(self, phy, reg, value)
     949             :         struct device *self;
     950             :         int phy;
     951             :         int reg;
     952             :         int value;
     953             : {
     954           0 :         struct xe_softc *sc = (struct xe_softc *)self;
     955             :         int i;
     956             : 
     957           0 :         PAGE(sc, 2);
     958           0 :         for (i = 0; i < 32; i++)     /* Synchronize. */
     959           0 :                 xe_mdi_pulse(sc, 1);
     960           0 :         xe_mdi_pulse_bits(sc, 0x05, 4); /* Start + Write opcode */
     961           0 :         xe_mdi_pulse_bits(sc, phy, 5);  /* PHY address */
     962           0 :         xe_mdi_pulse_bits(sc, reg, 5);  /* PHY register */
     963           0 :         xe_mdi_pulse_bits(sc, 0x02, 2); /* Turn around. */
     964           0 :         xe_mdi_pulse_bits(sc, value, 16);       /* Write the data */
     965           0 :         xe_mdi_idle(sc);                /* Idle away. */
     966             : 
     967             :         DPRINTF(XED_MII,
     968             :             ("xe_mdi_write: phy %d reg %d val %x\n", phy, reg, value));
     969           0 : }
     970             : 
     971             : void
     972           0 : xe_statchg(self)
     973             :         struct device *self;
     974             : {
     975           0 : }
     976             : 
     977             : /*
     978             :  * Change media according to request.
     979             :  */
     980             : int
     981           0 : xe_mediachange(ifp)
     982             :         struct ifnet *ifp;
     983             : {
     984           0 :         if (ifp->if_flags & IFF_UP)
     985           0 :                 xe_init(ifp->if_softc);
     986           0 :         return (0);
     987             : }
     988             : 
     989             : /*
     990             :  * Notify the world which media we're using.
     991             :  */
     992             : void
     993           0 : xe_mediastatus(ifp, ifmr)
     994             :         struct ifnet *ifp;
     995             :         struct ifmediareq *ifmr;
     996             : {
     997           0 :         struct xe_softc *sc = ifp->if_softc;
     998             : 
     999           0 :         mii_pollstat(&sc->sc_mii);
    1000           0 :         ifmr->ifm_status = sc->sc_mii.mii_media_status;
    1001           0 :         ifmr->ifm_active = sc->sc_mii.mii_media_active;
    1002           0 : }
    1003             : 
    1004             : void
    1005           0 : xe_reset(sc)
    1006             :         struct xe_softc *sc;
    1007             : {
    1008             :         int s;
    1009             : 
    1010           0 :         s = splnet();
    1011           0 :         xe_stop(sc);
    1012           0 :         xe_full_reset(sc);
    1013           0 :         xe_init(sc);
    1014           0 :         splx(s);
    1015           0 : }
    1016             : 
    1017             : void
    1018           0 : xe_watchdog(ifp)
    1019             :         struct ifnet *ifp;
    1020             : {
    1021           0 :         struct xe_softc *sc = ifp->if_softc;
    1022             : 
    1023           0 :         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
    1024           0 :         ++sc->sc_arpcom.ac_if.if_oerrors;
    1025             : 
    1026           0 :         xe_reset(sc);
    1027           0 : }
    1028             : 
    1029             : void
    1030           0 : xe_stop(sc)
    1031             :         register struct xe_softc *sc;
    1032             : {
    1033             :         /* Disable interrupts. */
    1034           0 :         PAGE(sc, 0);
    1035           0 :         bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + CR, 0);
    1036             : 
    1037           0 :         PAGE(sc, 1);
    1038           0 :         bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + IMR0, 0);
    1039             :         
    1040             :         /* Power down, wait. */
    1041           0 :         PAGE(sc, 4);
    1042           0 :         bus_space_write_1(sc->sc_bst, sc->sc_bsh, sc->sc_offset + GP1, 0);
    1043           0 :         DELAY(40000);
    1044             :         
    1045             :         /* Cancel watchdog timer. */
    1046           0 :         sc->sc_arpcom.ac_if.if_timer = 0;
    1047           0 : }
    1048             : 
    1049             : void
    1050           0 : xe_init(sc)
    1051             :         struct xe_softc *sc;
    1052             : {
    1053           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
    1054             :         int s;
    1055             : 
    1056             :         DPRINTF(XED_CONFIG, ("xe_init\n"));
    1057             : 
    1058           0 :         s = splnet();
    1059             : 
    1060           0 :         xe_set_address(sc);
    1061             : 
    1062             :         /* Set current media. */
    1063           0 :         mii_mediachg(&sc->sc_mii);
    1064             : 
    1065           0 :         ifp->if_flags |= IFF_RUNNING;
    1066           0 :         ifq_clr_oactive(&ifp->if_snd);
    1067           0 :         splx(s);
    1068           0 : }
    1069             : 
    1070             : /*
    1071             :  * Start outputting on the interface.
    1072             :  * Always called as splnet().
    1073             :  */
    1074             : void
    1075           0 : xe_start(ifp)
    1076             :         struct ifnet *ifp;
    1077             : {
    1078           0 :         struct xe_softc *sc = ifp->if_softc;
    1079           0 :         bus_space_tag_t bst = sc->sc_bst;
    1080           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1081           0 :         bus_size_t offset = sc->sc_offset;
    1082             :         unsigned int s, len, pad = 0;
    1083             :         struct mbuf *m0, *m;
    1084             :         u_int16_t space;
    1085             : 
    1086             :         /* Don't transmit if interface is busy or not running. */
    1087           0 :         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
    1088           0 :                 return;
    1089             : 
    1090             :         /* Peek at the next packet. */
    1091           0 :         m0 = ifq_deq_begin(&ifp->if_snd);
    1092           0 :         if (m0 == NULL)
    1093           0 :                 return;
    1094             : 
    1095             :         /* We need to use m->m_pkthdr.len, so require the header. */
    1096           0 :         if (!(m0->m_flags & M_PKTHDR))
    1097           0 :                 panic("xe_start: no header mbuf");
    1098             : 
    1099           0 :         len = m0->m_pkthdr.len;
    1100             : 
    1101             :         /* Pad to ETHER_MIN_LEN - ETHER_CRC_LEN. */
    1102           0 :         if (len < ETHER_MIN_LEN - ETHER_CRC_LEN)
    1103           0 :                 pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
    1104             : 
    1105           0 :         PAGE(sc, 0);
    1106           0 :         space = bus_space_read_2(bst, bsh, offset + TSO0) & 0x7fff;
    1107           0 :         if (len + pad + 2 > space) {
    1108           0 :                 ifq_deq_rollback(&ifp->if_snd, m0);
    1109             :                 DPRINTF(XED_FIFO,
    1110             :                     ("%s: not enough space in output FIFO (%d > %d)\n",
    1111             :                     sc->sc_dev.dv_xname, len + pad + 2, space));
    1112           0 :                 return;
    1113             :         }
    1114             : 
    1115           0 :         ifq_deq_commit(&ifp->if_snd, m0);
    1116             : 
    1117             : #if NBPFILTER > 0
    1118           0 :         if (ifp->if_bpf)
    1119           0 :                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
    1120             : #endif
    1121             : 
    1122             :         /*
    1123             :          * Do the output at splhigh() so that an interrupt from another device
    1124             :          * won't cause a FIFO underrun.
    1125             :          */
    1126           0 :         s = splhigh();
    1127             : 
    1128           0 :         bus_space_write_2(bst, bsh, offset + TSO2, (u_int16_t)len + pad + 2);
    1129           0 :         bus_space_write_2(bst, bsh, offset + EDP, (u_int16_t)len + pad);
    1130           0 :         for (m = m0; m; ) {
    1131           0 :                 if (m->m_len > 1)
    1132           0 :                         bus_space_write_raw_multi_2(bst, bsh, offset + EDP,
    1133             :                             mtod(m, u_int8_t *), m->m_len & ~1);
    1134           0 :                 if (m->m_len & 1)
    1135           0 :                         bus_space_write_1(bst, bsh, offset + EDP,
    1136             :                             *(mtod(m, u_int8_t *) + m->m_len - 1));
    1137           0 :                 m0 = m_free(m);
    1138             :                 m = m0;
    1139             :         }
    1140           0 :         if (sc->sc_flags & XEF_MOHAWK)
    1141           0 :                 bus_space_write_1(bst, bsh, offset + CR, TX_PKT | ENABLE_INT);
    1142             :         else {
    1143           0 :                 for (; pad > 1; pad -= 2)
    1144           0 :                         bus_space_write_2(bst, bsh, offset + EDP, 0);
    1145           0 :                 if (pad == 1)
    1146           0 :                         bus_space_write_1(bst, bsh, offset + EDP, 0);
    1147             :         }
    1148             : 
    1149           0 :         splx(s);
    1150             : 
    1151           0 :         ifp->if_timer = 5;
    1152           0 : }
    1153             : 
    1154             : int
    1155           0 : xe_ioctl(ifp, command, data)
    1156             :         struct ifnet *ifp;
    1157             :         u_long command;
    1158             :         caddr_t data;
    1159             : {
    1160           0 :         struct xe_softc *sc = ifp->if_softc;
    1161           0 :         struct ifreq *ifr = (struct ifreq *)data;
    1162             :         int s, error = 0;
    1163             : 
    1164           0 :         s = splnet();
    1165             : 
    1166           0 :         switch (command) {
    1167             :         case SIOCSIFADDR:
    1168           0 :                 ifp->if_flags |= IFF_UP;
    1169           0 :                 xe_init(sc);
    1170           0 :                 break;
    1171             : 
    1172             :         case SIOCSIFFLAGS:
    1173           0 :                 sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
    1174             :                                 
    1175           0 :                 PAGE(sc, 0x42);
    1176           0 :                 if ((ifp->if_flags & IFF_PROMISC) ||
    1177           0 :                     (ifp->if_flags & IFF_ALLMULTI))
    1178           0 :                         bus_space_write_1(sc->sc_bst, sc->sc_bsh,
    1179             :                             sc->sc_offset + SWC1,
    1180             :                             SWC1_PROMISC | SWC1_MCAST_PROM);
    1181             :                 else
    1182           0 :                         bus_space_write_1(sc->sc_bst, sc->sc_bsh,
    1183             :                             sc->sc_offset + SWC1, 0);
    1184             : 
    1185             :                 /*
    1186             :                  * If interface is marked up and not running, then start it.
    1187             :                  * If it is marked down and running, stop it.
    1188             :                  * XXX If it's up then re-initialize it. This is so flags
    1189             :                  * such as IFF_PROMISC are handled.
    1190             :                  */
    1191           0 :                 if (ifp->if_flags & IFF_UP) {
    1192           0 :                         xe_init(sc);
    1193           0 :                 } else {
    1194           0 :                         if (ifp->if_flags & IFF_RUNNING)
    1195           0 :                                 xe_stop(sc);
    1196             :                 }
    1197             :                 break;
    1198             : 
    1199             :         case SIOCADDMULTI:
    1200             :         case SIOCDELMULTI:
    1201           0 :                 sc->sc_all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0;
    1202           0 :                 error = (command == SIOCADDMULTI) ?
    1203           0 :                     ether_addmulti(ifr, &sc->sc_arpcom) :
    1204           0 :                     ether_delmulti(ifr, &sc->sc_arpcom);
    1205             : 
    1206           0 :                 if (error == ENETRESET) {
    1207             :                         /*
    1208             :                          * Multicast list has changed; set the hardware
    1209             :                          * filter accordingly.
    1210             :                          */
    1211           0 :                         if (!sc->sc_all_mcasts &&
    1212           0 :                             !(ifp->if_flags & IFF_PROMISC))
    1213           0 :                                 xe_set_address(sc);
    1214             : 
    1215             :                         /*
    1216             :                          * xe_set_address() can turn on all_mcasts if we run
    1217             :                          * out of space, so check it again rather than else {}.
    1218             :                          */
    1219           0 :                         if (sc->sc_all_mcasts)
    1220           0 :                                 xe_init(sc);
    1221             :                         error = 0;
    1222           0 :                 }
    1223             :                 break;
    1224             : 
    1225             :         case SIOCSIFMEDIA:
    1226             :         case SIOCGIFMEDIA:
    1227             :                 error =
    1228           0 :                     ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
    1229           0 :                 break;
    1230             : 
    1231             :         default:
    1232             :                 error = ENOTTY;
    1233           0 :         }
    1234             : 
    1235           0 :         splx(s);
    1236           0 :         return (error);
    1237             : }
    1238             : 
    1239             : void
    1240           0 : xe_set_address(sc)
    1241             :         struct xe_softc *sc;
    1242             : {
    1243           0 :         bus_space_tag_t bst = sc->sc_bst;
    1244           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1245           0 :         bus_size_t offset = sc->sc_offset;
    1246           0 :         struct arpcom *arp = &sc->sc_arpcom;
    1247             :         struct ether_multi *enm;
    1248             :         struct ether_multistep step;
    1249           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
    1250             :         int i, page, pos, num;
    1251             : 
    1252           0 :         PAGE(sc, 0x50);
    1253           0 :         for (i = 0; i < 6; i++) {
    1254           0 :                 bus_space_write_1(bst, bsh, offset + IA + i,
    1255             :                     sc->sc_arpcom.ac_enaddr[(sc->sc_flags & XEF_MOHAWK) ?
    1256             :                     5 - i : i]);
    1257             :         }
    1258             : 
    1259           0 :         if (arp->ac_multirangecnt > 0) {
    1260           0 :                 ifp->if_flags |= IFF_ALLMULTI;
    1261           0 :                 sc->sc_all_mcasts=1;
    1262           0 :         } else if (arp->ac_multicnt > 0) {
    1263           0 :                 if (arp->ac_multicnt > 9) {
    1264           0 :                         PAGE(sc, 0x42);
    1265           0 :                         bus_space_write_1(sc->sc_bst, sc->sc_bsh,
    1266             :                             sc->sc_offset + SWC1,
    1267             :                             SWC1_PROMISC | SWC1_MCAST_PROM);
    1268           0 :                         return;
    1269             :                 }
    1270             : 
    1271           0 :                 ETHER_FIRST_MULTI(step, arp, enm);
    1272             : 
    1273             :                 pos = IA + 6;
    1274           0 :                 for (page = 0x50, num = arp->ac_multicnt; num > 0 && enm;
    1275           0 :                     num--) {
    1276           0 :                         for (i = 0; i < 6; i++) {
    1277           0 :                                 bus_space_write_1(bst, bsh, offset + pos,
    1278             :                                     enm->enm_addrlo[
    1279             :                                     (sc->sc_flags & XEF_MOHAWK) ? 5 - i : i]);
    1280             : 
    1281           0 :                                 if (++pos > 15) {
    1282             :                                         pos = IA;
    1283           0 :                                         page++;
    1284           0 :                                         PAGE(sc, page);
    1285           0 :                                 }
    1286             :                         }
    1287             :                 }
    1288             :         }
    1289           0 : }
    1290             : 
    1291             : void
    1292           0 : xe_cycle_power(sc)
    1293             :         struct xe_softc *sc;
    1294             : {
    1295           0 :         bus_space_tag_t bst = sc->sc_bst;
    1296           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1297           0 :         bus_size_t offset = sc->sc_offset;
    1298             : 
    1299           0 :         PAGE(sc, 4);
    1300           0 :         DELAY(1);
    1301           0 :         bus_space_write_1(bst, bsh, offset + GP1, 0);
    1302           0 :         DELAY(40000);
    1303           0 :         if (sc->sc_flags & XEF_MOHAWK)
    1304           0 :                 bus_space_write_1(bst, bsh, offset + GP1, POWER_UP);
    1305             :         else
    1306             :                 /* XXX What is bit 2 (aka AIC)? */
    1307           0 :                 bus_space_write_1(bst, bsh, offset + GP1, POWER_UP | 4);
    1308           0 :         DELAY(20000);
    1309           0 : }
    1310             : 
    1311             : void
    1312           0 : xe_full_reset(sc)
    1313             :         struct xe_softc *sc;
    1314             : {
    1315           0 :         bus_space_tag_t bst = sc->sc_bst;
    1316           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1317           0 :         bus_size_t offset = sc->sc_offset;
    1318             : 
    1319             :         /* Do an as extensive reset as possible on all functions. */
    1320           0 :         xe_cycle_power(sc);
    1321           0 :         bus_space_write_1(bst, bsh, offset + CR, SOFT_RESET);
    1322           0 :         DELAY(20000);
    1323           0 :         bus_space_write_1(bst, bsh, offset + CR, 0);
    1324           0 :         DELAY(20000);
    1325           0 :         if (sc->sc_flags & XEF_MOHAWK) {
    1326           0 :                 PAGE(sc, 4);
    1327             :                 /*
    1328             :                  * Drive GP1 low to power up ML6692 and GP2 high to power up
    1329             :                  * the 10MHz chip.  XXX What chip is that?  The phy?
    1330             :                  */
    1331           0 :                 bus_space_write_1(bst, bsh, offset + GP0,
    1332             :                     GP1_OUT | GP2_OUT | GP2_WR);
    1333           0 :         }
    1334           0 :         DELAY(500000);
    1335             : 
    1336             :         /* Get revision information.  XXX Symbolic constants. */
    1337           0 :         sc->sc_rev = bus_space_read_1(bst, bsh, offset + BV) &
    1338           0 :             ((sc->sc_flags & XEF_MOHAWK) ? 0x70 : 0x30) >> 4;
    1339             : 
    1340             :         /* Media selection.  XXX Maybe manual overriding too? */
    1341           0 :         if (!(sc->sc_flags & XEF_MOHAWK)) {
    1342           0 :                 PAGE(sc, 4);
    1343             :                 /*
    1344             :                  * XXX I have no idea what this really does, it is from the
    1345             :                  * Linux driver.
    1346             :                  */
    1347           0 :                 bus_space_write_1(bst, bsh, offset + GP0, GP1_OUT);
    1348           0 :         }
    1349           0 :         DELAY(40000);
    1350             : 
    1351             :         /* Setup the ethernet interrupt mask. */
    1352           0 :         PAGE(sc, 1);
    1353           0 :         bus_space_write_1(bst, bsh, offset + IMR0,
    1354             :             ISR_TX_OFLOW | ISR_PKT_TX | ISR_MAC_INT | /* ISR_RX_EARLY | */
    1355             :             ISR_RX_FULL | ISR_RX_PKT_REJ | ISR_FORCED_INT);
    1356             : #if 0
    1357             :         bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
    1358             : #endif
    1359           0 :         if (!(sc->sc_flags & XEF_DINGO))
    1360             :                 /* XXX What is this?  Not for Dingo at least. */
    1361           0 :                 bus_space_write_1(bst, bsh, offset + IMR1, 1);
    1362             : 
    1363             :         /*
    1364             :          * Disable source insertion.
    1365             :          * XXX Dingo does not have this bit, but Linux does it unconditionally.
    1366             :          */
    1367           0 :         if (!(sc->sc_flags & XEF_DINGO)) {
    1368           0 :                 PAGE(sc, 0x42);
    1369           0 :                 bus_space_write_1(bst, bsh, offset + SWC0, 0x20);
    1370           0 :         }
    1371             : 
    1372             :         /* Set the local memory dividing line. */
    1373           0 :         if (sc->sc_rev != 1) {
    1374           0 :                 PAGE(sc, 2);
    1375             :                 /* XXX Symbolic constant preferrable. */
    1376           0 :                 bus_space_write_2(bst, bsh, offset + RBS0, 0x2000);
    1377           0 :         }
    1378             : 
    1379           0 :         xe_set_address(sc);
    1380             : 
    1381             :         /*
    1382             :          * Apparently the receive byte pointer can be bad after a reset, so
    1383             :          * we hardwire it correctly.
    1384             :          */
    1385           0 :         PAGE(sc, 0);
    1386           0 :         bus_space_write_2(bst, bsh, offset + DO0, DO_CHG_OFFSET);
    1387             : 
    1388             :         /* Setup ethernet MAC registers. XXX Symbolic constants. */
    1389           0 :         PAGE(sc, 0x40);
    1390           0 :         bus_space_write_1(bst, bsh, offset + RX0MSK,
    1391             :             PKT_TOO_LONG | CRC_ERR | RX_OVERRUN | RX_ABORT | RX_OK);
    1392           0 :         bus_space_write_1(bst, bsh, offset + TX0MSK,
    1393             :             CARRIER_LOST | EXCESSIVE_COLL | TX_UNDERRUN | LATE_COLLISION |
    1394             :             SQE | TX_ABORT | TX_OK);
    1395           0 :         if (!(sc->sc_flags & XEF_DINGO))
    1396             :                 /* XXX From Linux, dunno what 0xb0 means. */
    1397           0 :                 bus_space_write_1(bst, bsh, offset + TX1MSK, 0xb0);
    1398           0 :         bus_space_write_1(bst, bsh, offset + RXST0, 0);
    1399           0 :         bus_space_write_1(bst, bsh, offset + TXST0, 0);
    1400           0 :         bus_space_write_1(bst, bsh, offset + TXST1, 0);
    1401             : 
    1402             :         /* Enable MII function if available. */
    1403           0 :         if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
    1404           0 :                 PAGE(sc, 2);
    1405           0 :                 bus_space_write_1(bst, bsh, offset + MSR,
    1406             :                     bus_space_read_1(bst, bsh, offset + MSR) | SELECT_MII);
    1407           0 :                 DELAY(20000);
    1408           0 :         } else {
    1409           0 :                 PAGE(sc, 0);
    1410             :                                 
    1411             :                 /* XXX Do we need to do this? */
    1412           0 :                 PAGE(sc, 0x42);
    1413           0 :                 bus_space_write_1(bst, bsh, offset + SWC1, SWC1_AUTO_MEDIA);
    1414           0 :                 DELAY(50000);
    1415             : 
    1416             :                 /* XXX Linux probes the media here. */
    1417             :         }
    1418             : 
    1419             :         /* Configure the LED registers. */
    1420           0 :         PAGE(sc, 2);
    1421             : 
    1422             :         /* XXX This is not good for 10base2. */
    1423           0 :         bus_space_write_1(bst, bsh, offset + LED,
    1424             :             LED_TX_ACT << LED1_SHIFT | LED_10MB_LINK << LED0_SHIFT);
    1425           0 :         if (sc->sc_flags & XEF_DINGO)
    1426           0 :                 bus_space_write_1(bst, bsh, offset + LED3,
    1427             :                     LED_100MB_LINK << LED3_SHIFT);
    1428             : 
    1429             :         /* Enable receiver and go online. */
    1430           0 :         PAGE(sc, 0x40);
    1431           0 :         bus_space_write_1(bst, bsh, offset + CMD0, ENABLE_RX | ONLINE);
    1432             : 
    1433             : #if 0
    1434             :         /* XXX Linux does this here - is it necessary? */
    1435             :         PAGE(sc, 1);
    1436             :         bus_space_write_1(bst, bsh, offset + IMR0, 0xff);
    1437             :         if (!(sc->sc_flags & XEF_DINGO))
    1438             :                 /* XXX What is this?  Not for Dingo at least. */
    1439             :                 bus_space_write_1(bst, bsh, offset + IMR1, 1);
    1440             : #endif
    1441             : 
    1442             :        /* Enable interrupts. */
    1443           0 :         PAGE(sc, 0);
    1444           0 :         bus_space_write_1(bst, bsh, offset + CR, ENABLE_INT);
    1445             : 
    1446             :         /* XXX This is pure magic for me, found in the Linux driver. */
    1447           0 :         if ((sc->sc_flags & (XEF_DINGO | XEF_MODEM)) == XEF_MODEM) {
    1448           0 :                 if ((bus_space_read_1(bst, bsh, offset + 0x10) & 0x01) == 0)
    1449             :                         /* Unmask the master interrupt bit. */
    1450           0 :                         bus_space_write_1(bst, bsh, offset + 0x10, 0x11);
    1451             :         }
    1452             : 
    1453             :         /*
    1454             :          * The Linux driver says this:
    1455             :          * We should switch back to page 0 to avoid a bug in revision 0
    1456             :          * where regs with offset below 8 can't be read after an access
    1457             :          * to the MAC registers.
    1458             :          */
    1459           0 :         PAGE(sc, 0);
    1460           0 : }
    1461             : 
    1462             : #ifdef XEDEBUG
    1463             : void
    1464             : xe_reg_dump(sc)
    1465             :         struct xe_softc *sc;
    1466             : {
    1467             :         int page, i;
    1468             :         bus_space_tag_t bst = sc->sc_bst;
    1469             :         bus_space_handle_t bsh = sc->sc_bsh;
    1470             :         bus_size_t offset = sc->sc_offset;
    1471             : 
    1472             :         printf("%x: Common registers: ", sc->sc_dev.dv_xname);
    1473             :         for (i = 0; i < 8; i++) {
    1474             :                 printf(" %2.2x", bus_space_read_1(bst, bsh, offset + i));
    1475             :         }
    1476             :         printf("\n");
    1477             : 
    1478             :         for (page = 0; page < 8; page++) {
    1479             :                 printf("%s: Register page %2.2x: ", sc->sc_dev.dv_xname, page);
    1480             :                 PAGE(sc, page);
    1481             :                 for (i = 8; i < 16; i++) {
    1482             :                         printf(" %2.2x",
    1483             :                             bus_space_read_1(bst, bsh, offset + i));
    1484             :                 }
    1485             :                 printf("\n");
    1486             :         }
    1487             : 
    1488             :         for (page = 0x40; page < 0x5f; page++) {
    1489             :                 if (page == 0x43 || (page >= 0x46 && page <= 0x4f) ||
    1490             :                     (page >= 0x51 && page <= 0x5e))
    1491             :                         continue;
    1492             :                 printf("%s: Register page %2.2x: ", sc->sc_dev.dv_xname, page);
    1493             :                 PAGE(sc, page);
    1494             :                 for (i = 8; i < 16; i++) {
    1495             :                         printf(" %2.2x",
    1496             :                             bus_space_read_1(bst, bsh, offset + i));
    1497             :                 }
    1498             :                 printf("\n");
    1499             :         }
    1500             : }
    1501             : #endif  /* XEDEBUG */

Generated by: LCOV version 1.13