root/dev/pci/if_hme_pci.c

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

DEFINITIONS

This source file includes following definitions.
  1. hmematch_pci
  2. hme_pci_enaddr
  3. hmeattach_pci

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

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