0001
0002
0003
0004
0005
0006
0007 #ifndef __iwl_fw_dbg_h__
0008 #define __iwl_fw_dbg_h__
0009 #include <linux/workqueue.h>
0010 #include <net/cfg80211.h>
0011 #include "runtime.h"
0012 #include "iwl-prph.h"
0013 #include "iwl-io.h"
0014 #include "file.h"
0015 #include "error-dump.h"
0016 #include "api/commands.h"
0017 #include "api/dbg-tlv.h"
0018 #include "api/alive.h"
0019
0020
0021
0022
0023
0024
0025 struct iwl_fw_dump_desc {
0026 size_t len;
0027
0028 struct iwl_fw_error_dump_trigger_desc trig_desc;
0029 };
0030
0031
0032
0033
0034
0035
0036 struct iwl_fw_dbg_params {
0037 u32 in_sample;
0038 u32 out_ctrl;
0039 };
0040
0041 extern const struct iwl_fw_dump_desc iwl_dump_desc_assert;
0042
0043 int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
0044 const struct iwl_fw_dump_desc *desc,
0045 bool monitor_only, unsigned int delay);
0046 int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
0047 enum iwl_fw_dbg_trigger trig_type);
0048 int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
0049 struct iwl_fwrt_dump_data *dump_data,
0050 bool sync);
0051 int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
0052 enum iwl_fw_dbg_trigger trig, const char *str,
0053 size_t len, struct iwl_fw_dbg_trigger_tlv *trigger);
0054 int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
0055 struct iwl_fw_dbg_trigger_tlv *trigger,
0056 const char *fmt, ...) __printf(3, 4);
0057 int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id);
0058
0059 #define iwl_fw_dbg_trigger_enabled(fw, id) ({ \
0060 void *__dbg_trigger = (fw)->dbg.trigger_tlv[(id)]; \
0061 unlikely(__dbg_trigger); \
0062 })
0063
0064 static inline struct iwl_fw_dbg_trigger_tlv*
0065 _iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id)
0066 {
0067 return fw->dbg.trigger_tlv[id];
0068 }
0069
0070 #define iwl_fw_dbg_get_trigger(fw, id) ({ \
0071 BUILD_BUG_ON(!__builtin_constant_p(id)); \
0072 BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
0073 _iwl_fw_dbg_get_trigger((fw), (id)); \
0074 })
0075
0076 static inline bool
0077 iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
0078 struct wireless_dev *wdev)
0079 {
0080 u32 trig_vif = le32_to_cpu(trig->vif_type);
0081
0082 return trig_vif == IWL_FW_DBG_CONF_VIF_ANY ||
0083 wdev->iftype == trig_vif;
0084 }
0085
0086 static inline bool
0087 iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt,
0088 struct iwl_fw_dbg_trigger_tlv *trig)
0089 {
0090 return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) &&
0091 (fwrt->dump.conf == FW_DBG_INVALID ||
0092 (BIT(fwrt->dump.conf) & le32_to_cpu(trig->stop_conf_ids))));
0093 }
0094
0095 static inline bool
0096 iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_usec)
0097 {
0098 unsigned long wind_jiff = usecs_to_jiffies(dis_usec);
0099
0100
0101 if (fwrt->dump.non_collect_ts_start[id] &&
0102 (time_after(fwrt->dump.non_collect_ts_start[id] + wind_jiff,
0103 jiffies)))
0104 return true;
0105
0106 fwrt->dump.non_collect_ts_start[id] = jiffies;
0107 return false;
0108 }
0109
0110 static inline bool
0111 iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
0112 struct wireless_dev *wdev,
0113 struct iwl_fw_dbg_trigger_tlv *trig)
0114 {
0115 u32 usec = le16_to_cpu(trig->trig_dis_ms) * USEC_PER_MSEC;
0116
0117 if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev))
0118 return false;
0119
0120 if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id), usec)) {
0121 IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n",
0122 trig->id);
0123 return false;
0124 }
0125
0126 return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig);
0127 }
0128
0129 static inline struct iwl_fw_dbg_trigger_tlv*
0130 _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
0131 struct wireless_dev *wdev,
0132 const enum iwl_fw_dbg_trigger id)
0133 {
0134 struct iwl_fw_dbg_trigger_tlv *trig;
0135
0136 if (iwl_trans_dbg_ini_valid(fwrt->trans))
0137 return NULL;
0138
0139 if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
0140 return NULL;
0141
0142 trig = _iwl_fw_dbg_get_trigger(fwrt->fw, id);
0143
0144 if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trig))
0145 return NULL;
0146
0147 return trig;
0148 }
0149
0150 #define iwl_fw_dbg_trigger_on(fwrt, wdev, id) ({ \
0151 BUILD_BUG_ON(!__builtin_constant_p(id)); \
0152 BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
0153 _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \
0154 })
0155
0156 static inline void
0157 _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
0158 struct wireless_dev *wdev,
0159 struct iwl_fw_dbg_trigger_tlv *trigger)
0160 {
0161 if (!trigger)
0162 return;
0163
0164 if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trigger))
0165 return;
0166
0167 iwl_fw_dbg_collect_trig(fwrt, trigger, NULL);
0168 }
0169
0170 #define iwl_fw_dbg_trigger_simple_stop(fwrt, wdev, trig) \
0171 _iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev), \
0172 iwl_fw_dbg_get_trigger((fwrt)->fw,\
0173 (trig)))
0174 void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
0175 struct iwl_fw_dbg_params *params,
0176 bool stop);
0177
0178 #ifdef CONFIG_IWLWIFI_DEBUGFS
0179 static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
0180 {
0181 if (fwrt->cur_fw_img == IWL_UCODE_REGULAR &&
0182 (fwrt->fw->dbg.dest_tlv ||
0183 fwrt->trans->dbg.ini_dest != IWL_FW_INI_LOCATION_INVALID))
0184 fwrt->trans->dbg.rec_on = true;
0185 }
0186 #endif
0187
0188 static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
0189 {
0190 fwrt->dump.conf = FW_DBG_INVALID;
0191 }
0192
0193 void iwl_fw_error_dump_wk(struct work_struct *work);
0194
0195 static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
0196 {
0197 return (fwrt->fw->dbg.dump_mask & BIT(type));
0198 }
0199
0200 static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
0201 {
0202 return fw_has_capa(&fwrt->fw->ucode_capa,
0203 IWL_UCODE_TLV_CAPA_D3_DEBUG) &&
0204 fwrt->trans->cfg->d3_debug_data_length && fwrt->ops &&
0205 fwrt->ops->d3_debug_enable &&
0206 fwrt->ops->d3_debug_enable(fwrt->ops_ctx) &&
0207 iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
0208 }
0209
0210 static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt)
0211 {
0212 return iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PAGING) &&
0213 !fwrt->trans->trans_cfg->gen2 &&
0214 fwrt->cur_fw_img < IWL_UCODE_TYPE_MAX &&
0215 fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
0216 fwrt->fw_paging_db[0].fw_paging_block;
0217 }
0218
0219 void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
0220
0221 static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt)
0222 {
0223 int i;
0224
0225 iwl_dbg_tlv_del_timers(fwrt->trans);
0226 for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
0227 flush_delayed_work(&fwrt->dump.wks[i].wk);
0228 }
0229
0230 #ifdef CONFIG_IWLWIFI_DEBUGFS
0231 static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)
0232 {
0233 fwrt->timestamp.delay = 0;
0234 cancel_delayed_work_sync(&fwrt->timestamp.wk);
0235 }
0236
0237 void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay);
0238
0239 static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt)
0240 {
0241 cancel_delayed_work_sync(&fwrt->timestamp.wk);
0242 }
0243
0244 static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt)
0245 {
0246 if (!fwrt->timestamp.delay)
0247 return;
0248
0249 schedule_delayed_work(&fwrt->timestamp.wk,
0250 round_jiffies_relative(fwrt->timestamp.delay));
0251 }
0252
0253 #else
0254
0255 static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {}
0256
0257 static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt,
0258 u32 delay) {}
0259
0260 static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {}
0261
0262 static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
0263
0264 #endif
0265
0266 void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt);
0267
0268 static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
0269 u32 lmac_error_event_table)
0270 {
0271 if (!(trans->dbg.error_event_table_tlv_status &
0272 IWL_ERROR_EVENT_TABLE_LMAC1) ||
0273 WARN_ON(trans->dbg.lmac_error_event_table[0] !=
0274 lmac_error_event_table))
0275 trans->dbg.lmac_error_event_table[0] = lmac_error_event_table;
0276 }
0277
0278 static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans,
0279 u32 umac_error_event_table)
0280 {
0281 if (!(trans->dbg.error_event_table_tlv_status &
0282 IWL_ERROR_EVENT_TABLE_UMAC) ||
0283 WARN_ON(trans->dbg.umac_error_event_table !=
0284 umac_error_event_table))
0285 trans->dbg.umac_error_event_table = umac_error_event_table;
0286 }
0287
0288 static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt, bool sync)
0289 {
0290 enum iwl_fw_ini_time_point tp_id;
0291
0292 if (!iwl_trans_dbg_ini_valid(fwrt->trans)) {
0293 iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0);
0294 return;
0295 }
0296
0297 if (fwrt->trans->dbg.hw_error) {
0298 tp_id = IWL_FW_INI_TIME_POINT_FW_HW_ERROR;
0299 fwrt->trans->dbg.hw_error = false;
0300 } else {
0301 tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT;
0302 }
0303
0304 _iwl_dbg_tlv_time_point(fwrt, tp_id, NULL, sync);
0305 }
0306
0307 void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt);
0308
0309 static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
0310 struct iwl_lmac_alive *lmac,
0311 struct iwl_umac_alive *umac)
0312 {
0313 if (lmac) {
0314 fwrt->dump.fw_ver.type = lmac->ver_type;
0315 fwrt->dump.fw_ver.subtype = lmac->ver_subtype;
0316 fwrt->dump.fw_ver.lmac_major = le32_to_cpu(lmac->ucode_major);
0317 fwrt->dump.fw_ver.lmac_minor = le32_to_cpu(lmac->ucode_minor);
0318 }
0319
0320 if (umac) {
0321 fwrt->dump.fw_ver.umac_major = le32_to_cpu(umac->umac_major);
0322 fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
0323 }
0324 }
0325
0326 void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt);
0327 void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt,
0328 u32 timepoint,
0329 u32 timepoint_data);
0330 #endif