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_wi_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_wi_pci.c,v 1.31 2004/03/28 09:44:59 nakayama Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Hideaki Imaizumi <hiddy@sfc.wide.ad.jp>
    9  * and Ichiro FUKUHARA (ichiro@ichiro.org).
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * PCI bus front-end for the Intersil PCI WaveLan.
   42  * Works with Prism2.5 Mini-PCI wavelan.
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __KERNEL_RCSID(0, "$NetBSD: if_wi_pci.c,v 1.31 2004/03/28 09:44:59 nakayama Exp $");
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/syslog.h>
   52 #include <sys/socket.h>
   53 #include <sys/device.h>
   54 #include <sys/callout.h>
   55 
   56 #include <net/if.h>
   57 #include <net/if_ether.h>
   58 #include <net/if_media.h>
   59 
   60 #include <net80211/ieee80211_var.h>
   61 #include <net80211/ieee80211_compat.h>
   62 #include <net80211/ieee80211_radiotap.h>
   63 #include <net80211/ieee80211_rssadapt.h>
   64 
   65 #include <machine/bus.h>
   66 #include <machine/intr.h>
   67 
   68 #include <dev/pci/pcireg.h>
   69 #include <dev/pci/pcivar.h>
   70 #include <dev/pci/pcidevs.h>
   71 
   72 #include <dev/ic/wi_ieee.h>
   73 #include <dev/ic/wireg.h>
   74 #include <dev/ic/wivar.h>
   75 
   76 #define WI_PCI_CBMA             0x10    /* Configuration Base Memory Address */
   77 #define WI_PCI_PLX_LOMEM        0x10    /* PLX chip membase */
   78 #define WI_PCI_PLX_LOIO         0x14    /* PLX chip iobase */
   79 #define WI_PCI_LOMEM            0x18    /* ISA membase */
   80 #define WI_PCI_LOIO             0x1C    /* ISA iobase */
   81 
   82 #define CHIP_PLX_OTHER          0x01
   83 #define CHIP_PLX_9052           0x02
   84 #define CHIP_TMD_7160           0x03
   85 
   86 #define WI_PLX_COR_OFFSET       0x3E0
   87 #define WI_PLX_COR_VALUE        0x41
   88 
   89 struct wi_pci_softc {
   90         struct wi_softc psc_wi;         /* real "wi" softc */
   91 
   92         /* PCI-specific goo */
   93         pci_intr_handle_t psc_ih;       
   94         pci_chipset_tag_t psc_pc;
   95 
   96         void *sc_powerhook;             /* power hook descriptor */
   97 };
   98 
   99 static int      wi_pci_match __P((struct device *, struct cfdata *, void *));
  100 static void     wi_pci_attach __P((struct device *, struct device *, void *));
  101 static int      wi_pci_enable __P((struct wi_softc *));
  102 static void     wi_pci_disable __P((struct wi_softc *));
  103 static void     wi_pci_reset __P((struct wi_softc *));
  104 static void     wi_pci_powerhook __P((int, void *));
  105 
  106 static const struct wi_pci_product
  107         *wi_pci_lookup __P((struct pci_attach_args *));
  108 
  109 CFATTACH_DECL(wi_pci, sizeof(struct wi_pci_softc),
  110     wi_pci_match, wi_pci_attach, NULL, NULL);
  111 
  112 const struct wi_pci_product {
  113         pci_vendor_id_t         wpp_vendor;     /* vendor ID */
  114         pci_product_id_t        wpp_product;    /* product ID */
  115         const char              *wpp_name;      /* product name */
  116         int                     wpp_chip;       /* uses other chip */
  117 } wi_pci_products[] = {
  118         { PCI_VENDOR_GLOBALSUN,         PCI_PRODUCT_GLOBALSUN_GL24110P,
  119           NULL, CHIP_PLX_OTHER },
  120         { PCI_VENDOR_GLOBALSUN,         PCI_PRODUCT_GLOBALSUN_GL24110P02,
  121           NULL, CHIP_PLX_OTHER },
  122         { PCI_VENDOR_EUMITCOM,          PCI_PRODUCT_EUMITCOM_WL11000P,
  123           NULL, CHIP_PLX_OTHER },
  124         { PCI_VENDOR_3COM,              PCI_PRODUCT_3COM_3CRWE777A,
  125           NULL, CHIP_PLX_OTHER },
  126         { PCI_VENDOR_NETGEAR,           PCI_PRODUCT_NETGEAR_MA301,
  127           NULL, CHIP_PLX_OTHER },
  128         { PCI_VENDOR_INTERSIL,          PCI_PRODUCT_INTERSIL_MINI_PCI_WLAN,
  129           "Intersil Prism2.5", 0 },
  130         { PCI_VENDOR_NDC,               PCI_PRODUCT_NDC_NCP130,
  131           NULL, CHIP_PLX_9052 },
  132         { PCI_VENDOR_USR2,              PCI_PRODUCT_USR2_2415,
  133           NULL, CHIP_PLX_OTHER },
  134         { PCI_VENDOR_NDC,               PCI_PRODUCT_NDC_NCP130A2,
  135           NULL, CHIP_TMD_7160 },
  136         { 0,                            0,
  137           NULL, 0},
  138 };
  139 
  140 static int
  141 wi_pci_enable(sc)
  142         struct wi_softc *sc;
  143 {
  144         struct wi_pci_softc *psc = (struct wi_pci_softc *)sc;
  145 
  146         /* establish the interrupt. */
  147         sc->sc_ih = pci_intr_establish(psc->psc_pc, 
  148                                         psc->psc_ih, IPL_NET, wi_intr, sc);
  149         if (sc->sc_ih == NULL) {
  150                 printf("%s: couldn't establish interrupt\n",
  151                     sc->sc_dev.dv_xname);
  152                 return (EIO);
  153         }
  154 
  155         /* reset HFA3842 MAC core */
  156         if (sc->sc_reset != NULL)
  157                 wi_pci_reset(sc);
  158 
  159         return (0);
  160 }
  161 
  162 static void
  163 wi_pci_disable(sc)
  164         struct wi_softc *sc;
  165 {
  166         struct wi_pci_softc *psc = (struct wi_pci_softc *)sc;
  167 
  168         pci_intr_disestablish(psc->psc_pc, sc->sc_ih);
  169 }
  170 
  171 static void
  172 wi_pci_reset(sc)
  173         struct wi_softc         *sc;
  174 {
  175         int i, secs, usecs;
  176 
  177         bus_space_write_2(sc->sc_iot, sc->sc_ioh,
  178             WI_PCI_COR, WI_COR_SOFT_RESET);
  179         DELAY(250*1000); /* 1/4 second */
  180 
  181         bus_space_write_2(sc->sc_iot, sc->sc_ioh,
  182             WI_PCI_COR, WI_COR_CLEAR);
  183         DELAY(500*1000); /* 1/2 second */
  184 
  185         /* wait 2 seconds for firmware to complete initialization. */
  186 
  187         for (i = 200000; i--; DELAY(10))
  188                 if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
  189                         break;
  190  
  191         if (i < 0) {
  192                 printf("%s: PCI reset timed out\n", sc->sc_dev.dv_xname);
  193         } else if (sc->sc_if.if_flags & IFF_DEBUG) {
  194                 usecs = (200000 - i) * 10;
  195                 secs = usecs / 1000000;
  196                 usecs %= 1000000;
  197 
  198                 printf("%s: PCI reset in %d.%06d seconds\n",
  199                        sc->sc_dev.dv_xname, secs, usecs);
  200         }
  201 
  202         return;
  203 }
  204 
  205 static const struct wi_pci_product *
  206 wi_pci_lookup(pa)
  207         struct pci_attach_args *pa;
  208 {
  209         const struct wi_pci_product *wpp;
  210 
  211         for (wpp = wi_pci_products; wpp->wpp_vendor != 0; wpp++) {
  212                 if (PCI_VENDOR(pa->pa_id) == wpp->wpp_vendor &&
  213                     PCI_PRODUCT(pa->pa_id) == wpp->wpp_product)
  214                         return (wpp);
  215         }
  216         return (NULL);
  217 }
  218 
  219 static int
  220 wi_pci_match(parent, match, aux)
  221         struct device *parent;
  222         struct cfdata *match;
  223         void *aux;
  224 {
  225         struct pci_attach_args *pa = aux;
  226 
  227         if (wi_pci_lookup(pa) != NULL)
  228                 return (1);
  229         return (0);
  230 }
  231 
  232 static void
  233 wi_pci_attach(parent, self, aux)
  234         struct device *parent, *self;
  235         void *aux;
  236 {
  237         struct wi_pci_softc *psc = (struct wi_pci_softc *)self;
  238         struct wi_softc *sc = &psc->psc_wi;
  239         struct pci_attach_args *pa = aux;
  240         pci_chipset_tag_t pc = pa->pa_pc;
  241         const char *intrstr;
  242         const struct wi_pci_product *wpp;
  243         pci_intr_handle_t ih;
  244         bus_space_tag_t memt, iot, plxt, tmdt;
  245         bus_space_handle_t memh, ioh, plxh, tmdh;
  246 
  247         psc->psc_pc = pc;
  248 
  249         wpp = wi_pci_lookup(pa);
  250 #ifdef DIAGNOSTIC
  251         if (wpp == NULL) {
  252                 printf("\n");
  253                 panic("wi_pci_attach: impossible");
  254         }
  255 #endif
  256 
  257         switch (wpp->wpp_chip) {
  258         case CHIP_PLX_OTHER:
  259         case CHIP_PLX_9052:
  260                 /* Map memory and I/O registers. */
  261                 if (pci_mapreg_map(pa, WI_PCI_LOMEM, PCI_MAPREG_TYPE_MEM, 0,
  262                     &memt, &memh, NULL, NULL) != 0) {
  263                         printf(": can't map mem space\n");
  264                         return;
  265                 }
  266                 if (pci_mapreg_map(pa, WI_PCI_LOIO, PCI_MAPREG_TYPE_IO, 0,
  267                     &iot, &ioh, NULL, NULL) != 0) {
  268                         printf(": can't map I/O space\n");
  269                         return;
  270                 }
  271 
  272                 if (wpp->wpp_chip == CHIP_PLX_OTHER) {
  273                         /* The PLX 9052 doesn't have IO at 0x14.  Perhaps
  274                            other chips have, so we'll make this conditional. */
  275                         if (pci_mapreg_map(pa, WI_PCI_PLX_LOIO,
  276                                 PCI_MAPREG_TYPE_IO, 0, &plxt,
  277                                 &plxh, NULL, NULL) != 0) {
  278                                         printf(": can't map PLX\n");
  279                                         return;
  280                                 }
  281                 }
  282                 break;
  283         case CHIP_TMD_7160:
  284                 /* Used instead of PLX on at least one revision of
  285                  * the National Datacomm Corporation NCP130. Values
  286                  * for registers acquired from OpenBSD, which in
  287                  * turn got them from a Linux driver.
  288                  */   
  289                 /* Map COR and I/O registers. */
  290                 if (pci_mapreg_map(pa, WI_TMD_COR, PCI_MAPREG_TYPE_IO, 0,
  291                     &tmdt, &tmdh, NULL, NULL) != 0) {
  292                         printf(": can't map TMD\n");
  293                         return;
  294                 }
  295                 if (pci_mapreg_map(pa, WI_TMD_IO, PCI_MAPREG_TYPE_IO, 0,
  296                     &iot, &ioh, NULL, NULL) != 0) {
  297                         printf(": can't map I/O space\n");
  298                         return;
  299                 }
  300                 break;
  301         default:
  302                 if (pci_mapreg_map(pa, WI_PCI_CBMA,
  303                     PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT,
  304                     0, &iot, &ioh, NULL, NULL) != 0) {
  305                         printf(": can't map mem space\n");
  306                         return;
  307                 }
  308 
  309                 memt = iot;
  310                 memh = ioh;
  311                 sc->sc_pci = 1;
  312                 break;
  313         }
  314 
  315         if (wpp->wpp_name != NULL) {
  316                 printf(": %s Wireless Lan\n", wpp->wpp_name);
  317         } else {
  318                 char devinfo[256];
  319 
  320                 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
  321                 printf(": %s (rev. 0x%02x)\n", devinfo,
  322                        PCI_REVISION(pa->pa_class));
  323         }
  324 
  325         sc->sc_enabled = 1;
  326         sc->sc_enable = wi_pci_enable;
  327         sc->sc_disable = wi_pci_disable;
  328 
  329         sc->sc_iot = iot;
  330         sc->sc_ioh = ioh;
  331         /* Make sure interrupts are disabled. */
  332         CSR_WRITE_2(sc, WI_INT_EN, 0);
  333         CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
  334 
  335         if (wpp->wpp_chip == CHIP_PLX_OTHER) {
  336                 uint32_t command;
  337 #define WI_LOCAL_INTCSR         0x4c
  338 #define WI_LOCAL_INTEN          0x40    /* poke this into INTCSR */
  339 
  340                 command = bus_space_read_4(plxt, plxh, WI_LOCAL_INTCSR);
  341                 command |= WI_LOCAL_INTEN;
  342                 bus_space_write_4(plxt, plxh, WI_LOCAL_INTCSR, command);
  343         }
  344 
  345         /* Map and establish the interrupt. */
  346         if (pci_intr_map(pa, &ih)) {
  347                 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
  348                 return;
  349         }
  350         intrstr = pci_intr_string(pc, ih);
  351 
  352         psc->psc_ih = ih;
  353         sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wi_intr, sc);
  354         if (sc->sc_ih == NULL) {
  355                 printf("%s: couldn't establish interrupt",
  356                     sc->sc_dev.dv_xname);
  357                 if (intrstr != NULL)
  358                         printf(" at %s", intrstr);
  359                 printf("\n");
  360                 return;
  361         }
  362 
  363         printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
  364 
  365         switch (wpp->wpp_chip) {
  366         case CHIP_PLX_OTHER:
  367         case CHIP_PLX_9052:
  368                 /*
  369                  * Setup the PLX chip for level interrupts and config index 1
  370                  * XXX - should really reset the PLX chip too.
  371                  */
  372                 bus_space_write_1(memt, memh,
  373                     WI_PLX_COR_OFFSET, WI_PLX_COR_VALUE);
  374                 break;
  375         case CHIP_TMD_7160:
  376                 /* Enable I/O mode and level interrupts on the embedded
  377                  * card. The card's COR is the first byte of BAR 0.
  378                  */
  379                 bus_space_write_1(tmdt, tmdh, 0, WI_COR_IOMODE);
  380                 break;
  381         default:
  382                 /* reset HFA3842 MAC core */
  383                 wi_pci_reset(sc);
  384                 break;
  385         }
  386 
  387         printf("%s:", sc->sc_dev.dv_xname);
  388         if (wi_attach(sc) != 0) {
  389                 printf("%s: failed to attach controller\n",
  390                         sc->sc_dev.dv_xname);
  391                 pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
  392                 return;
  393         }
  394 
  395         if (!wpp->wpp_chip)
  396                 sc->sc_reset = wi_pci_reset;
  397 
  398         /* Add a suspend hook to restore PCI config state */
  399         psc->sc_powerhook = powerhook_establish(wi_pci_powerhook, psc);
  400         if (psc->sc_powerhook == NULL)
  401                 printf ("%s: WARNING: unable to establish pci power hook\n",
  402                         sc->sc_dev.dv_xname);
  403 }
  404 
  405 static void
  406 wi_pci_powerhook(why, arg)
  407         int why;
  408         void *arg;
  409 {
  410         struct wi_pci_softc *psc = arg;
  411         struct wi_softc *sc = &psc->psc_wi;
  412 
  413         wi_power(sc, why);
  414 }

Cache object: 78fee98ac85a41938364bb679d5aa547


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