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/pci/if_en_pci.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_en_pci.c,v 1.1 1996/06/22 02:00:31 chuck Exp $      */
    2 
    3 /*
    4  *
    5  * Copyright (c) 1996 Charles D. Cranor and Washington University.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by Charles D. Cranor and
   19  *      Washington University.
   20  * 4. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  *
   34  * $FreeBSD: releng/5.1/sys/pci/if_en_pci.c 114739 2003-05-05 16:35:52Z harti $
   35  */
   36 
   37 /*
   38  *
   39  * i f _ e n _ p c i . c  
   40  *
   41  * author: Chuck Cranor <chuck@ccrc.wustl.edu>
   42  * started: spring, 1996.
   43  *
   44  * FreeBSD PCI glue for the eni155p card.
   45  * thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs.
   46  */
   47 #include <sys/param.h>
   48 #include <sys/kernel.h>
   49 #include <sys/systm.h>
   50 #include <sys/socket.h>
   51 #include <sys/sysctl.h>
   52 
   53 #include <sys/bus.h>
   54 #include <machine/bus.h>
   55 #include <sys/rman.h>
   56 #include <machine/resource.h>
   57 
   58 #include <vm/uma.h>
   59 
   60 #include <net/if.h>
   61 #include <net/if_atm.h>
   62 
   63 #include <pci/pcivar.h>
   64 #include <pci/pcireg.h>
   65 
   66 #include <dev/en/midwayreg.h>
   67 #include <dev/en/midwayvar.h>
   68 
   69 MODULE_DEPEND(en, pci, 1, 1, 1);
   70 MODULE_DEPEND(en, atm, 1, 1, 1);
   71 
   72 /*
   73  * local structures
   74  */
   75 struct en_pci_softc {
   76         /* bus independent stuff */
   77         struct en_softc esc;    /* includes "device" structure */
   78 
   79         /* freebsd newbus glue */
   80         struct resource *res;   /* resource descriptor for registers */
   81         struct resource *irq;   /* resource descriptor for interrupt */
   82         void *ih;               /* interrupt handle */
   83 };
   84 
   85 static  void eni_get_macaddr(device_t, struct en_pci_softc *);
   86 static  void adp_get_macaddr(struct en_pci_softc *);
   87 
   88 /* 
   89  * address of config base memory address register in PCI config space
   90  * (this is card specific)
   91  */
   92 #define PCI_CBMA        0x10
   93 
   94 /*
   95  * tonga (pci bridge).   ENI cards only!
   96  */
   97 #define EN_TONGA        0x60            /* PCI config addr of tonga reg */
   98 
   99 #define TONGA_SWAP_DMA  0x80            /* endian swap control */
  100 #define TONGA_SWAP_BYTE 0x40
  101 #define TONGA_SWAP_WORD 0x20
  102 #define TONGA_READ_MULT 0x00
  103 #define TONGA_READ_MEM  0x04
  104 #define TONGA_READ_IVAN 0x08
  105 #define TONGA_READ_KEN  0x0C
  106 
  107 /*
  108  * adaptec pci bridge.   ADP cards only!
  109  */
  110 #define ADP_PCIREG      0x050040        /* PCI control register */
  111 
  112 #define ADP_PCIREG_RESET        0x1     /* reset card */
  113 #define ADP_PCIREG_IENABLE      0x2     /* interrupt enable */
  114 #define ADP_PCIREG_SWAP_WORD    0x4     /* swap byte on slave access */
  115 #define ADP_PCIREG_SWAP_DMA     0x8     /* swap byte on DMA */
  116 
  117 #define PCI_VENDOR_EFFICIENTNETS 0x111a                 /* Efficent Networks */
  118 #define PCI_PRODUCT_EFFICIENTNETS_ENI155PF 0x0000       /* ENI-155P ATM */
  119 #define PCI_PRODUCT_EFFICIENTNETS_ENI155PA 0x0002       /* ENI-155P ATM */
  120 #define PCI_VENDOR_ADP 0x9004                           /* adaptec */
  121 #define PCI_PRODUCT_ADP_AIC5900 0x5900
  122 #define PCI_PRODUCT_ADP_AIC5905 0x5905
  123 #define PCI_VENDOR(x)           ((x) & 0xFFFF)
  124 #define PCI_CHIPID(x)           (((x) >> 16) & 0xFFFF)
  125 
  126 /*
  127  * bus specific reset function [ADP only!]
  128  */
  129 static void
  130 adp_busreset(void *v)
  131 {
  132         struct en_softc *sc = (struct en_softc *)v;
  133         uint32_t dummy;
  134 
  135         bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG,
  136             ADP_PCIREG_RESET);
  137         DELAY(1000);                    /* let it reset */
  138         dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
  139         bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, 
  140             (ADP_PCIREG_SWAP_DMA | ADP_PCIREG_IENABLE));
  141         dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
  142         if ((dummy & (ADP_PCIREG_SWAP_WORD | ADP_PCIREG_SWAP_DMA)) !=
  143             ADP_PCIREG_SWAP_DMA)
  144                 if_printf(&sc->ifatm.ifnet, "adp_busreset: Adaptec ATM did "
  145                     "NOT reset!\n");
  146 }
  147 
  148 /***********************************************************************/
  149 
  150 /*
  151  * autoconfig stuff
  152  */
  153 static int
  154 en_pci_probe(device_t dev)
  155 {
  156         switch (pci_get_vendor(dev)) {
  157 
  158           case PCI_VENDOR_EFFICIENTNETS:
  159                 switch (pci_get_device(dev)) {
  160 
  161                     case PCI_PRODUCT_EFFICIENTNETS_ENI155PF:
  162                     case PCI_PRODUCT_EFFICIENTNETS_ENI155PA:
  163                         device_set_desc(dev, "Efficient Networks ENI-155p");
  164                         return (0);
  165                 }
  166                 break;
  167 
  168           case PCI_VENDOR_ADP:
  169                 switch (pci_get_device(dev)) {
  170 
  171                   case PCI_PRODUCT_ADP_AIC5900:
  172                   case PCI_PRODUCT_ADP_AIC5905:
  173                         device_set_desc(dev, "Adaptec 155 ATM");
  174                         return (0);
  175                 }
  176                 break;
  177         }
  178         return (ENXIO);
  179 }
  180 
  181 static int
  182 en_pci_attach(device_t dev)
  183 {
  184         struct en_softc *sc;
  185         struct en_pci_softc *scp;
  186         u_long val;
  187         int rid, unit, error = 0;
  188 
  189         sc = device_get_softc(dev);
  190         scp = (struct en_pci_softc *)sc;
  191 
  192         unit = device_get_unit(dev);
  193         sc->ifatm.ifnet.if_unit = unit;
  194         sc->ifatm.ifnet.if_name = "en";
  195 
  196         /*
  197          * Enable bus mastering.
  198          */
  199         val = pci_read_config(dev, PCIR_COMMAND, 2);
  200         val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
  201         pci_write_config(dev, PCIR_COMMAND, val, 2);
  202 
  203         /*
  204          * Map control/status registers.
  205          */
  206         rid = PCI_CBMA;
  207         scp->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
  208             0, ~0, 1, RF_ACTIVE);
  209         if (scp->res == NULL) {
  210                 device_printf(dev, "could not map memory\n");
  211                 error = ENXIO;
  212                 goto fail;
  213         }
  214 
  215         sc->dev = dev;
  216         sc->en_memt = rman_get_bustag(scp->res);
  217         sc->en_base = rman_get_bushandle(scp->res);
  218 
  219         /*
  220          * Allocate our interrupt.
  221          */
  222         rid = 0;
  223         scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
  224             RF_SHAREABLE | RF_ACTIVE);
  225         if (scp->irq == NULL) {
  226                 device_printf(dev, "could not map interrupt\n");
  227                 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
  228                 error = ENXIO;
  229                 goto fail;
  230         }
  231 
  232         sc->ipl = 1; /* XXX (required to enable interrupt on midway) */
  233 
  234         /* figure out if we are an adaptec card or not */
  235         sc->is_adaptec = (pci_get_vendor(dev) == PCI_VENDOR_ADP) ? 1 : 0;
  236 
  237         /*
  238          * set up pci bridge
  239          */
  240         if (sc->is_adaptec) {
  241                 adp_get_macaddr(scp);
  242                 sc->en_busreset = adp_busreset;
  243                 adp_busreset(sc);
  244         } else {
  245                 eni_get_macaddr(dev, scp);
  246                 sc->en_busreset = NULL;
  247                 pci_write_config(dev, EN_TONGA, TONGA_SWAP_DMA | TONGA_READ_IVAN, 4);
  248         }
  249 
  250         /*
  251          * Common attach stuff
  252          */
  253         if ((error = en_attach(sc)) != 0) {
  254                 device_printf(dev, "attach failed\n");
  255                 bus_teardown_intr(dev, scp->irq, scp->ih);
  256                 bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
  257                 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
  258                 goto fail;
  259         }
  260 
  261         /*
  262          * Do the interrupt SETUP last just before returning
  263          */
  264         error = bus_setup_intr(dev, scp->irq, INTR_TYPE_NET,
  265             en_intr, sc, &scp->ih);
  266         if (error) {
  267                 en_reset(sc);
  268                 atm_ifdetach(&sc->ifatm.ifnet);
  269                 device_printf(dev, "could not setup irq\n");
  270                 bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
  271                 bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
  272                 en_destroy(sc);
  273                 goto fail;
  274         }
  275 
  276         return (0);
  277 
  278     fail:
  279         return (error);
  280 }
  281 
  282 /*
  283  * Detach the adapter
  284  */
  285 static int
  286 en_pci_detach(device_t dev)
  287 {
  288         struct en_softc *sc = device_get_softc(dev);
  289         struct en_pci_softc *scp = (struct en_pci_softc *)sc;
  290 
  291         /*
  292          * Stop DMA and drop transmit queue.
  293          */
  294         if ((sc->ifatm.ifnet.if_flags & IFF_RUNNING)) {
  295                 if_printf(&sc->ifatm.ifnet, "still running\n");
  296                 sc->ifatm.ifnet.if_flags &= ~IFF_RUNNING;
  297         }
  298 
  299         /*
  300          * Close down routes etc.
  301          */
  302         en_reset(sc);
  303         atm_ifdetach(&sc->ifatm.ifnet);
  304 
  305         /*
  306          * Deallocate resources.
  307          */
  308         bus_teardown_intr(dev, scp->irq, scp->ih);
  309         bus_release_resource(dev, SYS_RES_IRQ, 0, scp->irq);
  310         bus_release_resource(dev, SYS_RES_MEMORY, PCI_CBMA, scp->res);
  311 
  312         /*
  313          * Free all the driver internal resources
  314          */
  315         en_destroy(sc);
  316 
  317         return (0);
  318 }
  319 
  320 static int
  321 en_pci_shutdown(device_t dev)
  322 {
  323         struct en_pci_softc *psc = device_get_softc(dev);
  324 
  325         en_reset(&psc->esc);
  326         DELAY(10);              /* is this necessary? */
  327 
  328         return (0);
  329 }
  330 
  331 /*
  332  * Get the MAC address from an Adaptec board. No idea how to get
  333  * serial number or other stuff, because I have no documentation for that
  334  * card.
  335  */
  336 static void 
  337 adp_get_macaddr(struct en_pci_softc *scp)
  338 {
  339         struct en_softc * sc = (struct en_softc *)scp;
  340         int lcv;
  341 
  342         for (lcv = 0; lcv < sizeof(sc->ifatm.mib.esi); lcv++)
  343                 sc->ifatm.mib.esi[lcv] = bus_space_read_1(sc->en_memt,
  344                     sc->en_base, MID_ADPMACOFF + lcv);
  345 }
  346 
  347 /*
  348  * Read station (MAC) address from serial EEPROM.
  349  * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
  350  */
  351 #define EN_PROM_MAGIC   0x0c
  352 #define EN_PROM_DATA    0x02
  353 #define EN_PROM_CLK     0x01
  354 #define EN_ESI          64
  355 #define EN_SERIAL       112
  356 
  357 /*
  358  * Read a byte from the given address in the EEPROM
  359  */
  360 static uint8_t
  361 eni_get_byte(device_t dev, uint32_t *data, u_int address)
  362 {
  363         int j;
  364         uint8_t tmp;
  365 
  366         address = (address << 1) + 1;
  367 
  368         /* start operation */
  369         *data |= EN_PROM_DATA ;
  370         pci_write_config(dev, EN_TONGA, *data, 4);
  371         *data |= EN_PROM_CLK ;
  372         pci_write_config(dev, EN_TONGA, *data, 4);
  373         *data &= ~EN_PROM_DATA ;
  374         pci_write_config(dev, EN_TONGA, *data, 4);
  375         *data &= ~EN_PROM_CLK ;
  376         pci_write_config(dev, EN_TONGA, *data, 4);
  377         /* send address with serial line */
  378         for ( j = 7 ; j >= 0 ; j --) {
  379                 *data = ((address >> j) & 1) ? (*data | EN_PROM_DATA) :
  380                     (*data & ~EN_PROM_DATA);
  381                 pci_write_config(dev, EN_TONGA, *data, 4);
  382                 *data |= EN_PROM_CLK ;
  383                 pci_write_config(dev, EN_TONGA, *data, 4);
  384                 *data &= ~EN_PROM_CLK ;
  385                 pci_write_config(dev, EN_TONGA, *data, 4);
  386         }
  387         /* get ack */
  388         *data |= EN_PROM_DATA ;
  389         pci_write_config(dev, EN_TONGA, *data, 4);
  390         *data |= EN_PROM_CLK ;
  391         pci_write_config(dev, EN_TONGA, *data, 4);
  392         *data = pci_read_config(dev, EN_TONGA, 4);
  393         *data &= ~EN_PROM_CLK ;
  394         pci_write_config(dev, EN_TONGA, *data, 4);
  395         *data |= EN_PROM_DATA ;
  396         pci_write_config(dev, EN_TONGA, *data, 4);
  397 
  398         tmp = 0;
  399 
  400         for ( j = 7 ; j >= 0 ; j --) {
  401                 tmp <<= 1;
  402                 *data |= EN_PROM_DATA ;
  403                 pci_write_config(dev, EN_TONGA, *data, 4);
  404                 *data |= EN_PROM_CLK ;
  405                 pci_write_config(dev, EN_TONGA, *data, 4);
  406                 *data = pci_read_config(dev, EN_TONGA, 4);
  407                 if(*data & EN_PROM_DATA) tmp |= 1;
  408                 *data &= ~EN_PROM_CLK ;
  409                 pci_write_config(dev, EN_TONGA, *data, 4);
  410                 *data |= EN_PROM_DATA ;
  411                 pci_write_config(dev, EN_TONGA, *data, 4);
  412         }
  413         /* get ack */
  414         *data |= EN_PROM_DATA ;
  415         pci_write_config(dev, EN_TONGA, *data, 4);
  416         *data |= EN_PROM_CLK ;
  417         pci_write_config(dev, EN_TONGA, *data, 4);
  418         *data = pci_read_config(dev, EN_TONGA, 4);
  419         *data &= ~EN_PROM_CLK ;
  420         pci_write_config(dev, EN_TONGA, *data, 4);
  421         *data |= EN_PROM_DATA ;
  422         pci_write_config(dev, EN_TONGA, *data, 4);
  423 
  424         return (tmp);
  425 }
  426 
  427 /*
  428  * Get MAC address and other stuff from the EEPROM
  429  */
  430 static void 
  431 eni_get_macaddr(device_t dev, struct en_pci_softc *scp)
  432 {
  433         struct en_softc * sc = (struct en_softc *)scp;
  434         int i;
  435         uint32_t data, t_data;
  436 
  437         t_data = pci_read_config(dev, EN_TONGA, 4) & 0xffffff00;
  438 
  439         data =  EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
  440         pci_write_config(dev, EN_TONGA, data, 4);
  441 
  442         for (i = 0; i < sizeof(sc->ifatm.mib.esi); i ++)
  443                 sc->ifatm.mib.esi[i] = eni_get_byte(dev, &data, i + EN_ESI);
  444 
  445         sc->ifatm.mib.serial = 0;
  446         for (i = 0; i < 4; i++) {
  447                 sc->ifatm.mib.serial <<= 8;
  448                 sc->ifatm.mib.serial |= eni_get_byte(dev, &data, i + EN_SERIAL);
  449         }
  450         /* stop operation */
  451         data &=  ~EN_PROM_DATA;
  452         pci_write_config(dev, EN_TONGA, data, 4);
  453         data |=  EN_PROM_CLK;
  454         pci_write_config(dev, EN_TONGA, data, 4);
  455         data |=  EN_PROM_DATA;
  456         pci_write_config(dev, EN_TONGA, data, 4);
  457         pci_write_config(dev, EN_TONGA, t_data, 4);
  458 }
  459 
  460 /*
  461  * Driver infrastructure
  462  */
  463 static device_method_t en_methods[] = {
  464         /* Device interface */
  465         DEVMETHOD(device_probe,         en_pci_probe),
  466         DEVMETHOD(device_attach,        en_pci_attach),
  467         DEVMETHOD(device_detach,        en_pci_detach),
  468         DEVMETHOD(device_shutdown,      en_pci_shutdown),
  469 
  470         { 0, 0 }
  471 };
  472 
  473 static driver_t en_driver = {
  474         "en",
  475         en_methods,
  476         sizeof(struct en_pci_softc),
  477 };
  478 
  479 static devclass_t en_devclass;
  480 
  481 DRIVER_MODULE(en, pci, en_driver, en_devclass, 0, 0);

Cache object: 0fee0e413c023c484e16b9ad15e97cd0


[ 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.