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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/netif/en_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: src/sys/pci/if_en_pci.c,v 1.12 1999/08/21 22:10:49 msmith Exp $
   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 
   48 #include "use_en.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/bus.h>
   52 #include <sys/kernel.h>
   53 #include <sys/systm.h>
   54 #if defined(__DragonFly__) || defined(__FreeBSD__)
   55 #include <sys/eventhandler.h>
   56 #endif
   57 #include <sys/malloc.h>
   58 #include <sys/socket.h>
   59 
   60 #include <machine/clock.h>              /* for DELAY */
   61 
   62 #include <net/if.h>
   63 
   64 #include "pcidevs.h"
   65 #include <bus/pci/pcivar.h>
   66 #include <bus/pci/pcireg.h>
   67 
   68 #include <dev/atm/en/midwayreg.h>
   69 #include <dev/atm/en/midwayvar.h>
   70 
   71 
   72 /*
   73  * prototypes
   74  */
   75 
   76 static  void en_pci_attach (pcici_t, int);
   77 static  const char *en_pci_probe (pcici_t, pcidi_t);
   78 static void en_pci_shutdown (void *, int);
   79 
   80 /*
   81  * local structures
   82  */
   83 
   84 struct en_pci_softc {
   85   /* bus independent stuff */
   86   struct en_softc esc;          /* includes "device" structure */
   87 
   88   /* PCI bus glue */
   89   void *sc_ih;                  /* interrupt handle */
   90   pci_chipset_tag_t en_pc;      /* for PCI calls */
   91   pcici_t en_confid;            /* config id */
   92 };
   93 
   94 #if !defined(MIDWAY_ENIONLY)
   95 static  void eni_get_macaddr (struct en_pci_softc *);
   96 #endif
   97 #if !defined(MIDWAY_ADPONLY)
   98 static  void adp_get_macaddr (struct en_pci_softc *);
   99 #endif
  100 
  101 /*
  102  * pointers to softcs (we alloc)
  103  */
  104 
  105 static struct en_pci_softc *enpcis[NEN] = {0};
  106 extern struct cfdriver en_cd;
  107 
  108 /*
  109  * autoconfig structures
  110  */
  111 
  112 static u_long en_pci_count;
  113 
  114 static struct pci_device endevice = {
  115         "en",
  116         en_pci_probe,
  117         en_pci_attach,
  118         &en_pci_count,
  119         NULL,
  120 };  
  121 
  122 COMPAT_PCI_DRIVER (if_en, endevice);
  123 
  124 /*
  125  * local defines (PCI specific stuff)
  126  */
  127 
  128 /* 
  129  * address of config base memory address register in PCI config space
  130  * (this is card specific)
  131  */
  132         
  133 #define PCI_CBMA        0x10
  134 
  135 /*
  136  * tonga (pci bridge).   ENI cards only!
  137  */
  138 
  139 #define EN_TONGA        0x60            /* PCI config addr of tonga reg */
  140 
  141 #define TONGA_SWAP_DMA  0x80            /* endian swap control */
  142 #define TONGA_SWAP_BYTE 0x40
  143 #define TONGA_SWAP_WORD 0x20
  144 
  145 /*
  146  * adaptec pci bridge.   ADP cards only!
  147  */
  148 
  149 #define ADP_PCIREG      0x050040        /* PCI control register */
  150 
  151 #define ADP_PCIREG_RESET        0x1     /* reset card */
  152 #define ADP_PCIREG_IENABLE      0x2     /* interrupt enable */
  153 #define ADP_PCIREG_SWAP_WORD    0x4     /* swap byte on slave access */
  154 #define ADP_PCIREG_SWAP_DMA     0x8     /* swap byte on DMA */
  155 
  156 #define PCI_VENDOR(x)           ((x) & 0xFFFF)
  157 #define PCI_CHIPID(x)           (((x) >> 16) & 0xFFFF)
  158 
  159 #if !defined(MIDWAY_ENIONLY)
  160 
  161 static void adp_busreset (void *);
  162 
  163 /*
  164  * bus specific reset function [ADP only!]
  165  */
  166 
  167 static void
  168 adp_busreset(void *v)
  169 {
  170   struct en_softc *sc = (struct en_softc *) v;
  171   u_int32_t dummy;
  172 
  173   bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, ADP_PCIREG_RESET);
  174   DELAY(1000);  /* let it reset */
  175   dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
  176   bus_space_write_4(sc->en_memt, sc->en_base, ADP_PCIREG, 
  177                 (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA|ADP_PCIREG_IENABLE));
  178   dummy = bus_space_read_4(sc->en_memt, sc->en_base, ADP_PCIREG);
  179   if ((dummy & (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA)) !=
  180                 (ADP_PCIREG_SWAP_WORD|ADP_PCIREG_SWAP_DMA))
  181     kprintf("adp_busreset: Adaptec ATM did NOT reset!\n");
  182 }
  183 #endif
  184 
  185 /***********************************************************************/
  186 
  187 /*
  188  * autoconfig stuff
  189  */
  190 
  191 static const char *
  192 en_pci_probe(pcici_t config_id, pcidi_t device_id)
  193 {
  194 #if !defined(MIDWAY_ADPONLY)
  195   if (PCI_VENDOR(device_id) == PCI_VENDOR_EFFICIENTNETS && 
  196       (PCI_CHIPID(device_id) == PCI_PRODUCT_EFFICIENTNETS_ENI155PF ||
  197        PCI_CHIPID(device_id) == PCI_PRODUCT_EFFICIENTNETS_ENI155PA))
  198     return "Efficient Networks ENI-155p";
  199 #endif
  200 
  201 #if !defined(MIDWAY_ENIONLY)
  202   if (PCI_VENDOR(device_id) == PCI_VENDOR_ADP && 
  203       (PCI_CHIPID(device_id) == PCI_PRODUCT_ADP_AIC5900 ||
  204        PCI_CHIPID(device_id) == PCI_PRODUCT_ADP_AIC5905))
  205     return "Adaptec 155 ATM";
  206 #endif
  207 
  208   return 0;
  209 }
  210 
  211 static void
  212 en_pci_attach(pcici_t config_id, int unit)
  213 {
  214   struct en_softc *sc;
  215   struct en_pci_softc *scp;
  216   pcidi_t device_id;
  217   int retval;
  218   vm_offset_t pa;
  219 
  220   if (unit >= NEN) {
  221     kprintf("en%d: not configured; kernel is built for only %d device%s.\n",
  222         unit, NEN, NEN == 1 ? "" : "s");
  223     return;
  224   }
  225 
  226   scp = kmalloc(sizeof(*scp), M_DEVBUF, M_WAITOK | M_ZERO);
  227   sc = &scp->esc;
  228 
  229   retval = pci_map_mem(config_id, PCI_CBMA, (vm_offset_t *) &sc->en_base, &pa);
  230 
  231   if (!retval) {
  232     kfree((caddr_t) scp, M_DEVBUF);
  233     return;
  234   }
  235   enpcis[unit] = scp;                   /* lock it in */
  236   en_cd.cd_devs[unit] = sc;             /* fake a cfdriver structure */
  237   en_cd.cd_ndevs = NEN;
  238   if_initname(&(sc->enif), "en", unit);
  239   ksnprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), "%s",
  240       sc->enif.if_xname);
  241   scp->en_confid = config_id;
  242 
  243   /*
  244    * figure out if we are an adaptec card or not.
  245    * XXX: why do we have to re-read PC_ID_REG when en_pci_probe already
  246    * had that info?
  247    */
  248 
  249   device_id = pci_conf_read(config_id, PCI_ID_REG);
  250   sc->is_adaptec = (PCI_VENDOR(device_id) == PCI_VENDOR_ADP) ? 1 : 0;
  251   
  252   /*
  253    * Add shutdown hook so that DMA is disabled prior to reboot. Not
  254    * doing so could allow DMA to corrupt kernel memory during the
  255    * reboot before the driver initializes.
  256    */
  257   EVENTHANDLER_REGISTER(shutdown_post_sync, en_pci_shutdown, scp,
  258                         SHUTDOWN_PRI_DRIVER);
  259 
  260   if (!pci_map_int(config_id, en_intr, (void *) sc)) {
  261     kprintf("%s: couldn't establish interrupt\n", sc->sc_dev.dv_xname);
  262     return;
  263   }
  264   sc->ipl = 1; /* XXX */
  265 
  266   /*
  267    * set up pci bridge
  268    */
  269 
  270 #if !defined(MIDWAY_ENIONLY)
  271   if (sc->is_adaptec) {
  272     adp_get_macaddr(scp);
  273     sc->en_busreset = adp_busreset;
  274     adp_busreset(sc);
  275   }
  276 #endif
  277 
  278 #if !defined(MIDWAY_ADPONLY)
  279   if (!sc->is_adaptec) {
  280     eni_get_macaddr(scp);
  281     sc->en_busreset = NULL;
  282     pci_conf_write(config_id, EN_TONGA, (TONGA_SWAP_DMA|TONGA_SWAP_WORD));
  283   }
  284 #endif
  285 
  286   /*
  287    * done PCI specific stuff
  288    */
  289 
  290   en_attach(sc);
  291 
  292 }
  293 
  294 static void
  295 en_pci_shutdown(void *sc, int howto)
  296 {
  297     struct en_pci_softc *psc = (struct en_pci_softc *)sc;
  298     
  299     en_reset(&psc->esc);
  300     DELAY(10);
  301 }
  302 
  303 #if !defined(MIDWAY_ENIONLY)
  304 
  305 #if defined(__DragonFly__) || defined(sparc) || defined(__FreeBSD__)
  306 #define bus_space_read_1(t, h, o) \
  307                 ((void)t, (*(volatile u_int8_t *)((h) + (o))))
  308 #endif
  309 
  310 static void 
  311 adp_get_macaddr(struct en_pci_softc *scp)
  312 {
  313   struct en_softc * sc = (struct en_softc *)scp;
  314   int lcv;
  315 
  316   for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
  317     sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
  318                                         MID_ADPMACOFF + lcv);
  319 }
  320 
  321 #endif /* MIDWAY_ENIONLY */
  322 
  323 #if !defined(MIDWAY_ADPONLY)
  324 
  325 /*
  326  * Read station (MAC) address from serial EEPROM.
  327  * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
  328  */
  329 #define EN_PROM_MAGIC  0x0c
  330 #define EN_PROM_DATA   0x02
  331 #define EN_PROM_CLK    0x01
  332 #define EN_ESI         64
  333 
  334 static void 
  335 eni_get_macaddr(struct en_pci_softc *scp)
  336 {
  337   struct en_softc * sc = (struct en_softc *)scp;
  338   pcici_t id = scp->en_confid;
  339   int i, j, address;
  340   u_int32_t data, t_data;
  341   u_int8_t tmp;
  342   
  343   t_data = pci_conf_read(id, EN_TONGA) & 0xffffff00;
  344 
  345   data =  EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
  346   pci_conf_write(id, EN_TONGA, data);
  347 
  348   for (i = 0; i < sizeof(sc->macaddr); i ++){
  349     /* start operation */
  350     data |= EN_PROM_DATA ;
  351     pci_conf_write(id, EN_TONGA, data);
  352     data |= EN_PROM_CLK ;
  353     pci_conf_write(id, EN_TONGA, data);
  354     data &= ~EN_PROM_DATA ;
  355     pci_conf_write(id, EN_TONGA, data);
  356     data &= ~EN_PROM_CLK ;
  357     pci_conf_write(id, EN_TONGA, data);
  358     /* send address with serial line */
  359     address = ((i + EN_ESI) << 1) + 1;
  360     for ( j = 7 ; j >= 0 ; j --){
  361       data = (address >> j) & 1 ? data | EN_PROM_DATA :
  362       data & ~EN_PROM_DATA;
  363       pci_conf_write(id, EN_TONGA, data);
  364       data |= EN_PROM_CLK ;
  365       pci_conf_write(id, EN_TONGA, data);
  366       data &= ~EN_PROM_CLK ;
  367       pci_conf_write(id, EN_TONGA, data);
  368     }
  369     /* get ack */
  370     data |= EN_PROM_DATA ;
  371     pci_conf_write(id, EN_TONGA, data);
  372     data |= EN_PROM_CLK ;
  373     pci_conf_write(id, EN_TONGA, data);
  374     data = pci_conf_read(id, EN_TONGA);
  375     data &= ~EN_PROM_CLK ;
  376     pci_conf_write(id, EN_TONGA, data);
  377     data |= EN_PROM_DATA ;
  378     pci_conf_write(id, EN_TONGA, data);
  379 
  380     tmp = 0;
  381 
  382     for ( j = 7 ; j >= 0 ; j --){
  383       tmp <<= 1;
  384       data |= EN_PROM_DATA ;
  385       pci_conf_write(id, EN_TONGA, data);
  386       data |= EN_PROM_CLK ;
  387       pci_conf_write(id, EN_TONGA, data);
  388       data = pci_conf_read(id, EN_TONGA);
  389       if(data & EN_PROM_DATA) tmp |= 1;
  390       data &= ~EN_PROM_CLK ;
  391       pci_conf_write(id, EN_TONGA, data);
  392       data |= EN_PROM_DATA ;
  393       pci_conf_write(id, EN_TONGA, data);
  394     }
  395     /* get ack */
  396     data |= EN_PROM_DATA ;
  397     pci_conf_write(id, EN_TONGA, data);
  398     data |= EN_PROM_CLK ;
  399     pci_conf_write(id, EN_TONGA, data);
  400     data = pci_conf_read(id, EN_TONGA);
  401     data &= ~EN_PROM_CLK ;
  402     pci_conf_write(id, EN_TONGA, data);
  403     data |= EN_PROM_DATA ;
  404     pci_conf_write(id, EN_TONGA, data);
  405 
  406     sc->macaddr[i] = tmp;
  407   }
  408   /* stop operation */
  409   data &=  ~EN_PROM_DATA;
  410   pci_conf_write(id, EN_TONGA, data);
  411   data |=  EN_PROM_CLK;
  412   pci_conf_write(id, EN_TONGA, data);
  413   data |=  EN_PROM_DATA;
  414   pci_conf_write(id, EN_TONGA, data);
  415   pci_conf_write(id, EN_TONGA, t_data);
  416 }
  417 
  418 #endif /* !MIDWAY_ADPONLY */

Cache object: 1e2fc321753e14cc87d307ef274030cb


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