diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mvm/ops.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mvm/ops.c | 394 |
1 files changed, 217 insertions, 177 deletions
diff --git a/sys/contrib/dev/iwlwifi/mvm/ops.c b/sys/contrib/dev/iwlwifi/mvm/ops.c index 2d684f8e9030..912fb6677a0d 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ops.c +++ b/sys/contrib/dev/iwlwifi/mvm/ops.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("BSD"); #endif -MODULE_IMPORT_NS(IWLWIFI); +MODULE_IMPORT_NS("IWLWIFI"); static const struct iwl_op_mode_ops iwl_mvm_ops; static const struct iwl_op_mode_ops iwl_mvm_ops_mq; @@ -74,8 +74,10 @@ static int __init iwl_mvm_init(void) } ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops); - if (ret) + if (ret) { pr_err("Unable to register MVM op_mode: %d\n", ret); + iwl_mvm_rate_control_unregister(); + } return ret; } @@ -109,11 +111,11 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) IWL_DEBUG_INFO(mvm, "Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type, radio_cfg_step, radio_cfg_dash); - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + if (mvm->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) return; /* SKU control */ - reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->hw_rev); + reg_val = CSR_HW_REV_STEP_DASH(mvm->trans->info.hw_rev); /* radio configuration */ reg_val |= radio_cfg_type << CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE; @@ -131,7 +133,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) * unrelated errors. Need to further investigate this, but for now * we'll separate cases. */ - if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_8000) + if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000) reg_val |= CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI; if (iwl_fw_dbg_is_d3_debug_enabled(&mvm->fwrt)) @@ -152,7 +154,7 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) * (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->apmg_not_supported) + if (!mvm->trans->mac_cfg->base->apmg_not_supported) 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); @@ -162,7 +164,7 @@ static void iwl_mvm_rx_esr_mode_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_mvm_esr_mode_notif *notif = (void *)pkt->data; + struct iwl_esr_mode_notif *notif = (void *)pkt->data; struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm); /* FW recommendations is only for entering EMLSR */ @@ -188,7 +190,8 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, if (notif->type != cpu_to_le32(IWL_DP_MON_NOTIF_TYPE_EXT_CCA)) return; - vif = iwl_mvm_get_vif_by_macid(mvm, notif->mac_id); + /* FIXME: should fetch the link and not the vif */ + vif = iwl_mvm_get_vif_by_macid(mvm, notif->link_id); if (!vif || vif->type != NL80211_IFTYPE_STATION) return; @@ -278,6 +281,12 @@ static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_thermal_dual_chain_request *req = (void *)pkt->data; + /* firmware is expected to handle that in RLC offload mode */ + if (IWL_FW_CHECK(mvm, iwl_mvm_has_rlc_offload(mvm), + "Got THERMAL_DUAL_CHAIN_REQUEST (0x%x) in RLC offload mode\n", + req->event)) + return; + /* * We could pass it to the iterator data, but also need to remember * it for new interfaces that are added while in this state. @@ -342,7 +351,7 @@ struct iwl_rx_handlers { */ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, RX_HANDLER_SYNC, - struct iwl_mvm_tx_resp), + struct iwl_tx_resp), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, RX_HANDLER_SYNC, struct iwl_mvm_ba_notif), @@ -350,9 +359,12 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_tlc_update_notif, RX_HANDLER_SYNC, struct iwl_tlc_update_notif), - RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, + RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_old_notif, RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_bt_coex_profile_notif), + struct iwl_bt_coex_prof_old_notif), + RX_HANDLER_GRP(BT_COEX_GROUP, PROFILE_NOTIF, iwl_mvm_rx_bt_coex_notif, + RX_HANDLER_ASYNC_LOCKED_WIPHY, + struct iwl_bt_coex_profile_notif), RX_HANDLER_NO_SIZE(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_NO_SIZE(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, @@ -379,7 +391,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_SYNC, struct iwl_time_event_notif), RX_HANDLER_GRP(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF, iwl_mvm_rx_session_protect_notif, RX_HANDLER_SYNC, - struct iwl_mvm_session_prot_notif), + struct iwl_session_prot_notif), RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, RX_HANDLER_ASYNC_LOCKED, struct iwl_mcc_chub_notif), @@ -402,10 +414,15 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { iwl_mvm_rx_umac_scan_iter_complete_notif, RX_HANDLER_SYNC, struct iwl_umac_scan_iter_complete_notif), - RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif, + RX_HANDLER(MISSED_BEACONS_NOTIFICATION, + iwl_mvm_rx_missed_beacons_notif_legacy, RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_missed_beacons_notif), + struct iwl_missed_beacons_notif_v4), + RX_HANDLER_GRP(MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, + iwl_mvm_rx_missed_beacons_notif, + RX_HANDLER_ASYNC_LOCKED_WIPHY, + struct iwl_missed_beacons_notif), RX_HANDLER(REPLY_ERROR, iwl_mvm_rx_fw_error, RX_HANDLER_SYNC, struct iwl_error_resp), RX_HANDLER(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION, @@ -460,7 +477,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF, iwl_mvm_rx_esr_mode_notif, RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_mvm_esr_mode_notif), + struct iwl_esr_mode_notif), RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, @@ -489,6 +506,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(SCAN_GROUP, CHANNEL_SURVEY_NOTIF, iwl_mvm_rx_channel_survey_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_umac_scan_channel_survey_notif), + RX_HANDLER_GRP(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, + iwl_mvm_rx_beacon_filter_notif, + RX_HANDLER_ASYNC_LOCKED, + /* same size as v1 */ + struct iwl_beacon_filter_notif), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -659,6 +681,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), + HCMD_NAME(BEACON_FILTER_IN_NOTIF), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), @@ -730,7 +753,15 @@ static const struct iwl_hcmd_names iwl_mvm_regulatory_and_nvm_names[] = { HCMD_NAME(TAS_CONFIG), }; -static const struct iwl_hcmd_arr iwl_mvm_groups[] = { +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ +static const struct iwl_hcmd_names iwl_mvm_bt_coex_names[] = { + HCMD_NAME(PROFILE_NOTIF), +}; + +VISIBLE_IF_IWLWIFI_KUNIT +const struct iwl_hcmd_arr iwl_mvm_groups[] = { [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names), [SYSTEM_GROUP] = HCMD_ARR(iwl_mvm_system_names), @@ -739,12 +770,18 @@ static const struct iwl_hcmd_arr iwl_mvm_groups[] = { [DATA_PATH_GROUP] = HCMD_ARR(iwl_mvm_data_path_names), [SCAN_GROUP] = HCMD_ARR(iwl_mvm_scan_names), [LOCATION_GROUP] = HCMD_ARR(iwl_mvm_location_names), + [BT_COEX_GROUP] = HCMD_ARR(iwl_mvm_bt_coex_names), [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names), [REGULATORY_AND_NVM_GROUP] = HCMD_ARR(iwl_mvm_regulatory_and_nvm_names), [DEBUG_GROUP] = HCMD_ARR(iwl_mvm_debug_names), [STATISTICS_GROUP] = HCMD_ARR(iwl_mvm_statistics_names), }; +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_groups); +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +const unsigned int iwl_mvm_groups_size = ARRAY_SIZE(iwl_mvm_groups); +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_groups_size); +#endif /* this forward declaration can avoid to export the function */ static void iwl_mvm_async_handlers_wk(struct work_struct *wk); @@ -1228,13 +1265,12 @@ static void iwl_mvm_trig_link_selection(struct wiphy *wiphy, } static struct iwl_op_mode * -iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, +iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) { struct ieee80211_hw *hw; struct iwl_op_mode *op_mode; struct iwl_mvm *mvm; - struct iwl_trans_config trans_cfg = {}; static const u8 no_reclaim_cmds[] = { TX_CMD, }; @@ -1242,14 +1278,16 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, size_t scan_size; u32 min_backoff; struct iwl_mvm_csme_conn_info *csme_conn_info __maybe_unused; + int ratecheck; + int err; /* - * We use IWL_MVM_STATION_COUNT_MAX to check the validity of the station + * We use IWL_STATION_COUNT_MAX to check the validity of the station * index all over the driver - check that its value corresponds to the * array size. */ BUILD_BUG_ON(ARRAY_SIZE(mvm->fw_id_to_mac_id) != - IWL_MVM_STATION_COUNT_MAX); + IWL_STATION_COUNT_MAX); /******************************** * 1. Allocating and configuring HW data @@ -1259,20 +1297,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_has_mld_api(fw) ? &iwl_mvm_mld_hw_ops : &iwl_mvm_hw_ops); if (!hw) - return NULL; + return ERR_PTR(-ENOMEM); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) max_agg = 512; else max_agg = IEEE80211_MAX_AMPDU_BUF_HE; hw->max_rx_aggregation_subframes = max_agg; - if (cfg->max_tx_agg_size) - hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; - else - hw->max_tx_aggregation_subframes = max_agg; - op_mode = hw->priv; mvm = IWL_OP_MODE_GET_MVM(op_mode); @@ -1288,27 +1321,67 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_get_bios_tables(mvm); iwl_uefi_get_sgom_table(trans, &mvm->fwrt); iwl_uefi_get_step_table(trans); + iwl_bios_setup_step(trans, &mvm->fwrt); mvm->init_status = 0; + /* start with v1 rates */ + mvm->fw_rates_ver = 1; + + /* check for rates version 2 */ + ratecheck = + (iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) >= 8) + + (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, + TLC_MNG_UPDATE_NOTIF, 0) >= 3) + + (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + REPLY_RX_MPDU_CMD, 0) >= 4) + + (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) >= 6); + if (ratecheck != 0 && ratecheck != 4) { + IWL_ERR(mvm, "Firmware has inconsistent rates\n"); + err = -EINVAL; + goto out_free; + } + if (ratecheck == 4) + mvm->fw_rates_ver = 2; + + /* check for rates version 3 */ + ratecheck = + (iwl_fw_lookup_cmd_ver(mvm->fw, TX_CMD, 0) >= 11) + + (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, + TLC_MNG_UPDATE_NOTIF, 0) >= 4) + + (iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + REPLY_RX_MPDU_CMD, 0) >= 6) + + (iwl_fw_lookup_notif_ver(mvm->fw, DATA_PATH_GROUP, + RX_NO_DATA_NOTIF, 0) >= 4) + + (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TX_CMD, 0) >= 9); + if (ratecheck != 0 && ratecheck != 5) { + IWL_ERR(mvm, "Firmware has inconsistent rates\n"); + err = -EINVAL; + goto out_free; + } + if (ratecheck == 5) + mvm->fw_rates_ver = 3; + + trans->conf.rx_mpdu_cmd = REPLY_RX_MPDU_CMD; + if (iwl_mvm_has_new_rx_api(mvm)) { op_mode->ops = &iwl_mvm_ops_mq; - trans->rx_mpdu_cmd_hdr_size = - (trans->trans_cfg->device_family >= + trans->conf.rx_mpdu_cmd_hdr_size = + (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_rx_mpdu_desc) : IWL_RX_DESC_SIZE_V1; } else { op_mode->ops = &iwl_mvm_ops; - trans->rx_mpdu_cmd_hdr_size = + trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); - if (WARN_ON(trans->num_rx_queues > 1)) + if (WARN_ON(trans->info.num_rxqs > 1)) { + err = -EINVAL; goto out_free; + } } - mvm->fw_restart = iwlwifi_mod_params.fw_restart ? -1 : 0; - if (iwl_mvm_has_new_tx_api(mvm)) { /* * If we have the new TX/queue allocation API initialize them @@ -1380,66 +1453,58 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_fw_lookup_notif_ver(mvm->fw, LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, 5); /* we only support up to version 9 */ - if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9)) + if (WARN_ON_ONCE(mvm->cmd_ver.range_resp > 9)) { + err = -EINVAL; goto out_free; + } /* * Populate the state variables that the transport layer needs * to know about. */ - trans_cfg.op_mode = op_mode; - trans_cfg.no_reclaim_cmds = no_reclaim_cmds; - trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - - trans_cfg.rx_buf_size = iwl_amsdu_size_to_rxb_size(); + BUILD_BUG_ON(sizeof(no_reclaim_cmds) > + sizeof(trans->conf.no_reclaim_cmds)); + memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds, + sizeof(no_reclaim_cmds)); + trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - trans->wide_cmd_header = true; - trans_cfg.bc_table_dword = - mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210; + trans->conf.rx_buf_size = iwl_amsdu_size_to_rxb_size(); - trans_cfg.command_groups = iwl_mvm_groups; - trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); + trans->conf.wide_cmd_header = true; - trans_cfg.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; - trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD; - trans_cfg.scd_set_active = true; + trans->conf.command_groups = iwl_mvm_groups; + trans->conf.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); - trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info, - driver_data[2]); + trans->conf.cmd_queue = IWL_MVM_DQA_CMD_QUEUE; + trans->conf.cmd_fifo = IWL_MVM_TX_FIFO_CMD; + trans->conf.scd_set_active = true; - /* Set a short watchdog for the command queue */ - trans_cfg.cmd_q_wdg_timeout = - iwl_mvm_get_wd_timeout(mvm, NULL, false, true); + trans->conf.cb_data_offs = offsetof(struct ieee80211_tx_info, + driver_data[2]); snprintf(mvm->hw->wiphy->fw_version, sizeof(mvm->hw->wiphy->fw_version), "%.31s", fw->fw_version); - trans_cfg.fw_reset_handshake = fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); + trans->conf.fw_reset_handshake = + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_RESET_HANDSHAKE); - trans_cfg.queue_alloc_cmd_ver = + trans->conf.queue_alloc_cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD), 0); mvm->sta_remove_requires_queue_remove = - trans_cfg.queue_alloc_cmd_ver > 0; + trans->conf.queue_alloc_cmd_ver > 0; mvm->mld_api_is_used = iwl_mvm_has_mld_api(mvm->fw); /* Configure transport layer */ - iwl_trans_configure(mvm->trans, &trans_cfg); + iwl_trans_op_mode_enter(mvm->trans, op_mode); - trans->rx_mpdu_cmd = REPLY_RX_MPDU_CMD; trans->dbg.dest_tlv = mvm->fw->dbg.dest_tlv; trans->dbg.n_dest_reg = mvm->fw->dbg.n_dest_reg; - memcpy(trans->dbg.conf_tlv, mvm->fw->dbg.conf_tlv, - sizeof(trans->dbg.conf_tlv)); - trans->dbg.trigger_tlv = mvm->fw->dbg.trigger_tlv; - - trans->iml = mvm->fw->iml; - trans->iml_len = mvm->fw->iml_len; /* set up notification wait support */ iwl_notification_wait_init(&mvm->notif_wait); @@ -1448,6 +1513,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, mvm->phy_db = iwl_phy_db_init(trans); if (!mvm->phy_db) { IWL_ERR(mvm, "Cannot init phy_db\n"); + err = -ENOMEM; goto out_free; } @@ -1460,13 +1526,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, scan_size = iwl_mvm_scan_size(mvm); mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); - if (!mvm->scan_cmd) + if (!mvm->scan_cmd) { + err = -ENOMEM; goto out_free; + } mvm->scan_cmd_size = scan_size; /* invalidate ids to prevent accidental removal of sta_id 0 */ - mvm->aux_sta.sta_id = IWL_MVM_INVALID_STA; - mvm->snif_sta.sta_id = IWL_MVM_INVALID_STA; + mvm->aux_sta.sta_id = IWL_INVALID_STA; + mvm->snif_sta.sta_id = IWL_INVALID_STA; /* Set EBS as successful as long as not stated otherwise by the FW. */ mvm->last_ebs_successful = true; @@ -1494,7 +1562,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_mvm_mei_scan_filter_init(&mvm->mei_scan_filter); - if (iwl_mvm_start_get_nvm(mvm)) { + err = iwl_mvm_start_get_nvm(mvm); + if (err) { /* * Getting NVM failed while CSME is the owner, but we are * registered to MEI, we'll get the NVM later when it'll be @@ -1507,7 +1576,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, } - if (iwl_mvm_start_post_nvm(mvm)) + err = iwl_mvm_start_post_nvm(mvm); + if (err) goto out_thermal_exit; return op_mode; @@ -1527,7 +1597,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, iwl_trans_op_mode_leave(trans); ieee80211_free_hw(mvm->hw); - return NULL; + return ERR_PTR(err); } void iwl_mvm_stop_device(struct iwl_mvm *mvm) @@ -1962,27 +2032,62 @@ static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) ieee80211_free_txskb(mvm->hw, skb); } -struct iwl_mvm_reprobe { - struct device *dev; - struct work_struct work; -}; +static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, + enum iwl_fw_error_type type) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + iwl_abort_notification_waits(&mvm->notif_wait); + iwl_dbg_tlv_del_timers(mvm->trans); + + if (type == IWL_ERR_TYPE_CMD_QUEUE_FULL) + IWL_ERR(mvm, "Command queue full!\n"); + else if (!iwl_trans_is_dead(mvm->trans) && + !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, + &mvm->status)) + iwl_mvm_dump_nic_error_log(mvm); + + /* + * This should be first thing before trying to collect any + * data to avoid endless loops if any HW error happens while + * collecting debug data. + * It might not actually be true that we'll restart, but the + * setting of the bit doesn't matter if we're going to be + * unbound either. + */ + if (type != IWL_ERR_TYPE_RESET_HS_TIMEOUT) + set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); +} -static void iwl_mvm_reprobe_wk(struct work_struct *wk) +static void iwl_mvm_dump_error(struct iwl_op_mode *op_mode, + struct iwl_fw_error_dump_mode *mode) { - struct iwl_mvm_reprobe *reprobe; - - reprobe = container_of(wk, struct iwl_mvm_reprobe, work); - if (device_reprobe(reprobe->dev)) - dev_err(reprobe->dev, "reprobe failed!\n"); - put_device(reprobe->dev); - kfree(reprobe); - module_put(THIS_MODULE); + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + /* if we come in from opmode we have the mutex held */ + if (mode->context == IWL_ERR_CONTEXT_FROM_OPMODE) { + lockdep_assert_held(&mvm->mutex); + iwl_fw_error_collect(&mvm->fwrt); + } else { + mutex_lock(&mvm->mutex); + if (mode->context != IWL_ERR_CONTEXT_ABORT) + iwl_fw_error_collect(&mvm->fwrt); + mutex_unlock(&mvm->mutex); + } } -void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) +static bool iwl_mvm_sw_reset(struct iwl_op_mode *op_mode, + enum iwl_fw_error_type type) { - iwl_abort_notification_waits(&mvm->notif_wait); - iwl_dbg_tlv_del_timers(mvm->trans); + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + + /* + * If the firmware crashes while we're already considering it + * to be dead then don't ask for a restart, that cannot do + * anything useful anyway. + */ + if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) + return false; /* * This is a bit racy, but worst case we tell mac80211 about @@ -1997,52 +2102,11 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) iwl_mvm_report_scan_aborted(mvm); /* - * If we're restarting already, don't cycle restarts. * If INIT fw asserted, it will likely fail again. * If WoWLAN fw asserted, don't restart either, mac80211 * can't recover this since we're already half suspended. */ - if (!mvm->fw_restart && fw_error) { - iwl_fw_error_collect(&mvm->fwrt, false); - } else if (test_bit(IWL_MVM_STATUS_STARTING, - &mvm->status)) { - IWL_ERR(mvm, "Starting mac, retry will be triggered anyway\n"); - } else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { - struct iwl_mvm_reprobe *reprobe; - - IWL_ERR(mvm, - "Firmware error during reconfiguration - reprobe!\n"); - - /* - * get a module reference to avoid doing this while unloading - * anyway and to avoid scheduling a work with code that's - * being removed. - */ - if (!try_module_get(THIS_MODULE)) { - IWL_ERR(mvm, "Module is being unloaded - abort\n"); - return; - } - - reprobe = kzalloc(sizeof(*reprobe), GFP_ATOMIC); - if (!reprobe) { - module_put(THIS_MODULE); - return; - } - reprobe->dev = get_device(mvm->trans->dev); - INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk); - schedule_work(&reprobe->work); - } else if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, - &mvm->status)) { - IWL_ERR(mvm, "HW restart already requested, but not started\n"); - } else if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && - mvm->hw_registered && - !test_bit(STATUS_TRANS_DEAD, &mvm->trans->status)) { - /* This should be first thing before trying to collect any - * data to avoid endless loops if any HW error happens while - * collecting debug data. - */ - set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); - + if (mvm->fwrt.cur_fw_img == IWL_UCODE_REGULAR && mvm->hw_registered) { if (mvm->fw->ucode_capa.error_log_size) { u32 src_size = mvm->fw->ucode_capa.error_log_size; u32 src_addr = mvm->fw->ucode_capa.error_log_addr; @@ -2057,81 +2121,55 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } - iwl_fw_error_collect(&mvm->fwrt, false); - - if (fw_error && mvm->fw_restart > 0) { - mvm->fw_restart--; - ieee80211_restart_hw(mvm->hw); - } else if (mvm->fwrt.trans->dbg.restart_required) { + if (mvm->fwrt.trans->dbg.restart_required) { IWL_DEBUG_INFO(mvm, "FW restart requested after debug collection\n"); mvm->fwrt.trans->dbg.restart_required = false; ieee80211_restart_hw(mvm->hw); - } else if (mvm->trans->trans_cfg->device_family <= IWL_DEVICE_FAMILY_8000) { + return true; + } else if (mvm->trans->mac_cfg->device_family <= IWL_DEVICE_FAMILY_8000) { ieee80211_restart_hw(mvm->hw); + return true; } } -} - -static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, bool sync) -{ - struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - - if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) && - !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, - &mvm->status)) - iwl_mvm_dump_nic_error_log(mvm); - - if (sync) { - iwl_fw_error_collect(&mvm->fwrt, true); - /* - * Currently, the only case for sync=true is during - * shutdown, so just stop in this case. If/when that - * changes, we need to be a bit smarter here. - */ - return; - } - /* - * If the firmware crashes while we're already considering it - * to be dead then don't ask for a restart, that cannot do - * anything useful anyway. - */ - if (!test_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status)) - return; - - iwl_mvm_nic_restart(mvm, false); + return false; } -static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) +static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, + enum iwl_fw_ini_time_point tp_id, + union iwl_dbg_tlv_tp_data *tp_data) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - WARN_ON(1); - iwl_mvm_nic_restart(mvm, true); + iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data); } -static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, - enum iwl_fw_ini_time_point tp_id, - union iwl_dbg_tlv_tp_data *tp_data) +static void iwl_mvm_dump(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + struct iwl_fw_runtime *fwrt = &mvm->fwrt; - iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data); + if (!iwl_trans_fw_running(fwrt->trans)) + return; + + iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL); } +#ifdef CONFIG_PM_SLEEP static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); mutex_lock(&mvm->mutex); clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); - mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; iwl_mvm_stop_device(mvm); -#ifdef CONFIG_PM mvm->fast_resume = false; -#endif mutex_unlock(&mvm->mutex); } +#else +static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) +{} +#endif #define IWL_MVM_COMMON_OPS \ /* these could be differentiated */ \ @@ -2140,7 +2178,8 @@ static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) .hw_rf_kill = iwl_mvm_set_hw_rfkill_state, \ .free_skb = iwl_mvm_free_skb, \ .nic_error = iwl_mvm_nic_error, \ - .cmd_queue_full = iwl_mvm_cmd_queue_full, \ + .dump_error = iwl_mvm_dump_error, \ + .sw_reset = iwl_mvm_sw_reset, \ .nic_config = iwl_mvm_nic_config, \ /* as we only register one, these MUST be common! */ \ .start = iwl_op_mode_mvm_start, \ @@ -2162,7 +2201,7 @@ static void iwl_mvm_rx_mq_rss(struct iwl_op_mode *op_mode, struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd); - if (unlikely(queue >= mvm->trans->num_rx_queues)) + if (unlikely(queue >= mvm->trans->info.num_rxqs)) return; if (unlikely(cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE))) @@ -2178,4 +2217,5 @@ static const struct iwl_op_mode_ops iwl_mvm_ops_mq = { IWL_MVM_COMMON_OPS, .rx = iwl_mvm_rx_mq, .rx_rss = iwl_mvm_rx_mq_rss, + .dump = iwl_mvm_dump, }; |
