static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) { int i; struct iwl_rss_config_cmd cmd = { .flags = cpu_to_le32(IWL_RSS_ENABLE), .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | IWL_RSS_HASH_TYPE_IPV4_UDP | IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | IWL_RSS_HASH_TYPE_IPV6_TCP | IWL_RSS_HASH_TYPE_IPV6_UDP | IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, }; if (mvm->trans->num_rx_queues == 1) return 0; /* Do not direct RSS traffic to Q 0 which is our fallback queue */ for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) cmd.indirection_table[i] = 1 + (i % (mvm->trans->num_rx_queues - 1)); netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); } static int iwl_configure_rxq(struct iwl_mvm *mvm) { int i, num_queues, size; struct iwl_rfh_queue_config *cmd; /* Do not configure default queue, it is configured via context info */ num_queues = mvm->trans->num_rx_queues - 1; size = sizeof(*cmd) + num_queues * sizeof(struct iwl_rfh_queue_data); cmd = kzalloc(size, GFP_KERNEL); if (!cmd) return -ENOMEM; cmd->num_queues = num_queues; for (i = 0; i < num_queues; i++) { struct iwl_trans_rxq_dma_data data; cmd->data[i].q_num = i + 1; iwl_trans_get_rxq_dma_data(mvm->trans, i + 1, &data); cmd->data[i].fr_bd_cb = cpu_to_le64(data.fr_bd_cb); cmd->data[i].urbd_stts_wrptr = cpu_to_le64(data.urbd_stts_wrptr); cmd->data[i].ur_bd_cb = cpu_to_le64(data.ur_bd_cb); cmd->data[i].fr_bd_wid = cpu_to_le32(data.fr_bd_wid); } return iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(DATA_PATH_GROUP, RFH_QUEUE_CONFIG_CMD), 0, size, cmd); }
static int iwl_mvm_send_add_sta_cmd(struct iwl_mvm *mvm, u32 flags, struct iwl_mvm_add_sta_cmd_v6 *cmd) { struct iwl_mvm_add_sta_cmd_v5 cmd_v5; if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(*cmd), cmd); iwl_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5); return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(cmd_v5), &cmd_v5); }
static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; bool ba_enable; struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION) return 0; if (vif->p2p && !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS)) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); if (ret) return ret; ba_enable = !!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); }
int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, const u8 *data, u32 count) { struct iwl_rxq_sync_cmd *cmd; u32 data_size = sizeof(*cmd) + count; int ret; /* should be DWORD aligned */ if (WARN_ON(count & 3 || count > IWL_MULTI_QUEUE_SYNC_MSG_MAX_SIZE)) return -EINVAL; cmd = kzalloc(data_size, GFP_KERNEL); if (!cmd) return -ENOMEM; cmd->rxq_mask = cpu_to_le32(rxq_mask); cmd->count = cpu_to_le32(count); cmd->flags = 0; memcpy(cmd->payload, data, count); ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(DATA_PATH_GROUP, TRIGGER_RX_QUEUES_NOTIF_CMD), 0, data_size, cmd); kfree(cmd); return ret; }
static int _iwl_mvm_power_update_device(struct iwl_mvm *mvm, bool force_disable) { struct iwl_device_power_cmd cmd = { .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DEVICE_PS_CMD)) return 0; if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM || force_disable) cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); #ifdef CPTCFG_IWLWIFI_DEBUGFS if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : mvm->disable_power_off) cmd.flags &= cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif IWL_DEBUG_POWER(mvm, "Sending device power command with flags = 0x%X\n", cmd.flags); return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, sizeof(cmd), &cmd); }
static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, struct iwl_beacon_filter_cmd *cmd) { int ret; ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, CMD_SYNC, sizeof(struct iwl_beacon_filter_cmd), cmd); if (!ret) { IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", cmd->ba_enable_beacon_abort); IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", cmd->ba_escape_timer); IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", cmd->bf_debug_flag); IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", cmd->bf_enable_beacon_filter); IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", cmd->bf_energy_delta); IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", cmd->bf_escape_timer); IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", cmd->bf_roaming_energy_delta); IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", cmd->bf_roaming_state); IWL_DEBUG_POWER(mvm, "bf_temperature_delta is: %d\n", cmd->bf_temperature_delta); } return ret; }
static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, bool enable) { struct iwl_bt_coex_reduced_txp_update_cmd cmd = {}; struct iwl_mvm_sta *mvmsta; u32 value; int ret; mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) return 0; /* nothing to do */ if (mvmsta->bt_reduced_txpower == enable) return 0; value = mvmsta->sta_id; if (enable) value |= BT_REDUCED_TX_POWER_BIT; IWL_DEBUG_COEX(mvm, "%sable reduced Tx Power for sta %d\n", enable ? "en" : "dis", sta_id); cmd.reduced_txp = cpu_to_le32(value); mvmsta->bt_reduced_txpower = enable; ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_UPDATE_REDUCED_TXP, CMD_ASYNC, sizeof(cmd), &cmd); return ret; }
int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_powertable_cmd cmd = {}; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); if (!iwlwifi_mod_params.power_save) { IWL_DEBUG_POWER(mvm, "Power management is not allowed\n"); return 0; } if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); cmd.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY); IWL_DEBUG_POWER(mvm, "Sending power table command on mac id 0x%X for power level %d, flags = 0x%X\n", cmd.id_and_color, iwlmvm_mod_params.power_scheme, le16_to_cpu(cmd.flags)); return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, sizeof(cmd), &cmd); }
static int iwl_mvm_beacon_filter_send_cmd(struct iwl_mvm *mvm, struct iwl_beacon_filter_cmd *cmd, u32 flags) { IWL_DEBUG_POWER(mvm, "ba_enable_beacon_abort is: %d\n", le32_to_cpu(cmd->ba_enable_beacon_abort)); IWL_DEBUG_POWER(mvm, "ba_escape_timer is: %d\n", le32_to_cpu(cmd->ba_escape_timer)); IWL_DEBUG_POWER(mvm, "bf_debug_flag is: %d\n", le32_to_cpu(cmd->bf_debug_flag)); IWL_DEBUG_POWER(mvm, "bf_enable_beacon_filter is: %d\n", le32_to_cpu(cmd->bf_enable_beacon_filter)); IWL_DEBUG_POWER(mvm, "bf_energy_delta is: %d\n", le32_to_cpu(cmd->bf_energy_delta)); IWL_DEBUG_POWER(mvm, "bf_escape_timer is: %d\n", le32_to_cpu(cmd->bf_escape_timer)); IWL_DEBUG_POWER(mvm, "bf_roaming_energy_delta is: %d\n", le32_to_cpu(cmd->bf_roaming_energy_delta)); IWL_DEBUG_POWER(mvm, "bf_roaming_state is: %d\n", le32_to_cpu(cmd->bf_roaming_state)); IWL_DEBUG_POWER(mvm, "bf_temp_threshold is: %d\n", le32_to_cpu(cmd->bf_temp_threshold)); IWL_DEBUG_POWER(mvm, "bf_temp_fast_filter is: %d\n", le32_to_cpu(cmd->bf_temp_fast_filter)); IWL_DEBUG_POWER(mvm, "bf_temp_slow_filter is: %d\n", le32_to_cpu(cmd->bf_temp_slow_filter)); return iwl_mvm_send_cmd_pdu(mvm, REPLY_BEACON_FILTERING_CMD, flags, sizeof(struct iwl_beacon_filter_cmd), cmd); }
int iwl_mvm_power_update_device(struct iwl_mvm *mvm) { struct iwl_device_power_cmd cmd = { .flags = cpu_to_le16(DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK), }; if (iwlmvm_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) mvm->ps_disabled = true; if (mvm->ps_disabled) cmd.flags |= cpu_to_le16(DEVICE_POWER_FLAGS_CAM_MSK); #ifdef CONFIG_IWLWIFI_DEBUGFS if ((mvm->cur_ucode == IWL_UCODE_WOWLAN) ? mvm->disable_power_off_d3 : mvm->disable_power_off) cmd.flags &= cpu_to_le16(~DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif IWL_DEBUG_POWER(mvm, "Sending device power command with flags = 0x%X\n", cmd.flags); return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, 0, sizeof(cmd), &cmd); }
static int iwl_mvm_send_add_sta_key_cmd(struct iwl_mvm *mvm, u32 flags, struct iwl_mvm_add_sta_key_cmd *cmd, u32 mac_id_n_color) { struct iwl_mvm_add_sta_cmd_v5 sta_cmd; if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_STA_KEY_CMD) return iwl_mvm_send_cmd_pdu(mvm, ADD_STA_KEY, flags, sizeof(*cmd), cmd); iwl_mvm_add_sta_key_to_add_sta_cmd_v5(cmd, &sta_cmd, mac_id_n_color); return iwl_mvm_send_cmd_pdu(mvm, ADD_STA, flags, sizeof(sta_cmd), &sta_cmd); }
static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id) { u8 *ptr; int ret; int i; if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv), "Invalid configuration %d\n", conf_id)) return -EINVAL; if (!mvm->fw->dbg_conf_tlv[conf_id]) return -EINVAL; if (mvm->fw_dbg_conf != FW_DBG_INVALID) IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n", mvm->fw_dbg_conf); /* Send all HCMDs for configuring the FW debug */ ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd; for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0, le16_to_cpu(cmd->len), cmd->data); if (ret) return ret; ptr += sizeof(*cmd); ptr += le16_to_cpu(cmd->len); } mvm->fw_dbg_conf = conf_id; return ret; }
static int iwl_mvm_power_mac_update_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { int ret; bool ba_enable; struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; /* * TODO: The following vif_count verification is temporary condition. * Avoid power mode update if more than one interface is currently * active. Remove this condition when FW will support power management * on multiple MACs. */ IWL_DEBUG_POWER(mvm, "Currently %d interfaces active\n", mvm->vif_count); if (mvm->vif_count > 1) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_SYNC, sizeof(cmd), &cmd); if (ret) return ret; ba_enable = !!(cmd.flags & cpu_to_le16(POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK)); return iwl_mvm_update_beacon_abort(mvm, vif, ba_enable); }
static int iwl_mvm_power_mac_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; struct iwl_mvm_vif *mvmvif __maybe_unused = iwl_mvm_vif_from_mac80211(vif); if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) cmd.flags |= cpu_to_le16(POWER_FLAGS_POWER_SAVE_ENA_MSK); #ifdef CPTCFG_IWLWIFI_DEBUGFS if (mvmvif->dbgfs_pm.mask & MVM_DEBUGFS_PM_DISABLE_POWER_OFF && mvmvif->dbgfs_pm.disable_power_off) cmd.flags &= cpu_to_le16(~POWER_FLAGS_POWER_SAVE_ENA_MSK); #endif iwl_mvm_power_log(mvm, &cmd); return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, CMD_ASYNC, sizeof(cmd), &cmd); }
static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id, enum iwl_sf_state new_state) { struct iwl_sf_cfg_cmd sf_cmd = { .state = cpu_to_le32(SF_FULL_ON), }; struct ieee80211_sta *sta; int ret = 0; if (IWL_UCODE_API(mvm->fw->ucode_ver) < 13) sf_cmd.state = cpu_to_le32(new_state); if (mvm->cfg->disable_dummy_notification) sf_cmd.state |= cpu_to_le32(SF_CFG_DUMMY_NOTIF_OFF); /* * If an associated AP sta changed its antenna configuration, the state * will remain FULL_ON but SF parameters need to be reconsidered. */ if (new_state != SF_FULL_ON && mvm->sf_state == new_state) return 0; switch (new_state) { case SF_UNINIT: if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 13) iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); break; case SF_FULL_ON: if (sta_id == IWL_MVM_STATION_COUNT) { IWL_ERR(mvm, "No station: Cannot switch SF to FULL_ON\n"); return -EINVAL; } rcu_read_lock(); sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); if (IS_ERR_OR_NULL(sta)) { IWL_ERR(mvm, "Invalid station id\n"); rcu_read_unlock(); return -EINVAL; } iwl_mvm_fill_sf_command(mvm, &sf_cmd, sta); rcu_read_unlock(); break; case SF_INIT_OFF: iwl_mvm_fill_sf_command(mvm, &sf_cmd, NULL); break; default: WARN_ONCE(1, "Invalid state: %d. not sending Smart Fifo cmd\n", new_state); return -EINVAL; } ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_SF_CFG_CMD, CMD_ASYNC, sizeof(sf_cmd), &sf_cmd); if (!ret) mvm->sf_state = new_state; return ret; }
int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) { if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWBT_COEX)) return 0; return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, CMD_SYNC, sizeof(struct iwl_bt_coex_prio_tbl_cmd), &iwl_bt_prio_tbl); }
static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { struct iwl_dts_measurement_cmd cmd = { .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; return iwl_mvm_send_cmd_pdu(mvm, CMD_DTS_MEASUREMENT_TRIGGER, 0, sizeof(cmd), &cmd); }
static int iwl_send_bt_prio_tbl(struct iwl_mvm *mvm) { if (unlikely(mvm->bt_force_ant_mode != BT_FORCE_ANT_DIS)) return 0; return iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PRIO_TABLE, 0, sizeof(struct iwl_bt_coex_prio_tbl_cmd), &iwl_bt_prio_tbl); }
static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant) { struct iwl_tx_ant_cfg_cmd tx_ant_cmd = { .valid = cpu_to_le32(valid_tx_ant), }; IWL_DEBUG_FW(mvm, "select valid tx ant: %u\n", valid_tx_ant); return iwl_mvm_send_cmd_pdu(mvm, TX_ANT_CONFIGURATION_CMD, 0, sizeof(tx_ant_cmd), &tx_ant_cmd); }
static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm) { struct iwl_dts_measurement_cmd cmd = { .flags = cpu_to_le32(DTS_TRIGGER_CMD_FLAGS_TEMP), }; struct iwl_ext_dts_measurement_cmd extcmd = { .control_mode = cpu_to_le32(DTS_AUTOMATIC), }; u32 cmdid; cmdid = iwl_cmd_id(CMD_DTS_MEASUREMENT_TRIGGER_WIDE, PHY_OPS_GROUP, 0); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE)) return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(cmd), &cmd); return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd); }
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable, u32 flags) { int ret; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; if (!vif->bss_conf.assoc) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { /* configure skip over dtim up to 306TU - 314 msec */ int dtimper = vif->bss_conf.dtim_period ?: 1; int dtimper_tu = dtimper * vif->bss_conf.beacon_int; bool radar_detect = iwl_mvm_power_is_radar(vif); if (WARN_ON(!dtimper_tu)) return 0; /* Check skip over DTIM conditions */ /* TODO: check that multicast wake lock is off */ if (!radar_detect && (dtimper < 10)) { cmd.skip_dtim_periods = 306 / dtimper_tu; if (cmd.skip_dtim_periods) cmd.flags |= cpu_to_le16( POWER_FLAGS_SKIP_OVER_DTIM_MSK); } } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, sizeof(cmd), &cmd); if (ret) return ret; /* configure beacon filtering */ if (mvmvif != mvm->bf_allowed_vif) return 0; if (enable) { struct iwl_beacon_filter_cmd cmd_bf = { IWL_BF_CMD_CONFIG_D0I3, .bf_enable_beacon_filter = cpu_to_le32(1), }; ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, flags, true); } else { if (mvmvif->bf_data.bf_enabled)
static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) { struct iwl_ltr_config_cmd cmd = { .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), }; if (!mvm->trans->ltr_enabled) return 0; return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, sizeof(cmd), &cmd); }
static int iwl_send_bt_env(struct iwl_mvm *mvm, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; int ret; env_cmd.action = action; env_cmd.type = type; ret = iwl_mvm_send_cmd_pdu(mvm, BT_COEX_PROT_ENV, CMD_SYNC, sizeof(env_cmd), &env_cmd); if (ret) IWL_ERR(mvm, "failed to send BT env command\n"); return ret; }
int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm, struct ieee80211_vif *vif, bool enable, u32 flags) { int ret; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mac_power_cmd cmd = {}; if (vif->type != NL80211_IFTYPE_STATION || vif->p2p) return 0; if (!vif->bss_conf.assoc) return 0; iwl_mvm_power_build_cmd(mvm, vif, &cmd); if (enable) { /* configure skip over dtim up to 300 msec */ int dtimper = mvm->hw->conf.ps_dtim_period ?: 1; int dtimper_msec = dtimper * vif->bss_conf.beacon_int; if (WARN_ON(!dtimper_msec)) return 0; cmd.skip_dtim_periods = 300 / dtimper_msec; if (cmd.skip_dtim_periods) cmd.flags |= cpu_to_le16(POWER_FLAGS_SKIP_OVER_DTIM_MSK); } iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&mvmvif->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif ret = iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, flags, sizeof(cmd), &cmd); if (ret) return ret; /* configure beacon filtering */ if (mvmvif != mvm->bf_allowed_vif) return 0; if (enable) { struct iwl_beacon_filter_cmd cmd_bf = { IWL_BF_CMD_CONFIG_D0I3, .bf_enable_beacon_filter = cpu_to_le32(1), }; ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf, flags, true); } else { if (mvmvif->bf_data.bf_enabled)
static int iwl_mvm_power_send_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mac_power_cmd cmd = {}; iwl_mvm_power_build_cmd(mvm, vif, &cmd); iwl_mvm_power_log(mvm, &cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS memcpy(&iwl_mvm_vif_from_mac80211(vif)->mac_pwr_cmd, &cmd, sizeof(cmd)); #endif return iwl_mvm_send_cmd_pdu(mvm, MAC_PM_POWER_TABLE, 0, sizeof(cmd), &cmd); }
static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm) { struct iwl_dqa_enable_cmd dqa_cmd = { .cmd_queue = cpu_to_le32(IWL_MVM_DQA_CMD_QUEUE), }; u32 cmd_id = iwl_cmd_id(DQA_ENABLE_CMD, DATA_PATH_GROUP, 0); int ret; ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd); if (ret) IWL_ERR(mvm, "Failed to send DQA enabling command: %d\n", ret); else IWL_DEBUG_FW(mvm, "Working in DQA mode\n"); return ret; }
/* set device type and latency */ static int iwl_set_soc_latency(struct iwl_mvm *mvm) { struct iwl_soc_configuration_cmd cmd; int ret; cmd.device_type = (mvm->trans->cfg->integrated) ? cpu_to_le32(SOC_CONFIG_CMD_INTEGRATED) : cpu_to_le32(SOC_CONFIG_CMD_DISCRETE); cmd.soc_latency = cpu_to_le32(mvm->trans->cfg->soc_latency); ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SOC_CONFIGURATION_CMD, SYSTEM_GROUP, 0), 0, sizeof(cmd), &cmd); if (ret) IWL_ERR(mvm, "Failed to set soc latency: %d\n", ret); return ret; }
static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { struct iwl_phy_cfg_cmd phy_cfg_cmd; enum iwl_ucode_type ucode_type = mvm->cur_ucode; /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); phy_cfg_cmd.calib_control.event_trigger = mvm->fw->default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = mvm->fw->default_calib[ucode_type].flow_trigger; IWL_DEBUG_INFO(mvm, "Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg); return iwl_mvm_send_cmd_pdu(mvm, PHY_CONFIGURATION_CMD, 0, sizeof(phy_cfg_cmd), &phy_cfg_cmd); }
static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) { int i; struct iwl_rss_config_cmd cmd = { .flags = cpu_to_le32(IWL_RSS_ENABLE), .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | IWL_RSS_HASH_TYPE_IPV6_TCP | IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, }; for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) cmd.indirection_table[i] = i % mvm->trans->num_rx_queues; memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key)); return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd); } void iwl_free_fw_paging(struct iwl_mvm *mvm) { int i; if (!mvm->fw_paging_db[0].fw_paging_block) return; for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) { if (!mvm->fw_paging_db[i].fw_paging_block) { IWL_DEBUG_FW(mvm, "Paging: block %d already freed, continue to next page\n", i); continue; } __free_pages(mvm->fw_paging_db[i].fw_paging_block, get_order(mvm->fw_paging_db[i].fw_paging_size)); } kfree(mvm->trans->paging_download_buf); mvm->trans->paging_download_buf = NULL; memset(mvm->fw_paging_db, 0, sizeof(mvm->fw_paging_db)); }
int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) { u8 *ptr; int ret; int i; if (WARN_ONCE(conf_id >= ARRAY_SIZE(mvm->fw->dbg_conf_tlv), "Invalid configuration %d\n", conf_id)) return -EINVAL; /* EARLY START - firmware's configuration is hard coded */ if ((!mvm->fw->dbg_conf_tlv[conf_id] || !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && conf_id == FW_DBG_START_FROM_ALIVE) { iwl_mvm_restart_early_start(mvm); return 0; } if (!mvm->fw->dbg_conf_tlv[conf_id]) return -EINVAL; if (mvm->fw_dbg_conf != FW_DBG_INVALID) IWL_WARN(mvm, "FW already configured (%d) - re-configuring\n", mvm->fw_dbg_conf); /* Send all HCMDs for configuring the FW debug */ ptr = (void *)&mvm->fw->dbg_conf_tlv[conf_id]->hcmd; for (i = 0; i < mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { struct iwl_fw_dbg_conf_hcmd *cmd = (void *)ptr; ret = iwl_mvm_send_cmd_pdu(mvm, cmd->id, 0, le16_to_cpu(cmd->len), cmd->data); if (ret) return ret; ptr += sizeof(*cmd); ptr += le16_to_cpu(cmd->len); } mvm->fw_dbg_conf = conf_id; return ret; }