/** * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; int ret = 0; u32 errcnt = 0; u32 i; IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { ret = -EIO; errcnt++; if (errcnt >= 3) break; } } return ret; }
static int iwl_send_phy_db_cmd(struct iwl_phy_db *phy_db, u16 type, u16 length, void *data) { struct iwl_phy_db_cmd phy_db_cmd; struct iwl_host_cmd cmd = { .id = PHY_DB_CMD, }; IWL_DEBUG_INFO(phy_db->trans, "Sending PHY-DB hcmd of type %d, of length %d\n", type, length); /* Set phy db cmd variables */ phy_db_cmd.type = cpu_to_le16(type); phy_db_cmd.length = cpu_to_le16(length); /* Set hcmd variables */ cmd.data[0] = &phy_db_cmd; cmd.len[0] = sizeof(struct iwl_phy_db_cmd); cmd.data[1] = data; cmd.len[1] = length; cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; return iwl_trans_send_cmd(phy_db->trans, &cmd); }
static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) { union acpi_object *limits, *domain_type, *power_limit; if (splx->type != ACPI_TYPE_PACKAGE || splx->package.count != 2 || splx->package.elements[0].type != ACPI_TYPE_INTEGER || splx->package.elements[0].integer.value != 0) { IWL_ERR(trans, "Unsupported splx structure\n"); return 0; } limits = &splx->package.elements[1]; if (limits->type != ACPI_TYPE_PACKAGE || limits->package.count < 2 || limits->package.elements[0].type != ACPI_TYPE_INTEGER || limits->package.elements[1].type != ACPI_TYPE_INTEGER) { IWL_ERR(trans, "Invalid limits element\n"); return 0; } domain_type = &limits->package.elements[0]; power_limit = &limits->package.elements[1]; if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { IWL_DEBUG_INFO(trans, "WiFi power is not limited\n"); return 0; } return power_limit->integer.value; }
static int iwl_phy_db_get_section_data(struct iwl_phy_db *phy_db, u32 type, u8 **data, u16 *size, u16 ch_id) { struct iwl_phy_db_entry *entry; u16 ch_group_id = 0; if (!phy_db) return -EINVAL; /* find wanted channel group */ if (type == IWL_PHY_DB_CALIB_CHG_PAPD) ch_group_id = channel_id_to_papd(ch_id); else if (type == IWL_PHY_DB_CALIB_CHG_TXP) ch_group_id = channel_id_to_txp(phy_db, ch_id); entry = iwl_phy_db_get_section(phy_db, type, ch_group_id); if (!entry) return -EINVAL; *data = entry->data; *size = entry->size; IWL_DEBUG_INFO(phy_db->trans, "%s(%d): [PHYDB] GET: Type %d , Size: %d\n", __func__, __LINE__, type, *size); return 0; }
static void iwlagn_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { int ret; if (!ctx->is_active) return; ctx->qos_data.def_qos_parm.qos_flags = 0; if (ctx->qos_data.qos_active) ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_UPDATE_EDCA_MSK; if (ctx->ht.enabled) ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", ctx->qos_data.qos_active, ctx->qos_data.def_qos_parm.qos_flags); ret = iwl_dvm_send_cmd_pdu(priv, ctx->qos_cmd, CMD_SYNC, sizeof(struct iwl_qosparam_cmd), &ctx->qos_data.def_qos_parm); if (ret) IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n"); }
static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* * TODO: Bits 7-8 of CSR in 8000 HW family set the ADC sampling, and * shouldn't be set to any non-zero value. The same is supposed to be * true of the other HW, but unsetting them (such as the 7260) causes * automatic tests to fail on seemingly unrelated errors. Need to * further investigate this, but for now we'll separate cases. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); }
int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; struct iwl_priv *priv = hw->priv; int result; u32 cmd; if (cb->args[3]) { /* offset by 1 since commands start at 0 */ cmd = cb->args[3] - 1; } else { result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len, iwl_testmode_gnl_msg_policy); if (result) { IWL_DEBUG_INFO(priv, "Error parsing the gnl message : %d\n", result); return result; } /* IWL_TM_ATTR_COMMAND is absolutely mandatory */ if (!tb[IWL_TM_ATTR_COMMAND]) { IWL_DEBUG_INFO(priv, "Error finding testmode command type\n"); return -ENOMSG; } cmd = nla_get_u32(tb[IWL_TM_ATTR_COMMAND]); cb->args[3] = cmd + 1; } /* in case multiple accesses to the device happens */ mutex_lock(&priv->shrd->mutex); switch (cmd) { case IWL_TM_CMD_APP2DEV_READ_TRACE: IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); result = iwl_testmode_trace_dump(hw, tb, skb, cb); break; default: result = -EINVAL; break; } mutex_unlock(&priv->shrd->mutex); return result; }
void iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; IWL_DEBUG_INFO(mvm, "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", le32_to_cpu(mfuart_notif->installed_ver), le32_to_cpu(mfuart_notif->external_ver), le32_to_cpu(mfuart_notif->status), le32_to_cpu(mfuart_notif->duration)); if (iwl_rx_packet_payload_len(pkt) == sizeof(*mfuart_notif)) IWL_DEBUG_INFO(mvm, "MFUART: image size: 0x%08x\n", le32_to_cpu(mfuart_notif->image_size)); }
static int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { int ret; s8 prev_tx_power; bool defer; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; if (priv->calib_disabled & IWL_TX_POWER_CALIB_DISABLED) return 0; lockdep_assert_held(&priv->mutex); if (priv->tx_power_user_lmt == tx_power && !force) return 0; if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", tx_power, IWLAGN_TX_POWER_TARGET_POWER_MIN); return -EINVAL; } if (tx_power > DIV_ROUND_UP(priv->nvm_data->max_tx_pwr_half_dbm, 2)) { IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", tx_power, priv->nvm_data->max_tx_pwr_half_dbm); return -EINVAL; } if (!iwl_is_ready_rf(priv)) return -EIO; /* scan complete and commit_rxon use tx_power_next value, * it always need to be updated for newest request */ priv->tx_power_next = tx_power; /* do not set tx power when scanning or channel changing */ defer = test_bit(STATUS_SCANNING, &priv->status) || memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); if (defer && !force) { IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); return 0; } prev_tx_power = priv->tx_power_user_lmt; priv->tx_power_user_lmt = tx_power; ret = iwlagn_send_tx_power(priv); /* if fail to set tx_power, restore the orig. tx power */ if (ret) { priv->tx_power_user_lmt = prev_tx_power; priv->tx_power_next = prev_tx_power; } return ret; }
/** * iwl_add_station_common - */ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, const u8 *addr, bool is_ap, struct ieee80211_sta *sta, u8 *sta_id_r) { unsigned long flags_spin; int ret = 0; u8 sta_id; struct iwl_addsta_cmd sta_cmd; *sta_id_r = 0; spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta); if (sta_id == IWL_INVALID_STATION) { IWL_ERR(priv, "Unable to prepare station %pM for addition\n", addr); spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); return -EINVAL; } /* * uCode is not able to deal with multiple requests to add a * station. Keep track if one is in progress so that we do not send * another. */ if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { IWL_DEBUG_INFO(priv, "STA %d already in process of being " "added.\n", sta_id); spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); return -EEXIST; } if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " "adding again.\n", sta_id, addr); spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); return -EEXIST; } priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); /* Add station to device's station table */ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); if (ret) { spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); IWL_ERR(priv, "Adding station %pM failed.\n", priv->stations[sta_id].sta.sta.addr); priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); } *sta_id_r = sta_id; return ret; }
/** * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ int iwl_verify_ucode(struct iwl_priv *priv) { __le32 *image; u32 len; int ret; /* Try bootstrap */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); return 0; } /* Try initialize */ image = (__le32 *)priv->ucode_init.v_addr; len = priv->ucode_init.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); return 0; } /* Try runtime/protocol */ image = (__le32 *)priv->ucode_code.v_addr; len = priv->ucode_code.len; ret = iwlcore_verify_inst_sparse(priv, image, len); if (!ret) { IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); return 0; } IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); /* Since nothing seems to match, show first several data entries in * instruction SRAM, so maybe visual inspection will give a clue. * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; ret = iwl_verify_inst_full(priv, image, len); return ret; }
/* * This function handles the user application switch ucode ownership. * * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_OWNER and * decide who the current owner of the uCode * * If the current owner is OWNERSHIP_TM, then the only host command * can deliver to uCode is from testmode, all the other host commands * will dropped. * * default driver is the owner of uCode in normal operational mode * * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = hw->priv; u8 owner; if (!tb[IWL_TM_ATTR_UCODE_OWNER]) { IWL_DEBUG_INFO(priv, "Error finding ucode owner\n"); return -ENOMSG; } owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]); if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) priv->shrd->ucode_owner = owner; else { IWL_DEBUG_INFO(priv, "Invalid owner\n"); return -EINVAL; } return 0; }
/** * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim * * If an Rx buffer has an async callback associated with it the callback * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); int cmd_index; struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced * in the queue management code. */ if (WARN(txq_id != priv->cmd_queue, "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n", txq_id, priv->cmd_queue, sequence, priv->txq[priv->cmd_queue].q.read_ptr, priv->txq[priv->cmd_queue].q.write_ptr)) { iwl_print_hex_error(priv, pkt, 32); return; } cmd_index = get_cmd_index(&txq->q, index); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; txq->time_stamp = jiffies; iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); rxb->page = NULL; } else if (meta->callback) meta->callback(priv, cmd, pkt); spin_lock_irqsave(&priv->hcmd_lock, flags); iwl_hcmd_queue_reclaim(priv, txq_id, index); if (!(meta->flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } meta->flags = 0; spin_unlock_irqrestore(&priv->hcmd_lock, flags); }
/** * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; u32 save_len = len; int ret = 0; u32 errcnt; IWL_DEBUG_INFO("ucode inst image size is %u\n", len); ret = iwl_grab_nic_access(priv); if (ret) return ret; iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); errcnt = 0; for (; len > 0; len -= sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERROR("uCode INST section is invalid at " "offset 0x%x, is 0x%x, s/b 0x%x\n", save_len - len, val, le32_to_cpu(*image)); ret = -EIO; errcnt++; if (errcnt >= 20) break; } } iwl_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO ("ucode image in INSTRUCTION memory is good\n"); return ret; }
void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rb_allocator *rba = &trans_pcie->rba; /*if rxq->bd is NULL, it means that nothing has been allocated, * exit now */ if (!rxq->bd) { IWL_DEBUG_INFO(trans, "Free NULL rx context\n"); return; } cancel_work_sync(&rba->rx_alloc); if (rba->alloc_wq) { destroy_workqueue(rba->alloc_wq); rba->alloc_wq = NULL; } spin_lock(&rba->lock); iwl_pcie_rx_free_rba(trans); spin_unlock(&rba->lock); spin_lock(&rxq->lock); iwl_pcie_rxq_free_rbs(trans); spin_unlock(&rxq->lock); dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); rxq->bd_dma = 0; rxq->bd = NULL; if (rxq->rb_stts) dma_free_coherent(trans->dev, sizeof(struct iwl_rb_status), rxq->rb_stts, rxq->rb_stts_dma); else IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); rxq->rb_stts_dma = 0; rxq->rb_stts = NULL; }
/* * ucode */ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, struct fw_desc *image, u32 dst_addr) { dma_addr_t phy_addr = image->p_addr; u32 byte_cnt = image->len; int ret; priv->ucode_write_complete = 0; iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); iwl_write_direct32(priv, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); iwl_write_direct32(priv, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); iwl_write_direct32(priv, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); iwl_write_direct32(priv, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name); ret = wait_event_interruptible_timeout(priv->wait_command_queue, priv->ucode_write_complete, 5 * HZ); if (ret == -ERESTARTSYS) { IWL_ERR(priv, "Could not load the %s uCode section due " "to interrupt\n", name); return ret; } if (!ret) { IWL_ERR(priv, "Could not load the %s uCode section\n", name); return -ETIMEDOUT; } return 0; }
static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash; u32 reg_val = 0; radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >> FW_PHY_CFG_RADIO_TYPE_POS; radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >> FW_PHY_CFG_RADIO_STEP_POS; radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >> FW_PHY_CFG_RADIO_DASH_POS; /* SKU control */ reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_STEP; reg_val |= CSR_HW_REV_DASH(mvm->trans->hw_rev) << CSR_HW_IF_CONFIG_REG_POS_MAC_DASH; /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; reg_val |= radio_cfg_step << CSR_HW_IF_CONFIG_REG_POS_PHY_STEP; reg_val |= radio_cfg_dash << CSR_HW_IF_CONFIG_REG_POS_PHY_DASH; WARN_ON((radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE) & ~CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE); /* silicon bits */ reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; iwl_trans_set_bits_mask(mvm->trans, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_MSK_MAC_DASH | CSR_HW_IF_CONFIG_REG_MSK_MAC_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_TYPE | CSR_HW_IF_CONFIG_REG_MSK_PHY_STEP | CSR_HW_IF_CONFIG_REG_MSK_PHY_DASH | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI, reg_val); IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); /* * W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), causing ME FW * to lose ownership and not being able to obtain it back. */ if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); }
/** * is_lq_table_valid() - Test one aspect of LQ cmd for validity * * It sometimes happens when a HT rate has been in use and we * loose connectivity with AP then mac80211 will first tell us that the * current channel is not HT anymore before removing the station. In such a * scenario the RXON flags will be updated to indicate we are not * communicating HT anymore, but the LQ command may still contain HT rates. * Test for this to prevent driver from sending LQ command between the time * RXON flags are updated and when LQ command is updated. */ static bool is_lq_table_valid(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct iwl_link_quality_cmd *lq) { int i; if (ctx->ht.enabled) return true; IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n", ctx->active.channel); for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) { IWL_DEBUG_INFO(priv, "index %d of LQ expects HT channel\n", i); return false; } } return true; }
int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) { u32 stat_flags = 0; struct iwl_host_cmd cmd = { .id = REPLY_STATISTICS_CMD, .meta.flags = flags, .len = sizeof(stat_flags), .data = (u8 *) &stat_flags, }; return iwl_send_cmd(priv, &cmd); } EXPORT_SYMBOL(iwl_send_statistics_request); /** * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) { u32 val; int ret = 0; u32 errcnt = 0; u32 i; IWL_DEBUG_INFO("ucode inst image size is %u\n", len); ret = iwl_grab_nic_access(priv); if (ret) return ret; for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + RTC_INST_LOWER_BOUND); val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { ret = -EIO; errcnt++; if (errcnt >= 3) break; } } iwl_release_nic_access(priv); return ret; }
void iwlagn_dev_txfifo_flush(struct iwl_priv *priv) { mutex_lock(&priv->mutex); ieee80211_stop_queues(priv->hw); if (iwlagn_txfifo_flush(priv, 0)) { IWL_ERR(priv, "flush request fail\n"); goto done; } IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n"); iwl_trans_wait_tx_queue_empty(priv->trans, 0xffffffff); done: ieee80211_wake_queues(priv->hw); mutex_unlock(&priv->mutex); }
/** * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, struct iwl_rx_queue *q) { unsigned long flags; u32 reg; spin_lock_irqsave(&q->lock, flags); if (q->need_update == 0) goto exit_unlock; if (trans->cfg->base_params->shadow_reg_enable) { /* shadow register enabled */ /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); } else { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_TPOWER_PMI, &trans_pcie->status)) { reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup," " GP1 = 0x%x\n", reg); iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; } q->write_actual = (q->write & ~0x7); iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); /* Else device is assumed to be awake */ } else { /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); iwl_write_direct32(trans, FH_RSCSR_CHNL0_WPTR, q->write_actual); } } q->need_update = 0; exit_unlock: spin_unlock_irqrestore(&q->lock, flags); }
int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_radio_version_notif *radio_version = (void *)pkt->data; /* TODO: what to do with that? */ IWL_DEBUG_INFO(mvm, "Radio version: flavor: 0x%08x, step 0x%08x, dash 0x%08x\n", le32_to_cpu(radio_version->radio_flavor), le32_to_cpu(radio_version->radio_step), le32_to_cpu(radio_version->radio_dash)); return 0; }
static void iwl5000_init_alive_start(struct iwl_priv *priv) { int ret = 0; /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { /* We had an error bringing up the hardware, so take it * all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n"); goto restart; } /* initialize uCode was loaded... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ if (iwl_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); goto restart; } iwl_clear_stations_table(priv); ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); goto restart; } iwl5000_send_calib_cfg(priv); return; restart: /* real restart (first load init_ucode) */ queue_work(priv->workqueue, &priv->restart); }
static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) { acpi_handle pxsx_handle; acpi_handle handle; struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; #if 0 /* Not in RHEL */ pxsx_handle = ACPI_HANDLE(&pdev->dev); #else pxsx_handle = DEVICE_ACPI_HANDLE(&pdev->dev); #endif if (!pxsx_handle) { IWL_DEBUG_INFO(trans, "Could not retrieve root port ACPI handle\n"); return; } /* Get the method's handle */ status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); if (ACPI_FAILURE(status)) { IWL_DEBUG_INFO(trans, "SPL method not found\n"); return; } /* Call SPLC with no arguments */ status = acpi_evaluate_object(handle, NULL, NULL, &splx); if (ACPI_FAILURE(status)) { IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status); return; } trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n", trans->dflt_pwr_limit); kfree(splx.pointer); }
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mfuart_load_notif *mfuart_notif = (void *)pkt->data; IWL_DEBUG_INFO(mvm, "MFUART: installed ver: 0x%08x, external ver: 0x%08x, status: 0x%08x, duration: 0x%08x\n", le32_to_cpu(mfuart_notif->installed_ver), le32_to_cpu(mfuart_notif->external_ver), le32_to_cpu(mfuart_notif->status), le32_to_cpu(mfuart_notif->duration)); return 0; }
void iwlagn_init_alive_start(struct iwl_priv *priv) { int ret = 0; /* initialize uCode was loaded... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ if (iwl_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); goto restart; } ret = priv->cfg->ops->lib->alive_notify(priv); if (ret) { IWL_WARN(priv, "Could not complete ALIVE transition: %d\n", ret); goto restart; } if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { /* * Tell uCode we are ready to perform calibration * need to perform this before any calibration * no need to close the envlope since we are going * to load the runtime uCode later. */ iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); } iwlagn_send_calib_cfg(priv); /** * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ if (priv->cfg->need_temp_offset_calib) iwlagn_set_temperature_offset_calib(priv); return; restart: /* real restart (first load init_ucode) */ queue_work(priv->workqueue, &priv->restart); }
/* Note: returns poll_bit return value, which is >= 0 if success */ static int iwl_set_hw_ready(struct iwl_priv *priv) { int ret; iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); /* See if we got it */ ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); return ret; }
static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif) { WARN_ON(!mutex_is_locked(&priv->mutex)); IWL_DEBUG_INFO(priv, "Starting scan...\n"); set_bit(STATUS_SCANNING, &priv->status); priv->is_internal_short_scan = false; priv->scan_start = jiffies; if (WARN_ON(!priv->cfg->ops->utils->request_scan)) return -EOPNOTSUPP; priv->cfg->ops->utils->request_scan(priv, vif); return 0; }
/* * This function handles the user application commands for SRAM data dump * * It retrieves the mandatory fields IWL_TM_ATTR_SRAM_ADDR and * IWL_TM_ATTR_SRAM_SIZE to decide the memory area for SRAM data reading * * Several error will be retured, -EBUSY if the SRAM data retrieved by * previous command has not been delivered to userspace, or -ENOMSG if * the mandatory fields (IWL_TM_ATTR_SRAM_ADDR,IWL_TM_ATTR_SRAM_SIZE) * are missing, or -ENOMEM if the buffer allocation fails. * * Otherwise 0 is replied indicating the success of the SRAM reading. * * @hw: ieee80211_hw object that represents the device * @tb: gnl message fields from the user space */ static int iwl_testmode_sram(struct ieee80211_hw *hw, struct nlattr **tb) { struct iwl_priv *priv = hw->priv; u32 base, ofs, size, maxsize; if (priv->testmode_sram.sram_readed) return -EBUSY; if (!tb[IWL_TM_ATTR_SRAM_ADDR]) { IWL_DEBUG_INFO(priv, "Error finding SRAM offset address\n"); return -ENOMSG; } ofs = nla_get_u32(tb[IWL_TM_ATTR_SRAM_ADDR]); if (!tb[IWL_TM_ATTR_SRAM_SIZE]) { IWL_DEBUG_INFO(priv, "Error finding size for SRAM reading\n"); return -ENOMSG; } size = nla_get_u32(tb[IWL_TM_ATTR_SRAM_SIZE]); switch (priv->shrd->ucode_type) { case IWL_UCODE_REGULAR: maxsize = trans(priv)->ucode_rt.data.len; break; case IWL_UCODE_INIT: maxsize = trans(priv)->ucode_init.data.len; break; case IWL_UCODE_WOWLAN: maxsize = trans(priv)->ucode_wowlan.data.len; break; case IWL_UCODE_NONE: IWL_DEBUG_INFO(priv, "Error, uCode does not been loaded\n"); return -ENOSYS; default: IWL_DEBUG_INFO(priv, "Error, unsupported uCode type\n"); return -ENOSYS; } if ((ofs + size) > maxsize) { IWL_DEBUG_INFO(priv, "Invalid offset/size: out of range\n"); return -EINVAL; } priv->testmode_sram.buff_size = (size / 4) * 4; priv->testmode_sram.buff_addr = kmalloc(priv->testmode_sram.buff_size, GFP_KERNEL); if (priv->testmode_sram.buff_addr == NULL) { IWL_DEBUG_INFO(priv, "Error allocating memory\n"); return -ENOMEM; } base = 0x800000; _iwl_read_targ_mem_words(bus(priv), base + ofs, priv->testmode_sram.buff_addr, priv->testmode_sram.buff_size / 4); priv->testmode_sram.num_chunks = DIV_ROUND_UP(priv->testmode_sram.buff_size, DUMP_CHUNK_SIZE); priv->testmode_sram.sram_readed = true; return 0; }
int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, bool force) { int ret; bool update_chains; lockdep_assert_held(&priv->mutex); /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) return 0; if (!iwl_is_ready_rf(priv)) return -EIO; /* scan complete use sleep_power_next, need to be updated */ memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); if (test_bit(STATUS_SCANNING, &priv->status) && !force) { IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n"); return 0; } if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) set_bit(STATUS_POWER_PMI, &priv->status); ret = iwl_set_power(priv, cmd); if (!ret) { if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) clear_bit(STATUS_POWER_PMI, &priv->status); if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); else if (priv->cfg->ops->lib->update_chain_flags) IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)); } else IWL_ERR(priv, "set power fail, ret = %d", ret); return ret; }