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/iwm/if_iwm_pcie_trans.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 /*      $OpenBSD: if_iwm.c,v 1.39 2015/03/23 00:35:19 jsg Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2014 genua mbh <info@genua.de>
    5  * Copyright (c) 2014 Fixup Software Ltd.
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 /*-
   21  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
   22  * which were used as the reference documentation for this implementation.
   23  *
   24  * Driver version we are currently based off of is
   25  * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
   26  *
   27  ***********************************************************************
   28  *
   29  * This file is provided under a dual BSD/GPLv2 license.  When using or
   30  * redistributing this file, you may do so under either license.
   31  *
   32  * GPL LICENSE SUMMARY
   33  *
   34  * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
   35  *
   36  * This program is free software; you can redistribute it and/or modify
   37  * it under the terms of version 2 of the GNU General Public License as
   38  * published by the Free Software Foundation.
   39  *
   40  * This program is distributed in the hope that it will be useful, but
   41  * WITHOUT ANY WARRANTY; without even the implied warranty of
   42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   43  * General Public License for more details.
   44  *
   45  * You should have received a copy of the GNU General Public License
   46  * along with this program; if not, write to the Free Software
   47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
   48  * USA
   49  *
   50  * The full GNU General Public License is included in this distribution
   51  * in the file called COPYING.
   52  *
   53  * Contact Information:
   54  *  Intel Linux Wireless <ilw@linux.intel.com>
   55  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   56  *
   57  *
   58  * BSD LICENSE
   59  *
   60  * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
   61  * All rights reserved.
   62  *
   63  * Redistribution and use in source and binary forms, with or without
   64  * modification, are permitted provided that the following conditions
   65  * are met:
   66  *
   67  *  * Redistributions of source code must retain the above copyright
   68  *    notice, this list of conditions and the following disclaimer.
   69  *  * Redistributions in binary form must reproduce the above copyright
   70  *    notice, this list of conditions and the following disclaimer in
   71  *    the documentation and/or other materials provided with the
   72  *    distribution.
   73  *  * Neither the name Intel Corporation nor the names of its
   74  *    contributors may be used to endorse or promote products derived
   75  *    from this software without specific prior written permission.
   76  *
   77  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   78  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   79  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   80  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   81  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   82  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   83  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   84  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   85  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   86  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   87  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   88  */
   89 
   90 /*-
   91  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
   92  *
   93  * Permission to use, copy, modify, and distribute this software for any
   94  * purpose with or without fee is hereby granted, provided that the above
   95  * copyright notice and this permission notice appear in all copies.
   96  *
   97  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   98  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   99  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  100  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  101  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  102  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  103  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  104  */
  105 #include <sys/cdefs.h>
  106 __FBSDID("$FreeBSD$");
  107 
  108 #include "opt_wlan.h"
  109 #include "opt_iwm.h"
  110 
  111 #include <sys/param.h>
  112 #include <sys/bus.h>
  113 #include <sys/conf.h>
  114 #include <sys/endian.h>
  115 #include <sys/firmware.h>
  116 #include <sys/kernel.h>
  117 #include <sys/malloc.h>
  118 #include <sys/mbuf.h>
  119 #include <sys/mutex.h>
  120 #include <sys/module.h>
  121 #include <sys/proc.h>
  122 #include <sys/rman.h>
  123 #include <sys/socket.h>
  124 #include <sys/sockio.h>
  125 #include <sys/sysctl.h>
  126 #include <sys/linker.h>
  127 
  128 #include <machine/bus.h>
  129 #include <machine/endian.h>
  130 #include <machine/resource.h>
  131 
  132 #include <dev/pci/pcivar.h>
  133 #include <dev/pci/pcireg.h>
  134 
  135 #include <net/bpf.h>
  136 
  137 #include <net/if.h>
  138 #include <net/if_var.h>
  139 #include <net/if_arp.h>
  140 #include <net/if_dl.h>
  141 #include <net/if_media.h>
  142 #include <net/if_types.h>
  143 
  144 #include <netinet/in.h>
  145 #include <netinet/in_systm.h>
  146 #include <netinet/if_ether.h>
  147 #include <netinet/ip.h>
  148 
  149 #include <net80211/ieee80211_var.h>
  150 #include <net80211/ieee80211_regdomain.h>
  151 #include <net80211/ieee80211_ratectl.h>
  152 #include <net80211/ieee80211_radiotap.h>
  153 
  154 #include <dev/iwm/if_iwmreg.h>
  155 #include <dev/iwm/if_iwmvar.h>
  156 #include <dev/iwm/if_iwm_config.h>
  157 #include <dev/iwm/if_iwm_debug.h>
  158 #include <dev/iwm/if_iwm_pcie_trans.h>
  159 
  160 /*
  161  * This is a subset of what's in linux iwlwifi/pcie/trans.c.
  162  * The rest can be migrated out into here once they're no longer in
  163  * if_iwm.c.
  164  */
  165 
  166 /*
  167  * basic device access
  168  */
  169 
  170 uint32_t
  171 iwm_read_prph(struct iwm_softc *sc, uint32_t addr)
  172 {
  173         IWM_WRITE(sc,
  174             IWM_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24)));
  175         IWM_BARRIER_READ_WRITE(sc);
  176         return IWM_READ(sc, IWM_HBUS_TARG_PRPH_RDAT);
  177 }
  178 
  179 void
  180 iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val)
  181 {
  182         IWM_WRITE(sc,
  183             IWM_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24)));
  184         IWM_BARRIER_WRITE(sc);
  185         IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val);
  186 }
  187 
  188 void
  189 iwm_write_prph64(struct iwm_softc *sc, uint64_t addr, uint64_t val)
  190 {
  191         iwm_write_prph(sc, (uint32_t)addr, val & 0xffffffff);
  192         iwm_write_prph(sc, (uint32_t)addr + 4, val >> 32);
  193 }
  194 
  195 int
  196 iwm_poll_prph(struct iwm_softc *sc, uint32_t addr, uint32_t bits, uint32_t mask,
  197     int timeout)
  198 {
  199         do {
  200                 if ((iwm_read_prph(sc, addr) & mask) == (bits & mask))
  201                         return (0);
  202                 DELAY(10);
  203                 timeout -= 10;
  204         } while (timeout > 0);
  205 
  206         return (ETIMEDOUT);
  207 }
  208 
  209 #ifdef IWM_DEBUG
  210 /* iwlwifi: pcie/trans.c */
  211 int
  212 iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords)
  213 {
  214         int offs, ret = 0;
  215         uint32_t *vals = buf;
  216 
  217         if (iwm_nic_lock(sc)) {
  218                 IWM_WRITE(sc, IWM_HBUS_TARG_MEM_RADDR, addr);
  219                 for (offs = 0; offs < dwords; offs++)
  220                         vals[offs] = IWM_READ(sc, IWM_HBUS_TARG_MEM_RDAT);
  221                 iwm_nic_unlock(sc);
  222         } else {
  223                 ret = EBUSY;
  224         }
  225         return ret;
  226 }
  227 #endif
  228 
  229 /* iwlwifi: pcie/trans.c */
  230 int
  231 iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords)
  232 {
  233         int offs;
  234         const uint32_t *vals = buf;
  235 
  236         if (iwm_nic_lock(sc)) {
  237                 IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr);
  238                 /* WADDR auto-increments */
  239                 for (offs = 0; offs < dwords; offs++) {
  240                         uint32_t val = vals ? vals[offs] : 0;
  241                         IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val);
  242                 }
  243                 iwm_nic_unlock(sc);
  244         } else {
  245                 IWM_DPRINTF(sc, IWM_DEBUG_TRANS,
  246                     "%s: write_mem failed\n", __func__);
  247                 return EBUSY;
  248         }
  249         return 0;
  250 }
  251 
  252 int
  253 iwm_write_mem32(struct iwm_softc *sc, uint32_t addr, uint32_t val)
  254 {
  255         return iwm_write_mem(sc, addr, &val, 1);
  256 }
  257 
  258 int
  259 iwm_poll_bit(struct iwm_softc *sc, int reg,
  260         uint32_t bits, uint32_t mask, int timo)
  261 {
  262         for (;;) {
  263                 if ((IWM_READ(sc, reg) & mask) == (bits & mask)) {
  264                         return 1;
  265                 }
  266                 if (timo < 10) {
  267                         return 0;
  268                 }
  269                 timo -= 10;
  270                 DELAY(10);
  271         }
  272 }
  273 
  274 int
  275 iwm_nic_lock(struct iwm_softc *sc)
  276 {
  277         int rv = 0;
  278 
  279         if (sc->cmd_hold_nic_awake)
  280                 return 1;
  281 
  282         IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
  283             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
  284 
  285         if (sc->cfg->device_family >= IWM_DEVICE_FAMILY_8000)
  286                 DELAY(2);
  287 
  288         if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
  289             IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
  290             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY
  291              | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) {
  292                 rv = 1;
  293         } else {
  294                 /* jolt */
  295                 IWM_DPRINTF(sc, IWM_DEBUG_RESET,
  296                     "%s: resetting device via NMI\n", __func__);
  297                 IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI);
  298         }
  299 
  300         return rv;
  301 }
  302 
  303 void
  304 iwm_nic_unlock(struct iwm_softc *sc)
  305 {
  306         if (sc->cmd_hold_nic_awake)
  307                 return;
  308 
  309         IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
  310             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
  311 }
  312 
  313 void
  314 iwm_set_bits_mask_prph(struct iwm_softc *sc,
  315         uint32_t reg, uint32_t bits, uint32_t mask)
  316 {
  317         uint32_t val;
  318 
  319         /* XXX: no error path? */
  320         if (iwm_nic_lock(sc)) {
  321                 val = iwm_read_prph(sc, reg) & mask;
  322                 val |= bits;
  323                 iwm_write_prph(sc, reg, val);
  324                 iwm_nic_unlock(sc);
  325         }
  326 }
  327 
  328 void
  329 iwm_set_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
  330 {
  331         iwm_set_bits_mask_prph(sc, reg, bits, ~0);
  332 }
  333 
  334 void
  335 iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
  336 {
  337         iwm_set_bits_mask_prph(sc, reg, 0, ~bits);
  338 }
  339 
  340 /*
  341  * High-level hardware frobbing routines
  342  */
  343 
  344 void
  345 iwm_enable_rfkill_int(struct iwm_softc *sc)
  346 {
  347         sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL;
  348         IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
  349         IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
  350             IWM_CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN);
  351 }
  352 
  353 int
  354 iwm_check_rfkill(struct iwm_softc *sc)
  355 {
  356         uint32_t v;
  357         int rv;
  358 
  359         /*
  360          * "documentation" is not really helpful here:
  361          *  27: HW_RF_KILL_SW
  362          *      Indicates state of (platform's) hardware RF-Kill switch
  363          *
  364          * But apparently when it's off, it's on ...
  365          */
  366         v = IWM_READ(sc, IWM_CSR_GP_CNTRL);
  367         rv = (v & IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0;
  368         if (rv) {
  369                 sc->sc_flags |= IWM_FLAG_RFKILL;
  370         } else {
  371                 sc->sc_flags &= ~IWM_FLAG_RFKILL;
  372         }
  373 
  374         return rv;
  375 }
  376 
  377 
  378 #define IWM_HW_READY_TIMEOUT 50
  379 int
  380 iwm_set_hw_ready(struct iwm_softc *sc)
  381 {
  382         int ready;
  383 
  384         IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
  385             IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
  386 
  387         ready = iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
  388             IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
  389             IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
  390             IWM_HW_READY_TIMEOUT);
  391         if (ready) {
  392                 IWM_SETBITS(sc, IWM_CSR_MBOX_SET_REG,
  393                     IWM_CSR_MBOX_SET_REG_OS_ALIVE);
  394         }
  395         return ready;
  396 }
  397 #undef IWM_HW_READY_TIMEOUT
  398 
  399 int
  400 iwm_prepare_card_hw(struct iwm_softc *sc)
  401 {
  402         int rv = 0;
  403         int t = 0;
  404 
  405         IWM_DPRINTF(sc, IWM_DEBUG_RESET, "->%s\n", __func__);
  406         if (iwm_set_hw_ready(sc))
  407                 goto out;
  408 
  409         IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG,
  410             IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED);
  411         DELAY(1000);
  412 
  413         /* If HW is not ready, prepare the conditions to check again */
  414         IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
  415             IWM_CSR_HW_IF_CONFIG_REG_PREPARE);
  416 
  417         do {
  418                 if (iwm_set_hw_ready(sc))
  419                         goto out;
  420                 DELAY(200);
  421                 t += 200;
  422         } while (t < 150000);
  423 
  424         rv = ETIMEDOUT;
  425 
  426  out:
  427         IWM_DPRINTF(sc, IWM_DEBUG_RESET, "<-%s\n", __func__);
  428         return rv;
  429 }
  430 
  431 void
  432 iwm_apm_config(struct iwm_softc *sc)
  433 {
  434         uint16_t lctl, cap;
  435         int pcie_ptr;
  436 
  437         /*
  438          * HW bug W/A for instability in PCIe bus L0S->L1 transition.
  439          * Check if BIOS (or OS) enabled L1-ASPM on this device.
  440          * If so (likely), disable L0S, so device moves directly L0->L1;
  441          *    costs negligible amount of power savings.
  442          * If not (unlikely), enable L0S, so there is at least some
  443          *    power savings, even without L1.
  444          */
  445         int error;
  446 
  447         error = pci_find_cap(sc->sc_dev, PCIY_EXPRESS, &pcie_ptr);
  448         if (error != 0)
  449                 return;
  450         lctl = pci_read_config(sc->sc_dev, pcie_ptr + PCIER_LINK_CTL,
  451             sizeof(lctl));
  452         if (lctl & PCIEM_LINK_CTL_ASPMC_L1)  {
  453                 IWM_SETBITS(sc, IWM_CSR_GIO_REG,
  454                     IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
  455         } else {
  456                 IWM_CLRBITS(sc, IWM_CSR_GIO_REG,
  457                     IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
  458         }
  459 
  460         cap = pci_read_config(sc->sc_dev, pcie_ptr + PCIER_DEVICE_CTL2,
  461             sizeof(cap));
  462         sc->sc_ltr_enabled = (cap & PCIEM_CTL2_LTR_ENABLE) ? 1 : 0;
  463         IWM_DPRINTF(sc, IWM_DEBUG_RESET | IWM_DEBUG_PWRSAVE,
  464             "L1 %sabled - LTR %sabled\n",
  465             (lctl & PCIEM_LINK_CTL_ASPMC_L1) ? "En" : "Dis",
  466             sc->sc_ltr_enabled ? "En" : "Dis");
  467 }
  468 
  469 /*
  470  * Start up NIC's basic functionality after it has been reset
  471  * (e.g. after platform boot, or shutdown via iwm_pcie_apm_stop())
  472  * NOTE:  This does not load uCode nor start the embedded processor
  473  */
  474 int
  475 iwm_apm_init(struct iwm_softc *sc)
  476 {
  477         int error = 0;
  478 
  479         IWM_DPRINTF(sc, IWM_DEBUG_RESET, "iwm apm start\n");
  480 
  481         /* Disable L0S exit timer (platform NMI Work/Around) */
  482         if (sc->cfg->device_family < IWM_DEVICE_FAMILY_8000) {
  483                 IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
  484                     IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
  485         }
  486 
  487         /*
  488          * Disable L0s without affecting L1;
  489          *  don't wait for ICH L0s (ICH bug W/A)
  490          */
  491         IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
  492             IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
  493 
  494         /* Set FH wait threshold to maximum (HW error during stress W/A) */
  495         IWM_SETBITS(sc, IWM_CSR_DBG_HPET_MEM_REG, IWM_CSR_DBG_HPET_MEM_REG_VAL);
  496 
  497         /*
  498          * Enable HAP INTA (interrupt from management bus) to
  499          * wake device's PCI Express link L1a -> L0s
  500          */
  501         IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
  502             IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
  503 
  504         iwm_apm_config(sc);
  505 
  506 #if 0 /* not for 7k/8k */
  507         /* Configure analog phase-lock-loop before activating to D0A */
  508         if (trans->cfg->base_params->pll_cfg_val)
  509                 IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG,
  510                     trans->cfg->base_params->pll_cfg_val);
  511 #endif
  512 
  513         /*
  514          * Set "initialization complete" bit to move adapter from
  515          * D0U* --> D0A* (powered-up active) state.
  516          */
  517         IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
  518 
  519         /*
  520          * Wait for clock stabilization; once stabilized, access to
  521          * device-internal resources is supported, e.g. iwm_write_prph()
  522          * and accesses to uCode SRAM.
  523          */
  524         if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
  525             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
  526             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) {
  527                 device_printf(sc->sc_dev,
  528                     "timeout waiting for clock stabilization\n");
  529                 error = ETIMEDOUT;
  530                 goto out;
  531         }
  532 
  533         if (sc->cfg->host_interrupt_operation_mode) {
  534                 /*
  535                  * This is a bit of an abuse - This is needed for 7260 / 3160
  536                  * only check host_interrupt_operation_mode even if this is
  537                  * not related to host_interrupt_operation_mode.
  538                  *
  539                  * Enable the oscillator to count wake up time for L1 exit. This
  540                  * consumes slightly more power (100uA) - but allows to be sure
  541                  * that we wake up from L1 on time.
  542                  *
  543                  * This looks weird: read twice the same register, discard the
  544                  * value, set a bit, and yet again, read that same register
  545                  * just to discard the value. But that's the way the hardware
  546                  * seems to like it.
  547                  */
  548                 if (iwm_nic_lock(sc)) {
  549                         iwm_read_prph(sc, IWM_OSC_CLK);
  550                         iwm_read_prph(sc, IWM_OSC_CLK);
  551                         iwm_nic_unlock(sc);
  552                 }
  553                 iwm_set_bits_prph(sc, IWM_OSC_CLK, IWM_OSC_CLK_FORCE_CONTROL);
  554                 if (iwm_nic_lock(sc)) {
  555                         iwm_read_prph(sc, IWM_OSC_CLK);
  556                         iwm_read_prph(sc, IWM_OSC_CLK);
  557                         iwm_nic_unlock(sc);
  558                 }
  559         }
  560 
  561         /*
  562          * Enable DMA clock and wait for it to stabilize.
  563          *
  564          * Write to "CLK_EN_REG"; "1" bits enable clocks, while "" bits
  565          * do not disable clocks.  This preserves any hardware bits already
  566          * set by default in "CLK_CTRL_REG" after reset.
  567          */
  568         if (sc->cfg->device_family == IWM_DEVICE_FAMILY_7000) {
  569                 if (iwm_nic_lock(sc)) {
  570                         iwm_write_prph(sc, IWM_APMG_CLK_EN_REG,
  571                             IWM_APMG_CLK_VAL_DMA_CLK_RQT);
  572                         iwm_nic_unlock(sc);
  573                 }
  574                 DELAY(20);
  575 
  576                 /* Disable L1-Active */
  577                 iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
  578                     IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
  579 
  580                 /* Clear the interrupt in APMG if the NIC is in RFKILL */
  581                 if (iwm_nic_lock(sc)) {
  582                         iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
  583                             IWM_APMG_RTC_INT_STT_RFKILL);
  584                         iwm_nic_unlock(sc);
  585                 }
  586         }
  587  out:
  588         if (error)
  589                 device_printf(sc->sc_dev, "apm init error %d\n", error);
  590         return error;
  591 }
  592 
  593 /* iwlwifi/pcie/trans.c */
  594 void
  595 iwm_apm_stop(struct iwm_softc *sc)
  596 {
  597         IWM_SETBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG,
  598             IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED);
  599         IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
  600             IWM_CSR_HW_IF_CONFIG_REG_PREPARE |
  601             IWM_CSR_HW_IF_CONFIG_REG_ENABLE_PME);
  602         DELAY(1000);
  603         IWM_CLRBITS(sc, IWM_CSR_DBG_LINK_PWR_MGMT_REG,
  604             IWM_CSR_RESET_LINK_PWR_MGMT_DISABLED);
  605         DELAY(5000);
  606 
  607         /* stop device's busmaster DMA activity */
  608         IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER);
  609 
  610         if (!iwm_poll_bit(sc, IWM_CSR_RESET,
  611             IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED,
  612             IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100))
  613                 device_printf(sc->sc_dev, "timeout waiting for master\n");
  614 
  615         /*
  616          * Clear "initialization complete" bit to move adapter from
  617          * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
  618          */
  619         IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
  620             IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
  621 
  622         IWM_DPRINTF(sc, IWM_DEBUG_TRANS, "%s: iwm apm stop\n", __func__);
  623 }
  624 
  625 /* iwlwifi pcie/trans.c */
  626 int
  627 iwm_start_hw(struct iwm_softc *sc)
  628 {
  629         int error;
  630 
  631         if ((error = iwm_prepare_card_hw(sc)) != 0)
  632                 return error;
  633 
  634         /* Reset the entire device */
  635         IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_SW_RESET);
  636         DELAY(5000);
  637 
  638         if ((error = iwm_apm_init(sc)) != 0)
  639                 return error;
  640 
  641         /* On newer chipsets MSI is disabled by default. */
  642         if (sc->cfg->mqrx_supported)
  643                 iwm_write_prph(sc, IWM_UREG_CHICK, IWM_UREG_CHICK_MSI_ENABLE);
  644 
  645         iwm_enable_rfkill_int(sc);
  646         iwm_check_rfkill(sc);
  647 
  648         return 0;
  649 }
  650 
  651 /* iwlwifi pcie/trans.c (always main power) */
  652 void
  653 iwm_set_pwr(struct iwm_softc *sc)
  654 {
  655         iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
  656             IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~IWM_APMG_PS_CTRL_MSK_PWR_SRC);
  657 }
  658 
  659 /* iwlwifi pcie/rx.c */
  660 int
  661 iwm_pcie_rx_stop(struct iwm_softc *sc)
  662 {
  663         int ret;
  664 
  665         ret = 0;
  666         if (iwm_nic_lock(sc)) {
  667                 if (sc->cfg->mqrx_supported) {
  668                         iwm_write_prph(sc, IWM_RFH_RXF_DMA_CFG, 0);
  669                         ret = iwm_poll_prph(sc, IWM_RFH_GEN_STATUS,
  670                             IWM_RXF_DMA_IDLE, IWM_RXF_DMA_IDLE, 1000);
  671                 } else {
  672                         IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
  673                         ret = iwm_poll_bit(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG,
  674                             IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
  675                             IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
  676                             1000);
  677                 }
  678                 iwm_nic_unlock(sc);
  679         }
  680         return ret;
  681 }
  682 
  683 void
  684 iwm_pcie_clear_cmd_in_flight(struct iwm_softc *sc)
  685 {
  686         if (!sc->cfg->apmg_wake_up_wa)
  687                 return;
  688 
  689         if (!sc->cmd_hold_nic_awake) {
  690                 device_printf(sc->sc_dev,
  691                     "%s: cmd_hold_nic_awake not set\n", __func__);
  692                 return;
  693         }
  694 
  695         sc->cmd_hold_nic_awake = 0;
  696         IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
  697             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
  698 }
  699 
  700 int
  701 iwm_pcie_set_cmd_in_flight(struct iwm_softc *sc)
  702 {
  703         int ret;
  704 
  705         /*
  706          * wake up the NIC to make sure that the firmware will see the host
  707          * command - we will let the NIC sleep once all the host commands
  708          * returned. This needs to be done only on NICs that have
  709          * apmg_wake_up_wa set.
  710          */
  711         if (sc->cfg->apmg_wake_up_wa &&
  712             !sc->cmd_hold_nic_awake) {
  713 
  714                 IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
  715                     IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
  716 
  717                 ret = iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
  718                     IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
  719                     (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
  720                      IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
  721                     15000);
  722                 if (ret == 0) {
  723                         IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
  724                             IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
  725                         device_printf(sc->sc_dev,
  726                             "%s: Failed to wake NIC for hcmd\n", __func__);
  727                         return EIO;
  728                 }
  729                 sc->cmd_hold_nic_awake = 1;
  730         }
  731 
  732         return 0;
  733 }

Cache object: e77f35f85e4a0fa70595f9308f269c75


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