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/hme/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 /*-
    2  * Copyright (c) 2000 Matthew R. Green
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. The name of the author may not be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  *      from: NetBSD: if_hme_pci.c,v 1.14 2004/03/17 08:58:23 martin Exp
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 /*
   35  * PCI front-end device driver for the HME ethernet device.
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/module.h>
   43 #include <sys/resource.h>
   44 #include <sys/socket.h>
   45 
   46 #include <machine/bus.h>
   47 #if defined(__powerpc__) || defined(__sparc64__)
   48 #include <dev/ofw/openfirm.h>
   49 #include <machine/ofw_machdep.h>
   50 #endif
   51 #include <machine/resource.h>
   52 
   53 #include <sys/rman.h>
   54 
   55 #include <net/ethernet.h>
   56 #include <net/if.h>
   57 #include <net/if_arp.h>
   58 #include <net/if_dl.h>
   59 #include <net/if_media.h>
   60 
   61 #include <dev/mii/mii.h>
   62 #include <dev/mii/miivar.h>
   63 
   64 #include <dev/pci/pcivar.h>
   65 #include <dev/pci/pcireg.h>
   66 
   67 #include <dev/hme/if_hmereg.h>
   68 #include <dev/hme/if_hmevar.h>
   69 
   70 #include "miibus_if.h"
   71 
   72 struct hme_pci_softc {
   73         struct  hme_softc       hsc_hme;        /* HME device */
   74         struct  resource        *hsc_sres;
   75         int                     hsc_srid;
   76         struct  resource        *hsc_ires;
   77         int                     hsc_irid;
   78         bus_space_tag_t         hsc_memt;
   79         bus_space_handle_t      hsc_memh;
   80         void                    *hsc_ih;
   81 };
   82 
   83 static int hme_pci_probe(device_t);
   84 static int hme_pci_attach(device_t);
   85 static int hme_pci_detach(device_t);
   86 static int hme_pci_suspend(device_t);
   87 static int hme_pci_resume(device_t);
   88 
   89 static device_method_t hme_pci_methods[] = {
   90         /* Device interface */
   91         DEVMETHOD(device_probe,         hme_pci_probe),
   92         DEVMETHOD(device_attach,        hme_pci_attach),
   93         DEVMETHOD(device_detach,        hme_pci_detach),
   94         DEVMETHOD(device_suspend,       hme_pci_suspend),
   95         DEVMETHOD(device_resume,        hme_pci_resume),
   96         /* Can just use the suspend method here. */
   97         DEVMETHOD(device_shutdown,      hme_pci_suspend),
   98 
   99         /* bus interface */
  100         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  101         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
  102 
  103         /* MII interface */
  104         DEVMETHOD(miibus_readreg,       hme_mii_readreg),
  105         DEVMETHOD(miibus_writereg,      hme_mii_writereg),
  106         DEVMETHOD(miibus_statchg,       hme_mii_statchg),
  107 
  108         { 0, 0 }
  109 };
  110 
  111 static driver_t hme_pci_driver = {
  112         "hme",
  113         hme_pci_methods,
  114         sizeof(struct hme_pci_softc)
  115 };
  116 
  117 DRIVER_MODULE(hme, pci, hme_pci_driver, hme_devclass, 0, 0);
  118 MODULE_DEPEND(hme, pci, 1, 1, 1);
  119 MODULE_DEPEND(hme, ether, 1, 1, 1);
  120 
  121 #define PCI_VENDOR_SUN                  0x108e
  122 #define PCI_PRODUCT_SUN_EBUS            0x1000
  123 #define PCI_PRODUCT_SUN_HMENETWORK      0x1001
  124 
  125 int
  126 hme_pci_probe(device_t dev)
  127 {
  128 
  129         if (pci_get_vendor(dev) == PCI_VENDOR_SUN &&
  130             pci_get_device(dev) ==  PCI_PRODUCT_SUN_HMENETWORK) {
  131                 device_set_desc(dev, "Sun HME 10/100 Ethernet");
  132                 return (BUS_PROBE_DEFAULT);
  133         }
  134         return (ENXIO);
  135 }
  136 
  137 int
  138 hme_pci_attach(device_t dev)
  139 {
  140         struct hme_pci_softc *hsc = device_get_softc(dev);
  141         struct hme_softc *sc = &hsc->hsc_hme;
  142         int error = 0;
  143 #if !(defined(__powerpc__) || defined(__sparc64__))
  144         device_t *children, ebus_dev;
  145         struct resource *ebus_rres;
  146         bus_space_handle_t romh;
  147         bus_space_tag_t romt;
  148         int dataoff, ebus_rrid, slot, vpdoff;
  149         int i, nchildren;
  150         uint8_t buf[32];
  151         static const uint8_t promhdr[] = { 0x55, 0xaa };
  152 #define PROMHDR_PTR_DATA        0x18
  153         static const uint8_t promdat[] = {
  154                 0x50, 0x43, 0x49, 0x52, /* "PCIR" */
  155                 PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8,
  156                 PCI_PRODUCT_SUN_HMENETWORK & 0xff,
  157                 PCI_PRODUCT_SUN_HMENETWORK >> 8
  158         };
  159 #define PROMDATA_PTR_VPD        0x08
  160         struct pci_vpd {
  161                  uint8_t        vpd_key0;
  162                  uint8_t        vpd_key1;
  163                  uint8_t        vpd_len;
  164         } *vpd;
  165 #define PCI_VPDRES_ISLARGE(x)                   ((x) & 0x80)
  166 #define PCI_VPDRES_LARGE_NAME(x)                ((x) & 0x7f)
  167 #define PCI_VPDRES_TYPE_VPD                     0x10    /* large */
  168 #endif
  169 
  170         pci_enable_busmaster(dev);
  171         /*
  172          * Some Sun HMEs do have their intpin register bogusly set to 0,
  173          * although it should be 1. correct that.
  174          */
  175         if (pci_get_intpin(dev) == 0)
  176                 pci_set_intpin(dev, 1);
  177 
  178         sc->sc_pci = 1;
  179         sc->sc_dev = dev;
  180         mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
  181             MTX_DEF);
  182 
  183         /*
  184          * Map five register banks:
  185          *
  186          *      bank 0: HME SEB registers:      +0x0000
  187          *      bank 1: HME ETX registers:      +0x2000
  188          *      bank 2: HME ERX registers:      +0x4000
  189          *      bank 3: HME MAC registers:      +0x6000
  190          *      bank 4: HME MIF registers:      +0x7000
  191          *
  192          */
  193         hsc->hsc_srid = PCI_HME_BASEADDR;
  194         hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 
  195             &hsc->hsc_srid, RF_ACTIVE);
  196         if (hsc->hsc_sres == NULL) {
  197                 device_printf(dev, "could not map device registers\n");
  198                 error = ENXIO;
  199                 goto fail_mtx;
  200         }
  201         hsc->hsc_irid = 0;
  202         hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 
  203             &hsc->hsc_irid, RF_SHAREABLE | RF_ACTIVE);
  204         if (hsc->hsc_ires == NULL) {
  205                 device_printf(dev, "could not allocate interrupt\n");
  206                 error = ENXIO;
  207                 goto fail_sres;
  208         }
  209         hsc->hsc_memt = rman_get_bustag(hsc->hsc_sres);
  210         hsc->hsc_memh = rman_get_bushandle(hsc->hsc_sres);
  211         sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift =
  212             hsc->hsc_memt;
  213         bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x0000, 0x1000,
  214             &sc->sc_sebh);
  215         bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x2000, 0x1000,
  216             &sc->sc_etxh);
  217         bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x4000, 0x1000,
  218             &sc->sc_erxh);
  219         bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x6000, 0x1000,
  220             &sc->sc_mach);
  221         bus_space_subregion(hsc->hsc_memt, hsc->hsc_memh, 0x7000, 0x1000,
  222             &sc->sc_mifh);
  223 
  224 #if defined(__powerpc__) || defined(__sparc64__)
  225         OF_getetheraddr(dev, sc->sc_enaddr);
  226 #else
  227         /*
  228          * Dig out VPD (vital product data) and read NA (network address).
  229          *
  230          * The PCI HME is a PCIO chip, which is composed of two functions:
  231          *      function 0: PCI-EBus2 bridge, and
  232          *      function 1: HappyMeal Ethernet controller.
  233          *
  234          * The VPD of HME resides in the Boot PROM (PCI FCode) attached
  235          * to the EBus bridge and can't be accessed via the PCI capability
  236          * pointer.
  237          * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later)
  238          * chapter 2 describes the data structure.
  239          *
  240          * We don't have a MI EBus driver since no EBus device exists
  241          * (besides the FCode PROM) on add-on HME boards. The ``no driver
  242          * attached'' message for function 0 therefore is what is expected.
  243          */
  244 
  245         /* Search accompanying EBus bridge. */
  246         slot = pci_get_slot(dev);
  247         if (device_get_children(device_get_parent(dev), &children,
  248             &nchildren) != 0) {
  249                 device_printf(dev, "could not get children\n");
  250                 error = ENXIO;
  251                 goto fail_sres;
  252         }
  253         ebus_dev = NULL;
  254         for (i = 0; i < nchildren; i++) {
  255                 if (pci_get_class(children[i]) == PCIC_BRIDGE &&
  256                     pci_get_vendor(children[i]) == PCI_VENDOR_SUN &&
  257                     pci_get_device(children[i]) ==  PCI_PRODUCT_SUN_EBUS &&
  258                     pci_get_slot(children[i]) == slot) {
  259                         ebus_dev = children[i];
  260                         break;
  261                 }
  262         }
  263         if (ebus_dev == NULL) {
  264                 device_printf(dev, "could not find EBus bridge\n");
  265                 error = ENXIO;
  266                 goto fail_children;
  267         }
  268 
  269         /* Map EBus bridge PROM registers. */
  270 #define PCI_EBUS2_BOOTROM       0x10
  271         ebus_rrid = PCI_EBUS2_BOOTROM;
  272         if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY,
  273             &ebus_rrid, RF_ACTIVE)) == NULL) {
  274                 device_printf(dev, "could not map PROM registers\n");
  275                 error = ENXIO;
  276                 goto fail_children;
  277         }
  278         romt = rman_get_bustag(ebus_rres);
  279         romh = rman_get_bushandle(ebus_rres);
  280 
  281         /* Read PCI expansion PROM header. */
  282         bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf));
  283         if (memcmp(buf, promhdr, sizeof(promhdr)) != 0 ||
  284             (dataoff = (buf[PROMHDR_PTR_DATA] |
  285             (buf[PROMHDR_PTR_DATA + 1] << 8))) < 0x1c) {
  286                 device_printf(dev, "unexpected PCI expansion PROM header\n");
  287                 error = ENXIO;
  288                 goto fail_rres;
  289         }
  290 
  291         /* Read PCI expansion PROM data. */
  292         bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf));
  293         if (memcmp(buf, promdat, sizeof(promdat)) != 0 ||
  294             (vpdoff = (buf[PROMDATA_PTR_VPD] |
  295             (buf[PROMDATA_PTR_VPD + 1] << 8))) < 0x1c) {
  296                 device_printf(dev, "unexpected PCI expansion PROM data\n");
  297                 error = ENXIO;
  298                 goto fail_rres;
  299         }
  300 
  301         /*
  302          * Read PCI VPD.
  303          * SUNW,hme cards have a single large resource VPD-R tag
  304          * containing one NA. SUNW,qfe cards have four large resource
  305          * VPD-R tags containing one NA each (all four HME chips share
  306          * the same PROM).
  307          * The VPD used on both cards is not in PCI 2.2 standard format
  308          * however. The length in the resource header is in big endian
  309          * and the end tag is non-standard (0x79) and followed by an
  310          * all-zero "checksum" byte. Sun calls this a "Fresh Choice
  311          * Ethernet" VPD...
  312          */
  313         /* Look at the end tag to determine whether this is a VPD with 4 NAs. */
  314         if (bus_space_read_1(romt, romh,
  315             vpdoff + 3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN) != 0x79 &&
  316             bus_space_read_1(romt, romh,
  317             vpdoff + 4 * (3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN)) == 0x79)
  318                 /* Use the Nth NA for the Nth HME on this SUNW,qfe. */
  319                 vpdoff += slot * (3 + sizeof(struct pci_vpd) + ETHER_ADDR_LEN);
  320         bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf));
  321         vpd = (void *)(buf + 3);
  322         if (PCI_VPDRES_ISLARGE(buf[0]) == 0 ||
  323             PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD ||
  324             (buf[1] << 8 | buf[2]) != sizeof(struct pci_vpd) + ETHER_ADDR_LEN ||
  325             vpd->vpd_key0 != 0x4e /* N */ ||
  326             vpd->vpd_key1 != 0x41 /* A */ ||
  327             vpd->vpd_len != ETHER_ADDR_LEN) {
  328                 device_printf(dev, "unexpected PCI VPD\n");
  329                 error = ENXIO;
  330                 goto fail_rres;
  331         }
  332         bcopy(buf + 3 + sizeof(struct pci_vpd), sc->sc_enaddr,
  333             ETHER_ADDR_LEN);
  334 
  335 fail_rres:
  336         bus_release_resource(ebus_dev, SYS_RES_MEMORY, ebus_rrid, ebus_rres);
  337 fail_children:
  338         free(children, M_TEMP);
  339         if (error != 0)
  340                 goto fail_sres;
  341 #endif
  342 
  343         sc->sc_burst = 64;      /* XXX */
  344 
  345         /*
  346          * call the main configure
  347          */
  348         if ((error = hme_config(sc)) != 0) {
  349                 device_printf(dev, "could not be configured\n");
  350                 goto fail_ires;
  351         }
  352 
  353         if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET |
  354             INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) {
  355                 device_printf(dev, "couldn't establish interrupt\n");
  356                 hme_detach(sc);
  357                 goto fail_ires;
  358         }
  359         return (0);
  360 
  361 fail_ires:
  362         bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires);
  363 fail_sres:
  364         bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres);
  365 fail_mtx:
  366         mtx_destroy(&sc->sc_lock);
  367         return (error);
  368 }
  369 
  370 static int
  371 hme_pci_detach(device_t dev)
  372 {
  373         struct hme_pci_softc *hsc = device_get_softc(dev);
  374         struct hme_softc *sc = &hsc->hsc_hme;
  375 
  376         bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih);
  377         hme_detach(sc);
  378         bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires);
  379         bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_srid, hsc->hsc_sres);
  380         mtx_destroy(&sc->sc_lock);
  381         return (0);
  382 }
  383 
  384 static int
  385 hme_pci_suspend(device_t dev)
  386 {
  387         struct hme_pci_softc *hsc = device_get_softc(dev);
  388         struct hme_softc *sc = &hsc->hsc_hme;
  389 
  390         hme_suspend(sc);
  391         return (0);
  392 }
  393 
  394 static int
  395 hme_pci_resume(device_t dev)
  396 {
  397         struct hme_pci_softc *hsc = device_get_softc(dev);
  398         struct hme_softc *sc = &hsc->hsc_hme;
  399 
  400         hme_resume(sc);
  401         return (0);
  402 }

Cache object: 440d3d7dfa615d0fd90a57247c76cd45


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