diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/utils.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/utils.c | 99 |
1 files changed, 95 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index a4a5e25623c..f4598cb2dd2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -376,9 +376,67 @@ struct iwl_error_event_table { u32 flow_handler; /* FH read/write pointers, RX credit */ } __packed; +/* + * UMAC error struct - relevant starting from family 8000 chip. + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_umac_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 umac_ver; /* umac version */ +} __packed; + #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) +static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) +{ + struct iwl_trans *trans = mvm->trans; + struct iwl_umac_error_event_table table; + u32 base; + + base = mvm->umac_error_event_table; + + if (base < 0x800000 || base >= 0x80C000) { + IWL_ERR(mvm, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (mvm->cur_ucode == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", + mvm->status, table.valid); + } + + IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, + desc_lookup(table.error_id)); + IWL_ERR(mvm, "0x%08X | umac uPc\n", table.pc); + IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); + IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); + IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); + IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); + IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); + IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); + IWL_ERR(mvm, "0x%08X | umac version\n", table.umac_ver); +} + void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) { struct iwl_trans *trans = mvm->trans; @@ -394,7 +452,7 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) base = mvm->fw->inst_errlog_ptr; } - if (base < 0x800000 || base >= 0x80C000) { + if (base < 0x800000) { IWL_ERR(mvm, "Not valid error log pointer 0x%08X for %s uCode\n", base, @@ -451,13 +509,17 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); + + if (mvm->support_umac_log) + iwl_mvm_dump_umac_error_log(mvm); } void iwl_mvm_dump_sram(struct iwl_mvm *mvm) { const struct fw_img *img; int ofs, len = 0; - u8 *buf; + int i; + __le32 *buf; if (!mvm->ucode_loaded) return; @@ -471,7 +533,12 @@ void iwl_mvm_dump_sram(struct iwl_mvm *mvm) return; iwl_trans_read_mem_bytes(mvm->trans, ofs, buf, len); - iwl_print_hex_error(mvm->trans, buf, len); + len = len >> 2; + for (i = 0; i < len; i++) { + IWL_ERR(mvm, "0x%08X\n", le32_to_cpu(buf[i])); + /* Add a small delay to let syslog catch up */ + udelay(10); + } kfree(buf); } @@ -514,7 +581,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request) { struct iwl_mvm_vif *mvmvif; - enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; + enum ieee80211_smps_mode smps_mode; int i; lockdep_assert_held(&mvm->mutex); @@ -523,6 +590,11 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (num_of_ant(iwl_fw_valid_rx_ant(mvm->fw)) == 1) return; + if (vif->type == NL80211_IFTYPE_AP) + smps_mode = IEEE80211_SMPS_OFF; + else + smps_mode = IEEE80211_SMPS_AUTOMATIC; + mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { @@ -536,3 +608,22 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, ieee80211_request_smps(vif, smps_mode); } + +int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + bool value) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int res; + + lockdep_assert_held(&mvm->mutex); + + mvmvif->low_latency = value; + + res = iwl_mvm_update_quotas(mvm, NULL); + if (res) + return res; + + iwl_mvm_bt_coex_vif_change(mvm); + + return iwl_mvm_power_update_mac(mvm, vif); +} |