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/pci/if_hme_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_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp $   */
    2 
    3 /*
    4  * Copyright (c) 2000 Matthew R. Green
    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. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /*
   32  * PCI front-end device driver for the HME ethernet device.
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __KERNEL_RCSID(0, "$NetBSD: if_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp $");
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/syslog.h>
   41 #include <sys/device.h>
   42 #include <sys/malloc.h>
   43 #include <sys/socket.h>
   44 
   45 #include <net/if.h>
   46 #include <net/if_dl.h>
   47 #include <net/if_ether.h>
   48 #include <net/if_media.h>
   49 
   50 #include <dev/mii/mii.h>
   51 #include <dev/mii/miivar.h>
   52 
   53 #include <machine/intr.h>
   54 
   55 #include <dev/pci/pcivar.h>
   56 #include <dev/pci/pcireg.h>
   57 #include <dev/pci/pcidevs.h>
   58 
   59 #include <dev/ic/hmevar.h>
   60 #ifdef __sparc__
   61 #include <machine/promlib.h>
   62 #endif
   63 
   64 #ifndef HME_USE_LOCAL_MAC_ADDRESS
   65 #ifdef __sparc__
   66 #define HME_USE_LOCAL_MAC_ADDRESS       0       /* use system-wide address */
   67 #else
   68 #define HME_USE_LOCAL_MAC_ADDRESS       1
   69 #endif
   70 #endif
   71 
   72 struct hme_pci_softc {
   73         struct  hme_softc       hsc_hme;        /* HME device */
   74         bus_space_tag_t         hsc_memt;
   75         bus_space_handle_t      hsc_memh;
   76         void                    *hsc_ih;
   77 };
   78 
   79 int     hmematch_pci __P((struct device *, struct cfdata *, void *));
   80 void    hmeattach_pci __P((struct device *, struct device *, void *));
   81 
   82 CFATTACH_DECL(hme_pci, sizeof(struct hme_pci_softc),
   83     hmematch_pci, hmeattach_pci, NULL, NULL);
   84 
   85 int
   86 hmematch_pci(parent, cf, aux)
   87         struct device *parent;
   88         struct cfdata *cf;
   89         void *aux;
   90 {
   91         struct pci_attach_args *pa = aux;
   92 
   93         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && 
   94             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_HMENETWORK)
   95                 return (1);
   96 
   97         return (0);
   98 }
   99 
  100 void
  101 hmeattach_pci(parent, self, aux)
  102         struct device *parent, *self;
  103         void *aux;
  104 {
  105         struct pci_attach_args *pa = aux;
  106         struct hme_pci_softc *hsc = (void *)self;
  107         struct hme_softc *sc = &hsc->hsc_hme;
  108         pci_intr_handle_t ih;
  109         pcireg_t csr;
  110         const char *intrstr;
  111         int type;
  112 #if HME_USE_LOCAL_MAC_ADDRESS
  113         struct pci_attach_args  ebus_pa;
  114         pcireg_t                ebus_cl, ebus_id;
  115         u_int8_t                *enaddr;
  116         bus_space_tag_t         romt;
  117         bus_space_handle_t      romh;
  118         bus_size_t              romsize;
  119         u_int8_t                buf[32];
  120         int                     dataoff, vpdoff;
  121         struct pci_vpd          *vpd;
  122         static const u_int8_t promhdr[] = { 0x55, 0xaa };
  123 #define PROMHDR_PTR_DATA        0x18
  124         static const u_int8_t promdat[] = {
  125                 0x50, 0x43, 0x49, 0x52,         /* "PCIR" */
  126                 PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
  127                 PCI_PRODUCT_SUN_HMENETWORK & 0xff,
  128                 PCI_PRODUCT_SUN_HMENETWORK >> 8
  129         };
  130 #define PROMDATA_PTR_VPD        0x08
  131 #define PROMDATA_DATA2          0x0a            
  132         static const u_int8_t promdat2[] = {
  133                 0x18, 0x00,                     /* structure length */
  134                 0x00,                           /* structure revision */
  135                 0x00,                           /* interface revision */
  136                 PCI_SUBCLASS_NETWORK_ETHERNET,  /* subclass code */
  137                 PCI_CLASS_NETWORK               /* class code */
  138         };
  139 #endif  /* HME_USE_LOCAL_MAC_ADDRESS */
  140 
  141         printf(": Sun Happy Meal Ethernet, rev. %d\n",
  142             PCI_REVISION(pa->pa_class));
  143 
  144         /*
  145          * enable io/memory-space accesses.  this is kinda of gross; but
  146          # the hme comes up with neither IO space enabled, or memory space.
  147          */
  148         if (pa->pa_memt)
  149                 pa->pa_flags |= PCI_FLAGS_MEM_ENABLED;
  150         if (pa->pa_iot)
  151                 pa->pa_flags |= PCI_FLAGS_IO_ENABLED;
  152         csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
  153         if (pa->pa_memt) {
  154                 type = PCI_MAPREG_TYPE_MEM;
  155                 csr |= PCI_COMMAND_MEM_ENABLE;
  156                 sc->sc_bustag = pa->pa_memt;
  157         } else {
  158                 type = PCI_MAPREG_TYPE_IO;
  159                 csr |= PCI_COMMAND_IO_ENABLE;
  160                 sc->sc_bustag = pa->pa_iot;
  161         }
  162         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
  163             csr | PCI_COMMAND_MEM_ENABLE);
  164 
  165         sc->sc_dmatag = pa->pa_dmat;
  166 
  167         sc->sc_pci = 1; /* XXXXX should all be done in bus_dma. */
  168         /*
  169          * Map five register banks:
  170          *
  171          *      bank 0: HME SEB registers:      +0x0000
  172          *      bank 1: HME ETX registers:      +0x2000
  173          *      bank 2: HME ERX registers:      +0x4000
  174          *      bank 3: HME MAC registers:      +0x6000
  175          *      bank 4: HME MIF registers:      +0x7000
  176          *
  177          */
  178 
  179 #define PCI_HME_BASEADDR        0x10
  180         if (pci_mapreg_map(pa, PCI_HME_BASEADDR, type, 0,
  181             &hsc->hsc_memt, &hsc->hsc_memh, NULL, NULL) != 0)
  182         {
  183                 printf("%s: unable to map device registers\n",
  184                     sc->sc_dev.dv_xname);
  185                 return;
  186         }
  187         sc->sc_seb = hsc->hsc_memh;
  188         if (bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x2000,
  189             0x1000, &sc->sc_etx)) {
  190                 printf("%s: unable to subregion ETX registers\n",
  191                     sc->sc_dev.dv_xname);
  192                 return;
  193         }
  194         if (bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x4000,
  195             0x1000, &sc->sc_erx)) {
  196                 printf("%s: unable to subregion ERX registers\n",
  197                     sc->sc_dev.dv_xname);
  198                 return;
  199         }
  200         if (bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x6000,
  201             0x1000, &sc->sc_mac)) {
  202                 printf("%s: unable to subregion MAC registers\n",
  203                     sc->sc_dev.dv_xname);
  204                 return;
  205         }
  206         if (bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x7000,
  207             0x1000, &sc->sc_mif)) {
  208                 printf("%s: unable to subregion MIF registers\n",
  209                     sc->sc_dev.dv_xname);
  210                 return;
  211         }
  212 
  213 #if HME_USE_LOCAL_MAC_ADDRESS
  214         /*
  215          * Dig out VPD (vital product data) and acquire Ethernet address.
  216          * The VPD of hme resides in the Boot PROM (PCI FCode) attached
  217          * to the EBus interface.
  218          */
  219         /*
  220          * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later)
  221          * chapter 2 describes the data structure.
  222          */
  223 
  224         enaddr = NULL;
  225 
  226         /* get a PCI tag for the EBus bridge (function 0 of the same device) */
  227         ebus_pa = *pa;
  228         ebus_pa.pa_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
  229 
  230         ebus_cl = pci_conf_read(ebus_pa.pa_pc, ebus_pa.pa_tag, PCI_CLASS_REG);
  231         ebus_id = pci_conf_read(ebus_pa.pa_pc, ebus_pa.pa_tag, PCI_ID_REG);
  232 
  233 #define PCI_EBUS2_BOOTROM       0x10
  234         if (PCI_CLASS(ebus_cl) == PCI_CLASS_BRIDGE &&
  235             PCI_PRODUCT(ebus_id) == PCI_PRODUCT_SUN_EBUS &&
  236             pci_mapreg_map(&ebus_pa, PCI_EBUS2_BOOTROM, PCI_MAPREG_TYPE_MEM,
  237                 BUS_SPACE_MAP_CACHEABLE | BUS_SPACE_MAP_PREFETCHABLE,
  238                 &romt, &romh, 0, &romsize) == 0) {
  239 
  240                 /* read PCI Expansion PROM Header */
  241                 bus_space_read_region_1(romt, romh, 0, buf, sizeof buf);
  242                 if (memcmp(buf, promhdr, sizeof promhdr) == 0 &&
  243                     (dataoff = (buf[PROMHDR_PTR_DATA] |
  244                         (buf[PROMHDR_PTR_DATA + 1] << 8))) >= 0x1c) {
  245 
  246                         /* read PCI Expansion PROM Data */
  247                         bus_space_read_region_1(romt, romh, dataoff,
  248                             buf, sizeof buf);
  249                         if (memcmp(buf, promdat, sizeof promdat) == 0 &&
  250                             memcmp(buf + PROMDATA_DATA2, promdat2,
  251                                 sizeof promdat2) == 0 &&
  252                             (vpdoff = (buf[PROMDATA_PTR_VPD] |
  253                                 (buf[PROMDATA_PTR_VPD + 1] << 8))) >= 0x1c) {
  254 
  255                                 /*
  256                                  * The VPD of hme is not in PCI 2.2 standard
  257                                  * format.  The length in the resource header
  258                                  * is in big endian, and resources are not
  259                                  * properly terminated (only one resource
  260                                  * and no end tag).
  261                                  */
  262                                 /* read PCI VPD */
  263                                 bus_space_read_region_1(romt, romh,
  264                                     vpdoff, buf, sizeof buf);
  265                                 vpd = (void *)(buf + 3);
  266                                 if (PCI_VPDRES_ISLARGE(buf[0]) &&
  267                                     PCI_VPDRES_LARGE_NAME(buf[0])
  268                                         == PCI_VPDRES_TYPE_VPD &&
  269                                     /* buf[1] == 0 && buf[2] == 9 && */ /*len*/
  270                                     vpd->vpd_key0 == 0x4e /* N */ &&
  271                                     vpd->vpd_key1 == 0x41 /* A */ &&
  272                                     vpd->vpd_len == ETHER_ADDR_LEN) {
  273                                         /*
  274                                          * Ethernet address found
  275                                          */
  276                                         enaddr = buf + 6;
  277                                 }
  278                         }
  279                 }
  280                 bus_space_unmap(romt, romh, romsize);
  281         }
  282 
  283         if (enaddr)
  284                 memcpy(sc->sc_enaddr, enaddr, ETHER_ADDR_LEN);
  285         else
  286 #endif  /* HME_USE_LOCAL_MAC_ADDRESS */
  287 #ifdef __sparc__
  288                 prom_getether(PCITAG_NODE(pa->pa_tag), sc->sc_enaddr);
  289 #else
  290                 printf("%s: no Ethernet address found\n", sc->sc_dev.dv_xname);
  291 #endif
  292 
  293         /*
  294          * Map and establish our interrupt.
  295          */
  296         if (pci_intr_map(pa, &ih) != 0) {
  297                 printf("%s: unable to map interrupt\n", sc->sc_dev.dv_xname);
  298                 return;
  299         }       
  300         intrstr = pci_intr_string(pa->pa_pc, ih);
  301         hsc->hsc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, hme_intr, sc);
  302         if (hsc->hsc_ih == NULL) {
  303                 printf("%s: unable to establish interrupt",
  304                     sc->sc_dev.dv_xname);
  305                 if (intrstr != NULL)
  306                         printf(" at %s", intrstr);
  307                 printf("\n");
  308                 return;
  309         }
  310         printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
  311 
  312         sc->sc_burst = 16;      /* XXX */
  313 
  314         /* Finish off the attach. */
  315         hme_config(sc);
  316 }

Cache object: 3fecf79fcc43aa9cc217df256d45b78a


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