root/dev/cardbus/if_re_cardbus.c

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

DEFINITIONS

This source file includes following definitions.
  1. re_cardbus_probe
  2. re_cardbus_attach
  3. re_cardbus_setup
  4. re_cardbus_detach
  5. re_cardbus_shutdown
  6. re_cardbus_powerhook

    1 /*      $OpenBSD: if_re_cardbus.c,v 1.11 2006/11/28 20:04:02 brad Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005 Peter Valchev <pvalchev@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /*
   20  * Cardbus front-end for the Realtek 8169
   21  */
   22 
   23 #include <sys/param.h>
   24 #include <sys/endian.h>
   25 #include <sys/systm.h>
   26 #include <sys/sockio.h>
   27 #include <sys/mbuf.h>
   28 #include <sys/malloc.h>
   29 #include <sys/kernel.h>
   30 #include <sys/device.h>
   31 #include <sys/timeout.h>
   32 #include <sys/socket.h>
   33 
   34 #include <net/if.h>
   35 #include <net/if_dl.h>
   36 #include <net/if_media.h>
   37 
   38 #ifdef INET
   39 #include <netinet/in.h>
   40 #include <netinet/in_systm.h>
   41 #include <netinet/in_var.h>
   42 #include <netinet/ip.h>
   43 #include <netinet/if_ether.h>
   44 #endif
   45 
   46 #include <dev/mii/mii.h>
   47 #include <dev/mii/miivar.h>
   48 
   49 #include <dev/pci/pcidevs.h>
   50 
   51 #include <dev/cardbus/cardbusvar.h>
   52 
   53 #include <dev/ic/rtl81x9reg.h>
   54 #include <dev/ic/revar.h>
   55 
   56 struct re_cardbus_softc {
   57         /* General */
   58         struct rl_softc sc_rl;
   59 
   60         /* Cardbus-specific data */
   61         void *sc_ih;
   62         cardbus_devfunc_t ct;
   63         cardbustag_t sc_tag;
   64         int sc_csr;
   65         int sc_cben;
   66         int sc_bar_reg;
   67         pcireg_t sc_bar_val;
   68         int sc_intrline;
   69 
   70         bus_size_t sc_mapsize;
   71 };
   72 
   73 int     re_cardbus_probe(struct device *, void *, void *);
   74 void    re_cardbus_attach(struct device *, struct device *, void *);
   75 int     re_cardbus_detach(struct device *, int);
   76 void    re_cardbus_setup(struct rl_softc *);
   77 
   78 void    re_cardbus_shutdown(void *);
   79 void    re_cardbus_powerhook(int, void *);
   80 
   81 /*
   82  * Cardbus autoconfig definitions
   83  */
   84 struct cfattach re_cardbus_ca = {
   85         sizeof(struct re_cardbus_softc),
   86         re_cardbus_probe,
   87         re_cardbus_attach,
   88         re_cardbus_detach
   89 };
   90 
   91 const struct cardbus_matchid re_cardbus_devices[] = {
   92         { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8169 },
   93 };
   94 
   95 /*
   96  * Probe for a RealTek 8169/8110 chip. Check the PCI vendor and device
   97  * IDs against our list and return a device name if we find a match.
   98  */
   99 int
  100 re_cardbus_probe(struct device *parent, void *match, void *aux)
  101 {
  102         return (cardbus_matchbyid((struct cardbus_attach_args *)aux,
  103             re_cardbus_devices,
  104             sizeof(re_cardbus_devices)/sizeof(re_cardbus_devices[0])));
  105 }
  106 
  107 /*
  108  * Attach the interface. Allocate softc structures, do ifmedia
  109  * setup and ethernet/BPF attach.
  110  */
  111 void
  112 re_cardbus_attach(struct device *parent, struct device *self, void *aux)
  113 {
  114         struct re_cardbus_softc *csc = (struct re_cardbus_softc *)self;
  115         struct rl_softc         *sc = &csc->sc_rl;
  116         struct cardbus_attach_args *ca = aux;
  117         struct cardbus_softc *psc =
  118             (struct cardbus_softc *)sc->sc_dev.dv_parent;
  119         cardbus_chipset_tag_t cc = psc->sc_cc;
  120         cardbus_function_tag_t cf = psc->sc_cf;
  121         cardbus_devfunc_t ct = ca->ca_ct;
  122         bus_addr_t adr;
  123         char intrstr[16];
  124 
  125         sc->sc_dmat = ca->ca_dmat;
  126         csc->ct = ct;
  127         csc->sc_tag = ca->ca_tag;
  128         csc->sc_intrline = ca->ca_intrline;
  129 
  130         /*
  131          * Map control/status registers.
  132          */
  133         if (Cardbus_mapreg_map(ct, RL_PCI_LOMEM, CARDBUS_MAPREG_TYPE_MEM, 0,
  134             &sc->rl_btag, &sc->rl_bhandle, &adr, &csc->sc_mapsize) == 0) {
  135                 csc->sc_cben = CARDBUS_MEM_ENABLE;
  136                 csc->sc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
  137                 csc->sc_bar_reg = RL_PCI_LOMEM;
  138                 csc->sc_bar_val = adr | CARDBUS_MAPREG_TYPE_MEM;
  139         } else {
  140                 printf(": can't map mem space\n");
  141                 return;
  142         }
  143 
  144         /* Enable power */
  145         Cardbus_function_enable(ct);
  146 
  147         /* Get chip out of powersave mode (if applicable), initialize
  148          * config registers */
  149         re_cardbus_setup(sc);
  150 
  151         /* Allocate interrupt */
  152         csc->sc_ih = cardbus_intr_establish(cc, cf, csc->sc_intrline,
  153             IPL_NET, re_intr, sc, sc->sc_dev.dv_xname);
  154         if (csc->sc_ih == NULL) {
  155                 printf(": couldn't establish interrupt at %s",
  156                     ca->ca_intrline);
  157                 Cardbus_function_disable(csc->ct);
  158                 return;
  159         }
  160         snprintf(intrstr, sizeof(intrstr), "irq %d", ca->ca_intrline);
  161 
  162         sc->sc_flags |= RL_ENABLED;
  163         sc->rl_type = RL_8169;
  164 
  165         sc->sc_sdhook = shutdownhook_establish(re_cardbus_shutdown, sc);
  166         sc->sc_pwrhook = powerhook_establish(re_cardbus_powerhook, sc);
  167 
  168         /* Call bus-independent (common) attach routine */
  169         re_attach(sc, intrstr);
  170 }
  171 
  172 /*
  173  * Get chip out of power-saving mode, init registers
  174  */
  175 void
  176 re_cardbus_setup(struct rl_softc *sc)
  177 {
  178         struct re_cardbus_softc *csc = (struct re_cardbus_softc *)sc;
  179         cardbus_devfunc_t ct = csc->ct;
  180         cardbus_chipset_tag_t cc = ct->ct_cc;
  181         cardbus_function_tag_t cf = ct->ct_cf;
  182         pcireg_t reg, command;
  183         int pmreg;
  184 
  185         /* Handle power management nonsense */
  186         if (cardbus_get_capability(cc, cf, csc->sc_tag,
  187             PCI_CAP_PWRMGMT, &pmreg, 0)) {
  188                 command = cardbus_conf_read(cc, cf, csc->sc_tag,
  189                     pmreg + PCI_PMCSR);
  190 
  191                 if (command & RL_PSTATE_MASK) {
  192                         pcireg_t iobase, membase, irq;
  193 
  194                         /* Save important PCI config data */
  195                         iobase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOIO);
  196                         membase = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_LOMEM);
  197                         irq = cardbus_conf_read(cc, cf, csc->sc_tag, RL_PCI_INTLINE);
  198 
  199                         /* Reset the power state */
  200                         printf("%s: chip is in D%d power mode "
  201                             "-- setting to D0\n", sc->sc_dev.dv_xname,
  202                             command & RL_PSTATE_MASK);
  203                         command &= RL_PSTATE_MASK;
  204                         cardbus_conf_write(cc, cf, csc->sc_tag, pmreg + PCI_PMCSR,
  205                             command);
  206 
  207                         /* Restore PCI config data */
  208                         cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOIO, iobase);
  209                         cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_LOMEM, membase);
  210                         cardbus_conf_write(cc, cf, csc->sc_tag, RL_PCI_INTLINE, irq);
  211                 }
  212         }
  213 
  214         /* Make sure the right access type is on the Cardbus bridge */
  215         (*ct->ct_cf->cardbus_ctrl)(cc, csc->sc_cben);
  216         (*ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE);
  217 
  218         /* Program the BAR */
  219         cardbus_conf_write(cc, cf, csc->sc_tag, csc->sc_bar_reg, csc->sc_bar_val);
  220 
  221         /* Enable proper bits in CARDBUS CSR */
  222         reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG);
  223         reg &= ~(CARDBUS_COMMAND_IO_ENABLE|CARDBUS_COMMAND_MEM_ENABLE);
  224         reg |= csc->sc_csr;
  225         cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
  226 
  227         /* Make sure the latency timer is set to some reasonable value */
  228         reg = cardbus_conf_read(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG);
  229         if (CARDBUS_LATTIMER(reg) < 0x20) {
  230                 reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
  231                 reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
  232                 cardbus_conf_write(cc, cf, csc->sc_tag, CARDBUS_BHLC_REG, reg);
  233         }
  234 }
  235 
  236 /*
  237  * Cardbus detach function: deallocate all resources
  238  */
  239 int
  240 re_cardbus_detach(struct device *self, int flags)
  241 {
  242         struct re_cardbus_softc *csc = (void *)self;
  243         struct rl_softc *sc = &csc->sc_rl;
  244         struct cardbus_devfunc *ct = csc->ct;
  245         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  246 
  247         /* Remove timeout handler */
  248         timeout_del(&sc->timer_handle);
  249 
  250         /* Detach PHY */
  251         if (LIST_FIRST(&sc->sc_mii.mii_phys) != NULL)
  252                 mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
  253 
  254         /* Delete media stuff */
  255         ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
  256         ether_ifdetach(ifp);
  257         if_detach(ifp);
  258 
  259         /* No more hooks */
  260         if (sc->sc_sdhook != NULL)
  261                 shutdownhook_disestablish(sc->sc_sdhook);
  262         if (sc->sc_pwrhook != NULL)
  263                 powerhook_disestablish(sc->sc_pwrhook);
  264 
  265         /* Disable interrupts */
  266         if (csc->sc_ih != NULL)
  267                 cardbus_intr_disestablish(ct->ct_cc, ct->ct_cf, csc->sc_ih);
  268 
  269         /* Free cardbus resources */
  270         Cardbus_mapreg_unmap(ct, csc->sc_bar_reg, sc->rl_btag, sc->rl_bhandle,
  271             csc->sc_mapsize);
  272 
  273         return (0);
  274 }
  275 
  276 void
  277 re_cardbus_shutdown(void *arg)
  278 {
  279         struct rl_softc *sc = arg;
  280         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  281 
  282         re_stop(ifp, 1);
  283 }
  284 
  285 void
  286 re_cardbus_powerhook(int why, void *arg)
  287 {
  288         struct rl_softc *sc = arg;
  289         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  290 
  291         if (why == PWR_RESUME)
  292                 re_init(ifp);
  293 }

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