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/contrib/dev/iwlwifi/pcie/trans-gen2.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 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
    2 /*
    3  * Copyright (C) 2017 Intel Deutschland GmbH
    4  * Copyright (C) 2018-2021 Intel Corporation
    5  */
    6 #if defined(__FreeBSD__)
    7 #include <linux/delay.h>
    8 #endif
    9 #include "iwl-trans.h"
   10 #include "iwl-prph.h"
   11 #include "iwl-context-info.h"
   12 #include "iwl-context-info-gen3.h"
   13 #include "internal.h"
   14 #include "fw/dbg.h"
   15 
   16 #define FW_RESET_TIMEOUT (HZ / 5)
   17 
   18 /*
   19  * Start up NIC's basic functionality after it has been reset
   20  * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop())
   21  * NOTE:  This does not load uCode nor start the embedded processor
   22  */
   23 int iwl_pcie_gen2_apm_init(struct iwl_trans *trans)
   24 {
   25         int ret = 0;
   26 
   27         IWL_DEBUG_INFO(trans, "Init card's basic functions\n");
   28 
   29         /*
   30          * Use "set_bit" below rather than "write", to preserve any hardware
   31          * bits already set by default after reset.
   32          */
   33 
   34         /*
   35          * Disable L0s without affecting L1;
   36          * don't wait for ICH L0s (ICH bug W/A)
   37          */
   38         iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS,
   39                     CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
   40 
   41         /* Set FH wait threshold to maximum (HW error during stress W/A) */
   42         iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL);
   43 
   44         /*
   45          * Enable HAP INTA (interrupt from management bus) to
   46          * wake device's PCI Express link L1a -> L0s
   47          */
   48         iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
   49                     CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
   50 
   51         iwl_pcie_apm_config(trans);
   52 
   53         ret = iwl_finish_nic_init(trans);
   54         if (ret)
   55                 return ret;
   56 
   57         set_bit(STATUS_DEVICE_ENABLED, &trans->status);
   58 
   59         return 0;
   60 }
   61 
   62 static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
   63 {
   64         IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
   65 
   66         if (op_mode_leave) {
   67                 if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
   68                         iwl_pcie_gen2_apm_init(trans);
   69 
   70                 /* inform ME that we are leaving */
   71                 iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
   72                             CSR_RESET_LINK_PWR_MGMT_DISABLED);
   73                 iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
   74                             CSR_HW_IF_CONFIG_REG_PREPARE |
   75                             CSR_HW_IF_CONFIG_REG_ENABLE_PME);
   76                 mdelay(1);
   77                 iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG,
   78                               CSR_RESET_LINK_PWR_MGMT_DISABLED);
   79                 mdelay(5);
   80         }
   81 
   82         clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
   83 
   84         /* Stop device's DMA activity */
   85         iwl_pcie_apm_stop_master(trans);
   86 
   87         iwl_trans_sw_reset(trans, false);
   88 
   89         /*
   90          * Clear "initialization complete" bit to move adapter from
   91          * D0A* (powered-up Active) --> D0U* (Uninitialized) state.
   92          */
   93         if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
   94                 iwl_clear_bit(trans, CSR_GP_CNTRL,
   95                               CSR_GP_CNTRL_REG_FLAG_MAC_INIT);
   96         else
   97                 iwl_clear_bit(trans, CSR_GP_CNTRL,
   98                               CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
   99 }
  100 
  101 static void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans)
  102 {
  103         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  104         int ret;
  105 
  106         trans_pcie->fw_reset_state = FW_RESET_REQUESTED;
  107 
  108         if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
  109                 iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER,
  110                                     UREG_NIC_SET_NMI_DRIVER_RESET_HANDSHAKE);
  111         else if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210)
  112                 iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
  113                                     UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE);
  114         else
  115                 iwl_write32(trans, CSR_DOORBELL_VECTOR,
  116                             UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE);
  117 
  118         /* wait 200ms */
  119         ret = wait_event_timeout(trans_pcie->fw_reset_waitq,
  120                                  trans_pcie->fw_reset_state != FW_RESET_REQUESTED,
  121                                  FW_RESET_TIMEOUT);
  122         if (!ret || trans_pcie->fw_reset_state == FW_RESET_ERROR) {
  123                 IWL_INFO(trans,
  124                          "firmware didn't ACK the reset - continue anyway\n");
  125                 iwl_trans_fw_error(trans, true);
  126         }
  127 
  128         trans_pcie->fw_reset_state = FW_RESET_IDLE;
  129 }
  130 
  131 void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
  132 {
  133         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  134 
  135         lockdep_assert_held(&trans_pcie->mutex);
  136 
  137         if (trans_pcie->is_down)
  138                 return;
  139 
  140         if (trans->state >= IWL_TRANS_FW_STARTED)
  141                 if (trans_pcie->fw_reset_handshake)
  142                         iwl_trans_pcie_fw_reset_handshake(trans);
  143 
  144         trans_pcie->is_down = true;
  145 
  146         /* tell the device to stop sending interrupts */
  147         iwl_disable_interrupts(trans);
  148 
  149         /* device going down, Stop using ICT table */
  150         iwl_pcie_disable_ict(trans);
  151 
  152         /*
  153          * If a HW restart happens during firmware loading,
  154          * then the firmware loading might call this function
  155          * and later it might be called again due to the
  156          * restart. So don't process again if the device is
  157          * already dead.
  158          */
  159         if (test_and_clear_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
  160                 IWL_DEBUG_INFO(trans,
  161                                "DEVICE_ENABLED bit was set and is now cleared\n");
  162                 iwl_txq_gen2_tx_free(trans);
  163                 iwl_pcie_rx_stop(trans);
  164         }
  165 
  166         iwl_pcie_ctxt_info_free_paging(trans);
  167         if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
  168                 iwl_pcie_ctxt_info_gen3_free(trans, false);
  169         else
  170                 iwl_pcie_ctxt_info_free(trans);
  171 
  172         /* Stop the device, and put it in low power state */
  173         iwl_pcie_gen2_apm_stop(trans, false);
  174 
  175         /* re-take ownership to prevent other users from stealing the device */
  176         iwl_trans_sw_reset(trans, true);
  177 
  178         /*
  179          * Upon stop, the IVAR table gets erased, so msi-x won't
  180          * work. This causes a bug in RF-KILL flows, since the interrupt
  181          * that enables radio won't fire on the correct irq, and the
  182          * driver won't be able to handle the interrupt.
  183          * Configure the IVAR table again after reset.
  184          */
  185         iwl_pcie_conf_msix_hw(trans_pcie);
  186 
  187         /*
  188          * Upon stop, the APM issues an interrupt if HW RF kill is set.
  189          * This is a bug in certain verions of the hardware.
  190          * Certain devices also keep sending HW RF kill interrupt all
  191          * the time, unless the interrupt is ACKed even if the interrupt
  192          * should be masked. Re-ACK all the interrupts here.
  193          */
  194         iwl_disable_interrupts(trans);
  195 
  196         /* clear all status bits */
  197         clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
  198         clear_bit(STATUS_INT_ENABLED, &trans->status);
  199         clear_bit(STATUS_TPOWER_PMI, &trans->status);
  200 
  201         /*
  202          * Even if we stop the HW, we still want the RF kill
  203          * interrupt
  204          */
  205         iwl_enable_rfkill_int(trans);
  206 }
  207 
  208 void iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans)
  209 {
  210         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  211         bool was_in_rfkill;
  212 
  213         iwl_op_mode_time_point(trans->op_mode,
  214                                IWL_FW_INI_TIME_POINT_HOST_DEVICE_DISABLE,
  215                                NULL);
  216 
  217         mutex_lock(&trans_pcie->mutex);
  218         trans_pcie->opmode_down = true;
  219         was_in_rfkill = test_bit(STATUS_RFKILL_OPMODE, &trans->status);
  220         _iwl_trans_pcie_gen2_stop_device(trans);
  221         iwl_trans_pcie_handle_stop_rfkill(trans, was_in_rfkill);
  222         mutex_unlock(&trans_pcie->mutex);
  223 }
  224 
  225 static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans)
  226 {
  227         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  228         int queue_size = max_t(u32, IWL_CMD_QUEUE_SIZE,
  229                                trans->cfg->min_txq_size);
  230 
  231         /* TODO: most of the logic can be removed in A0 - but not in Z0 */
  232         spin_lock_bh(&trans_pcie->irq_lock);
  233         iwl_pcie_gen2_apm_init(trans);
  234         spin_unlock_bh(&trans_pcie->irq_lock);
  235 
  236         iwl_op_mode_nic_config(trans->op_mode);
  237 
  238         /* Allocate the RX queue, or reset if it is already allocated */
  239         if (iwl_pcie_gen2_rx_init(trans))
  240                 return -ENOMEM;
  241 
  242         /* Allocate or reset and init all Tx and Command queues */
  243         if (iwl_txq_gen2_init(trans, trans->txqs.cmd.q_id, queue_size))
  244                 return -ENOMEM;
  245 
  246         /* enable shadow regs in HW */
  247         iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF);
  248         IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n");
  249 
  250         return 0;
  251 }
  252 
  253 static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
  254 {
  255         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  256         char *buf = trans_pcie->rf_name;
  257         size_t buflen = sizeof(trans_pcie->rf_name);
  258         size_t pos;
  259         u32 version;
  260 
  261         if (buf[0])
  262                 return;
  263 
  264         switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
  265         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF):
  266                 pos = scnprintf(buf, buflen, "JF");
  267                 break;
  268         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF):
  269                 pos = scnprintf(buf, buflen, "GF");
  270                 break;
  271         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_GF4):
  272                 pos = scnprintf(buf, buflen, "GF4");
  273                 break;
  274         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
  275                 pos = scnprintf(buf, buflen, "HR");
  276                 break;
  277         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
  278                 pos = scnprintf(buf, buflen, "HR1");
  279                 break;
  280         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
  281                 pos = scnprintf(buf, buflen, "HRCDB");
  282                 break;
  283         default:
  284                 return;
  285         }
  286 
  287         switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) {
  288         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR):
  289         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1):
  290         case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB):
  291                 version = iwl_read_prph(trans, CNVI_MBOX_C);
  292                 switch (version) {
  293                 case 0x20000:
  294                         pos += scnprintf(buf + pos, buflen - pos, " B3");
  295                         break;
  296                 case 0x120000:
  297                         pos += scnprintf(buf + pos, buflen - pos, " B5");
  298                         break;
  299                 default:
  300                         pos += scnprintf(buf + pos, buflen - pos,
  301                                          " (0x%x)", version);
  302                         break;
  303                 }
  304                 break;
  305         default:
  306                 break;
  307         }
  308 
  309         pos += scnprintf(buf + pos, buflen - pos, ", rfid=0x%x",
  310                          trans->hw_rf_id);
  311 
  312         IWL_INFO(trans, "Detected RF %s\n", buf);
  313 
  314         /*
  315          * also add a \n for debugfs - need to do it after printing
  316          * since our IWL_INFO machinery wants to see a static \n at
  317          * the end of the string
  318          */
  319         pos += scnprintf(buf + pos, buflen - pos, "\n");
  320 }
  321 
  322 void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
  323 {
  324         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  325 
  326         iwl_pcie_reset_ict(trans);
  327 
  328         /* make sure all queue are not stopped/used */
  329         memset(trans->txqs.queue_stopped, 0,
  330                sizeof(trans->txqs.queue_stopped));
  331         memset(trans->txqs.queue_used, 0, sizeof(trans->txqs.queue_used));
  332 
  333         /* now that we got alive we can free the fw image & the context info.
  334          * paging memory cannot be freed included since FW will still use it
  335          */
  336         if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
  337                 iwl_pcie_ctxt_info_gen3_free(trans, true);
  338         else
  339                 iwl_pcie_ctxt_info_free(trans);
  340 
  341         /*
  342          * Re-enable all the interrupts, including the RF-Kill one, now that
  343          * the firmware is alive.
  344          */
  345         iwl_enable_interrupts(trans);
  346         mutex_lock(&trans_pcie->mutex);
  347         iwl_pcie_check_hw_rf_kill(trans);
  348 
  349         iwl_pcie_get_rf_name(trans);
  350         mutex_unlock(&trans_pcie->mutex);
  351 }
  352 
  353 static void iwl_pcie_set_ltr(struct iwl_trans *trans)
  354 {
  355         u32 ltr_val = CSR_LTR_LONG_VAL_AD_NO_SNOOP_REQ |
  356                       u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
  357                                       CSR_LTR_LONG_VAL_AD_NO_SNOOP_SCALE) |
  358                       u32_encode_bits(250,
  359                                       CSR_LTR_LONG_VAL_AD_NO_SNOOP_VAL) |
  360                       CSR_LTR_LONG_VAL_AD_SNOOP_REQ |
  361                       u32_encode_bits(CSR_LTR_LONG_VAL_AD_SCALE_USEC,
  362                                       CSR_LTR_LONG_VAL_AD_SNOOP_SCALE) |
  363                       u32_encode_bits(250, CSR_LTR_LONG_VAL_AD_SNOOP_VAL);
  364 
  365         /*
  366          * To workaround hardware latency issues during the boot process,
  367          * initialize the LTR to ~250 usec (see ltr_val above).
  368          * The firmware initializes this again later (to a smaller value).
  369          */
  370         if ((trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210 ||
  371              trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) &&
  372             !trans->trans_cfg->integrated) {
  373                 iwl_write32(trans, CSR_LTR_LONG_VAL_AD, ltr_val);
  374         } else if (trans->trans_cfg->integrated &&
  375                    trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22000) {
  376                 iwl_write_prph(trans, HPM_MAC_LTR_CSR, HPM_MAC_LRT_ENABLE_ALL);
  377                 iwl_write_prph(trans, HPM_UMAC_LTR, ltr_val);
  378         }
  379 }
  380 
  381 int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
  382                                  const struct fw_img *fw, bool run_in_rfkill)
  383 {
  384         struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
  385         bool hw_rfkill;
  386         int ret;
  387 
  388         /* This may fail if AMT took ownership of the device */
  389         if (iwl_pcie_prepare_card_hw(trans)) {
  390                 IWL_WARN(trans, "Exit HW not ready\n");
  391                 return -EIO;
  392         }
  393 
  394         iwl_enable_rfkill_int(trans);
  395 
  396         iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
  397 
  398         /*
  399          * We enabled the RF-Kill interrupt and the handler may very
  400          * well be running. Disable the interrupts to make sure no other
  401          * interrupt can be fired.
  402          */
  403         iwl_disable_interrupts(trans);
  404 
  405         /* Make sure it finished running */
  406         iwl_pcie_synchronize_irqs(trans);
  407 
  408         mutex_lock(&trans_pcie->mutex);
  409 
  410         /* If platform's RF_KILL switch is NOT set to KILL */
  411         hw_rfkill = iwl_pcie_check_hw_rf_kill(trans);
  412         if (hw_rfkill && !run_in_rfkill) {
  413                 ret = -ERFKILL;
  414                 goto out;
  415         }
  416 
  417         /* Someone called stop_device, don't try to start_fw */
  418         if (trans_pcie->is_down) {
  419                 IWL_WARN(trans,
  420                          "Can't start_fw since the HW hasn't been started\n");
  421                 ret = -EIO;
  422                 goto out;
  423         }
  424 
  425         /* make sure rfkill handshake bits are cleared */
  426         iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
  427         iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
  428                     CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
  429 
  430         /* clear (again), then enable host interrupts */
  431         iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
  432 
  433         ret = iwl_pcie_gen2_nic_init(trans);
  434         if (ret) {
  435                 IWL_ERR(trans, "Unable to init nic\n");
  436                 goto out;
  437         }
  438 
  439         if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
  440                 ret = iwl_pcie_ctxt_info_gen3_init(trans, fw);
  441         else
  442                 ret = iwl_pcie_ctxt_info_init(trans, fw);
  443         if (ret)
  444                 goto out;
  445 
  446         iwl_pcie_set_ltr(trans);
  447 
  448         if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) {
  449                 iwl_write32(trans, CSR_FUNC_SCRATCH, CSR_FUNC_SCRATCH_INIT_VALUE);
  450                 iwl_set_bit(trans, CSR_GP_CNTRL,
  451                             CSR_GP_CNTRL_REG_FLAG_ROM_START);
  452         } else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
  453                 iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1);
  454         } else {
  455                 iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1);
  456         }
  457 
  458         /* re-check RF-Kill state since we may have missed the interrupt */
  459         hw_rfkill = iwl_pcie_check_hw_rf_kill(trans);
  460         if (hw_rfkill && !run_in_rfkill)
  461                 ret = -ERFKILL;
  462 
  463 out:
  464         mutex_unlock(&trans_pcie->mutex);
  465         return ret;
  466 }

Cache object: edc92bf6a7506286f9a11d1427b62b0c


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