root/dev/pci/if_gem_pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gem_match_pci
  2. gem_pci_enaddr
  3. gem_attach_pci

    1 /*      $OpenBSD: if_gem_pci.c,v 1.28 2007/04/19 19:00:01 kettenis Exp $        */
    2 /*      $NetBSD: if_gem_pci.c,v 1.1 2001/09/16 00:11:42 eeh Exp $ */
    3 
    4 /*
    5  *
    6  * Copyright (C) 2001 Eduardo Horvath.
    7  * All rights reserved.
    8  *
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  */
   32 
   33 /*
   34  * PCI bindings for Sun GEM ethernet controllers.
   35  */
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/malloc.h>
   40 #include <sys/kernel.h>
   41 #include <sys/socket.h>
   42 #include <sys/errno.h>
   43 #include <sys/device.h>
   44 
   45 #include <machine/endian.h>
   46 
   47 #include <net/if.h>
   48 #include <net/if_dl.h>
   49 #include <net/if_media.h>
   50 
   51 #ifdef INET
   52 #include <netinet/in.h>
   53 #include <netinet/if_ether.h>
   54 #endif
   55 
   56 #if NBPFILTER > 0
   57 #include <net/bpf.h>
   58 #endif
   59 
   60 #include <machine/bus.h>
   61 #include <machine/intr.h>
   62 
   63 #ifdef __sparc64__
   64 #include <dev/ofw/openfirm.h>
   65 #endif
   66 
   67 #include <dev/mii/mii.h>
   68 #include <dev/mii/miivar.h>
   69 #include <dev/mii/mii_bitbang.h>
   70 
   71 #include <dev/ic/gemreg.h>
   72 #include <dev/ic/gemvar.h>
   73 
   74 #include <dev/pci/pcivar.h>
   75 #include <dev/pci/pcireg.h>
   76 #include <dev/pci/pcidevs.h>
   77 
   78 struct gem_pci_softc {
   79         struct  gem_softc       gsc_gem;        /* GEM device */
   80         bus_space_tag_t         gsc_memt;
   81         bus_space_handle_t      gsc_memh;
   82         void                    *gsc_ih;
   83 };
   84 
   85 int     gem_match_pci(struct device *, void *, void *);
   86 void    gem_attach_pci(struct device *, struct device *, void *);
   87 int     gem_pci_enaddr(struct gem_softc *, struct pci_attach_args *);
   88 
   89 struct cfattach gem_pci_ca = {
   90         sizeof(struct gem_pci_softc), gem_match_pci, gem_attach_pci
   91 };
   92 
   93 /*
   94  * Attach routines need to be split out to different bus-specific files.
   95  */
   96 
   97 const struct pci_matchid gem_pci_devices[] = {
   98         { PCI_VENDOR_SUN, PCI_PRODUCT_SUN_ERINETWORK },
   99         { PCI_VENDOR_SUN, PCI_PRODUCT_SUN_GEMNETWORK },
  100         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_INTREPID2_GMAC },
  101         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_K2_GMAC },
  102         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_PANGEA_GMAC },
  103         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_SHASTA_GMAC },
  104         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTHGMAC },
  105         { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_UNINORTH2GMAC },
  106 };
  107 
  108 int
  109 gem_match_pci(struct device *parent, void *cf, void *aux)
  110 {
  111         return (pci_matchbyid((struct pci_attach_args *)aux, gem_pci_devices,
  112             sizeof(gem_pci_devices)/sizeof(gem_pci_devices[0])));
  113 }
  114 
  115 #define PROMHDR_PTR_DATA        0x18
  116 #define PROMDATA_PTR_VPD        0x08
  117 #define PROMDATA_DATA2          0x0a
  118 
  119 static const u_int8_t gem_promhdr[] = { 0x55, 0xaa };
  120 static const u_int8_t gem_promdat[] = {
  121         'P', 'C', 'I', 'R',
  122         PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
  123         PCI_PRODUCT_SUN_GEMNETWORK & 0xff, PCI_PRODUCT_SUN_GEMNETWORK >> 8
  124 };
  125 
  126 static const u_int8_t gem_promdat2[] = {
  127         0x18, 0x00,                     /* structure length */
  128         0x00,                           /* structure revision */
  129         0x00,                           /* interface revision */
  130         PCI_SUBCLASS_NETWORK_ETHERNET,  /* subclass code */
  131         PCI_CLASS_NETWORK               /* class code */
  132 };
  133 
  134 int
  135 gem_pci_enaddr(struct gem_softc *sc, struct pci_attach_args *pa)
  136 {
  137         struct pci_vpd *vpd;
  138         bus_space_handle_t romh;
  139         bus_space_tag_t romt;
  140         bus_size_t romsize;
  141         u_int8_t buf[32];
  142         pcireg_t address, mask;
  143         int dataoff, vpdoff;
  144         int rv = -1;
  145 
  146         address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
  147         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe);
  148         mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
  149         address |= PCI_ROM_ENABLE;
  150         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
  151 
  152         romt = pa->pa_memt;
  153         romsize = PCI_ROM_SIZE(mask);
  154         if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) {
  155                 romsize = 0;
  156                 goto fail;
  157         }
  158 
  159         bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
  160         if (bcmp(buf, gem_promhdr, sizeof(gem_promhdr)))
  161                 goto fail;
  162 
  163         dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8);
  164         if (dataoff < 0x1c)
  165                 goto fail;
  166 
  167         bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
  168         if (bcmp(buf, gem_promdat, sizeof(gem_promdat)) ||
  169             bcmp(buf + PROMDATA_DATA2, gem_promdat2, sizeof(gem_promdat2)))
  170                 goto fail;
  171 
  172         vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8);
  173         if (vpdoff < 0x1c)
  174                 goto fail;
  175 
  176         bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
  177 
  178         /*
  179          * The VPD of gem is not in PCI 2.2 standard format.  The length
  180          * in the resource header is in big endian.
  181          */
  182         vpd = (struct pci_vpd *)(buf + 3);
  183         if (!PCI_VPDRES_ISLARGE(buf[0]) ||
  184             PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD)
  185                 goto fail;
  186         if (vpd->vpd_key0 != 'N' || vpd->vpd_key1 != 'A')
  187                 goto fail;
  188 
  189         bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
  190         rv = 0;
  191 
  192  fail:
  193         if (romsize != 0)
  194                 bus_space_unmap(romt, romh, romsize);
  195 
  196         address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
  197         address &= ~PCI_ROM_ENABLE;
  198         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
  199 
  200         return (rv);
  201 }
  202 
  203 void
  204 gem_attach_pci(struct device *parent, struct device *self, void *aux)
  205 {
  206         struct pci_attach_args *pa = aux;
  207         struct gem_pci_softc *gsc = (void *)self;
  208         struct gem_softc *sc = &gsc->gsc_gem;
  209         pci_intr_handle_t ih;
  210 #ifdef __sparc64__
  211         /* XXX the following declarations should be elsewhere */
  212         extern void myetheraddr(u_char *);
  213 #endif
  214         const char *intrstr = NULL;
  215         bus_size_t size;
  216         int type, gotenaddr = 0;
  217 
  218         if (pa->pa_memt) {
  219                 type = PCI_MAPREG_TYPE_MEM;
  220                 sc->sc_bustag = pa->pa_memt;
  221         } else {
  222                 type = PCI_MAPREG_TYPE_IO;
  223                 sc->sc_bustag = pa->pa_iot;
  224         }
  225 
  226         sc->sc_dmatag = pa->pa_dmat;
  227 
  228         sc->sc_pci = 1; /* XXXXX should all be done in bus_dma. */
  229 
  230         if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)
  231                 sc->sc_variant = GEM_SUN_GEM;
  232         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK)
  233                 sc->sc_variant = GEM_SUN_ERI;
  234         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC)
  235                 sc->sc_variant = GEM_APPLE_GMAC;
  236         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_PANGEA_GMAC)
  237                 sc->sc_variant = GEM_APPLE_GMAC;
  238         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC)
  239                 sc->sc_variant = GEM_APPLE_GMAC;
  240         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_UNINORTHGMAC)
  241                 sc->sc_variant = GEM_APPLE_GMAC;
  242         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_UNINORTH2GMAC)
  243                 sc->sc_variant = GEM_APPLE_GMAC;
  244         else if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC)
  245                 sc->sc_variant = GEM_APPLE_K2_GMAC;
  246 
  247 #define PCI_GEM_BASEADDR        0x10
  248         if (pci_mapreg_map(pa, PCI_GEM_BASEADDR, type, 0,
  249             &gsc->gsc_memt, &gsc->gsc_memh, NULL, &size, 0) != 0) {
  250                 printf(": could not map registers\n");
  251                 return;
  252         }
  253 
  254         sc->sc_bustag = gsc->gsc_memt;
  255         sc->sc_h1 = gsc->gsc_memh;
  256 
  257         if (bus_space_subregion(sc->sc_bustag, sc->sc_h1,
  258             GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) {
  259                 printf(": unable to create bank 2 subregion\n");
  260                 bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
  261                 return;
  262         }
  263 
  264         if (gem_pci_enaddr(sc, pa) == 0)
  265                 gotenaddr = 1;
  266 
  267 #ifdef __sparc64__
  268         if (!gotenaddr) {
  269                 if (OF_getprop(PCITAG_NODE(pa->pa_tag), "local-mac-address",
  270                     sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN) <= 0)
  271                         myetheraddr(sc->sc_arpcom.ac_enaddr);
  272                 gotenaddr = 1;
  273         }
  274 #endif
  275 #ifdef __powerpc__
  276         if (!gotenaddr) {
  277                 pci_ether_hw_addr(pa->pa_pc, sc->sc_arpcom.ac_enaddr);
  278                 gotenaddr = 1;
  279         }
  280 #endif
  281 
  282         sc->sc_burst = 16;      /* XXX */
  283 
  284         if (pci_intr_map(pa, &ih) != 0) {
  285                 printf(": couldn't map interrupt\n");
  286                 bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
  287                 return;
  288         }
  289         intrstr = pci_intr_string(pa->pa_pc, ih);
  290         gsc->gsc_ih = pci_intr_establish(pa->pa_pc,
  291             ih, IPL_NET, gem_intr, sc, self->dv_xname);
  292         if (gsc->gsc_ih == NULL) {
  293                 printf(": couldn't establish interrupt");
  294                 if (intrstr != NULL)
  295                         printf(" at %s", intrstr);
  296                 printf("\n");
  297                 bus_space_unmap(gsc->gsc_memt, gsc->gsc_memh, size);
  298                 return;
  299         }
  300 
  301         printf(": %s", intrstr);
  302 
  303         /*
  304          * call the main configure
  305          */
  306         gem_config(sc);
  307 }

/* [<][>][^][v][top][bottom][index][help] */