Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/iwlwifi/fw/dbg.h
48287 views
1
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
2
/*
3
* Copyright (C) 2005-2014, 2018-2019, 2021-2025 Intel Corporation
4
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
5
* Copyright (C) 2015-2017 Intel Deutschland GmbH
6
*/
7
#ifndef __iwl_fw_dbg_h__
8
#define __iwl_fw_dbg_h__
9
#include <linux/workqueue.h>
10
#include <net/cfg80211.h>
11
#include "runtime.h"
12
#include "iwl-prph.h"
13
#include "iwl-io.h"
14
#include "file.h"
15
#include "error-dump.h"
16
#include "api/commands.h"
17
#include "api/dbg-tlv.h"
18
#include "api/alive.h"
19
20
/**
21
* struct iwl_fw_dump_desc - describes the dump
22
* @len: length of trig_desc->data
23
* @trig_desc: the description of the dump
24
*/
25
struct iwl_fw_dump_desc {
26
size_t len;
27
/* must be last */
28
struct iwl_fw_error_dump_trigger_desc trig_desc;
29
};
30
31
/**
32
* struct iwl_fw_dbg_params - register values to restore
33
* @in_sample: DBGC_IN_SAMPLE value
34
* @out_ctrl: DBGC_OUT_CTRL value
35
*/
36
struct iwl_fw_dbg_params {
37
u32 in_sample;
38
u32 out_ctrl;
39
};
40
41
extern const struct iwl_fw_dump_desc iwl_dump_desc_assert;
42
43
int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt,
44
const struct iwl_fw_dump_desc *desc,
45
bool monitor_only, unsigned int delay);
46
int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt,
47
enum iwl_fw_dbg_trigger trig_type);
48
int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt,
49
struct iwl_fwrt_dump_data *dump_data,
50
bool sync);
51
int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
52
enum iwl_fw_dbg_trigger trig, const char *str,
53
size_t len, struct iwl_fw_dbg_trigger_tlv *trigger);
54
int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
55
struct iwl_fw_dbg_trigger_tlv *trigger,
56
const char *fmt, ...) __printf(3, 4);
57
int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 id);
58
59
#define iwl_fw_dbg_trigger_enabled(fw, id) ({ \
60
void *__dbg_trigger = (fw)->dbg.trigger_tlv[(id)]; \
61
unlikely(__dbg_trigger); \
62
})
63
64
static inline struct iwl_fw_dbg_trigger_tlv*
65
_iwl_fw_dbg_get_trigger(const struct iwl_fw *fw, enum iwl_fw_dbg_trigger id)
66
{
67
return fw->dbg.trigger_tlv[id];
68
}
69
70
#define iwl_fw_dbg_get_trigger(fw, id) ({ \
71
BUILD_BUG_ON(!__builtin_constant_p(id)); \
72
BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
73
_iwl_fw_dbg_get_trigger((fw), (id)); \
74
})
75
76
static inline bool
77
iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
78
struct wireless_dev *wdev)
79
{
80
u32 trig_vif = le32_to_cpu(trig->vif_type);
81
82
return trig_vif == IWL_FW_DBG_CONF_VIF_ANY ||
83
wdev->iftype == trig_vif;
84
}
85
86
static inline bool
87
iwl_fw_dbg_trigger_stop_conf_match(struct iwl_fw_runtime *fwrt,
88
struct iwl_fw_dbg_trigger_tlv *trig)
89
{
90
return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) &&
91
(fwrt->dump.conf == FW_DBG_INVALID ||
92
(BIT(fwrt->dump.conf) & le32_to_cpu(trig->stop_conf_ids))));
93
}
94
95
static inline bool
96
iwl_fw_dbg_no_trig_window(struct iwl_fw_runtime *fwrt, u32 id, u32 dis_usec)
97
{
98
unsigned long wind_jiff = usecs_to_jiffies(dis_usec);
99
100
/* If this is the first event checked, jump to update start ts */
101
if (fwrt->dump.non_collect_ts_start[id] &&
102
(time_after(fwrt->dump.non_collect_ts_start[id] + wind_jiff,
103
jiffies)))
104
return true;
105
106
fwrt->dump.non_collect_ts_start[id] = jiffies;
107
return false;
108
}
109
110
static inline bool
111
iwl_fw_dbg_trigger_check_stop(struct iwl_fw_runtime *fwrt,
112
struct wireless_dev *wdev,
113
struct iwl_fw_dbg_trigger_tlv *trig)
114
{
115
u32 usec = le16_to_cpu(trig->trig_dis_ms) * USEC_PER_MSEC;
116
117
if (wdev && !iwl_fw_dbg_trigger_vif_match(trig, wdev))
118
return false;
119
120
if (iwl_fw_dbg_no_trig_window(fwrt, le32_to_cpu(trig->id), usec)) {
121
IWL_WARN(fwrt, "Trigger %d occurred while no-collect window.\n",
122
trig->id);
123
return false;
124
}
125
126
return iwl_fw_dbg_trigger_stop_conf_match(fwrt, trig);
127
}
128
129
static inline struct iwl_fw_dbg_trigger_tlv*
130
_iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt,
131
struct wireless_dev *wdev,
132
const enum iwl_fw_dbg_trigger id)
133
{
134
struct iwl_fw_dbg_trigger_tlv *trig;
135
136
if (iwl_trans_dbg_ini_valid(fwrt->trans))
137
return NULL;
138
139
if (!iwl_fw_dbg_trigger_enabled(fwrt->fw, id))
140
return NULL;
141
142
trig = _iwl_fw_dbg_get_trigger(fwrt->fw, id);
143
144
if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trig))
145
return NULL;
146
147
return trig;
148
}
149
150
#define iwl_fw_dbg_trigger_on(fwrt, wdev, id) ({ \
151
BUILD_BUG_ON(!__builtin_constant_p(id)); \
152
BUILD_BUG_ON((id) >= FW_DBG_TRIGGER_MAX); \
153
_iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \
154
})
155
156
static inline void
157
_iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
158
struct wireless_dev *wdev,
159
struct iwl_fw_dbg_trigger_tlv *trigger)
160
{
161
if (!trigger)
162
return;
163
164
if (!iwl_fw_dbg_trigger_check_stop(fwrt, wdev, trigger))
165
return;
166
167
#if defined(__linux__)
168
iwl_fw_dbg_collect_trig(fwrt, trigger, NULL);
169
#elif defined(__FreeBSD__)
170
iwl_fw_dbg_collect_trig(fwrt, trigger, "");
171
#endif
172
}
173
174
#define iwl_fw_dbg_trigger_simple_stop(fwrt, wdev, trig) \
175
_iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev), \
176
iwl_fw_dbg_get_trigger((fwrt)->fw,\
177
(trig)))
178
void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
179
struct iwl_fw_dbg_params *params,
180
bool stop);
181
182
#ifdef CONFIG_IWLWIFI_DEBUGFS
183
static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
184
{
185
if (fwrt->cur_fw_img == IWL_UCODE_REGULAR &&
186
(fwrt->fw->dbg.dest_tlv ||
187
fwrt->trans->dbg.ini_dest != IWL_FW_INI_LOCATION_INVALID))
188
fwrt->trans->dbg.rec_on = true;
189
}
190
#endif
191
192
static inline void iwl_fw_dump_conf_clear(struct iwl_fw_runtime *fwrt)
193
{
194
fwrt->dump.conf = FW_DBG_INVALID;
195
}
196
197
void iwl_fw_error_dump_wk(struct work_struct *work);
198
199
static inline bool iwl_fw_dbg_type_on(struct iwl_fw_runtime *fwrt, u32 type)
200
{
201
return (fwrt->fw->dbg.dump_mask & BIT(type));
202
}
203
204
static inline bool iwl_fw_dbg_is_d3_debug_enabled(struct iwl_fw_runtime *fwrt)
205
{
206
return fw_has_capa(&fwrt->fw->ucode_capa,
207
IWL_UCODE_TLV_CAPA_D3_DEBUG) &&
208
fwrt->trans->mac_cfg->base->d3_debug_data_length && fwrt->ops &&
209
fwrt->ops->d3_debug_enable &&
210
fwrt->ops->d3_debug_enable(fwrt->ops_ctx) &&
211
iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA);
212
}
213
214
static inline bool iwl_fw_dbg_is_paging_enabled(struct iwl_fw_runtime *fwrt)
215
{
216
return iwl_fw_dbg_type_on(fwrt, IWL_FW_ERROR_DUMP_PAGING) &&
217
!fwrt->trans->mac_cfg->gen2 &&
218
fwrt->cur_fw_img < IWL_UCODE_TYPE_MAX &&
219
fwrt->fw->img[fwrt->cur_fw_img].paging_mem_size &&
220
fwrt->fw_paging_db[0].fw_paging_block;
221
}
222
223
void iwl_fw_dbg_read_d3_debug_data(struct iwl_fw_runtime *fwrt);
224
225
static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt)
226
{
227
int i;
228
229
iwl_dbg_tlv_del_timers(fwrt->trans);
230
for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++)
231
flush_delayed_work(&fwrt->dump.wks[i].wk);
232
}
233
234
int iwl_fw_send_timestamp_marker_cmd(struct iwl_fw_runtime *fwrt);
235
236
#ifdef CONFIG_IWLWIFI_DEBUGFS
237
static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)
238
{
239
fwrt->timestamp.delay = 0;
240
cancel_delayed_work_sync(&fwrt->timestamp.wk);
241
}
242
243
void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay);
244
245
static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt)
246
{
247
cancel_delayed_work_sync(&fwrt->timestamp.wk);
248
}
249
250
static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt)
251
{
252
if (!fwrt->timestamp.delay)
253
return;
254
255
schedule_delayed_work(&fwrt->timestamp.wk,
256
round_jiffies_relative(fwrt->timestamp.delay));
257
}
258
259
#else
260
261
static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {}
262
263
static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt,
264
u32 delay) {}
265
266
static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {}
267
268
static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
269
270
#endif /* CONFIG_IWLWIFI_DEBUGFS */
271
272
void iwl_fw_dbg_stop_sync(struct iwl_fw_runtime *fwrt);
273
274
static inline void iwl_fw_lmac1_set_alive_err_table(struct iwl_trans *trans,
275
u32 lmac_error_event_table)
276
{
277
if (!(trans->dbg.error_event_table_tlv_status &
278
IWL_ERROR_EVENT_TABLE_LMAC1) ||
279
WARN_ON(trans->dbg.lmac_error_event_table[0] !=
280
lmac_error_event_table))
281
trans->dbg.lmac_error_event_table[0] = lmac_error_event_table;
282
}
283
284
static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans,
285
u32 umac_error_event_table)
286
{
287
if (!(trans->dbg.error_event_table_tlv_status &
288
IWL_ERROR_EVENT_TABLE_UMAC) ||
289
WARN_ON(trans->dbg.umac_error_event_table !=
290
umac_error_event_table))
291
trans->dbg.umac_error_event_table = umac_error_event_table;
292
}
293
294
static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt)
295
{
296
enum iwl_fw_ini_time_point tp_id;
297
298
if (!iwl_trans_dbg_ini_valid(fwrt->trans)) {
299
iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0);
300
return;
301
}
302
303
if (fwrt->trans->dbg.hw_error) {
304
tp_id = IWL_FW_INI_TIME_POINT_FW_HW_ERROR;
305
fwrt->trans->dbg.hw_error = false;
306
} else {
307
tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT;
308
}
309
310
iwl_dbg_tlv_time_point_sync(fwrt, tp_id, NULL);
311
}
312
313
static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt,
314
struct iwl_lmac_alive *lmac,
315
struct iwl_umac_alive *umac)
316
{
317
if (lmac) {
318
fwrt->dump.fw_ver.type = lmac->ver_type;
319
fwrt->dump.fw_ver.subtype = lmac->ver_subtype;
320
fwrt->dump.fw_ver.lmac_major = le32_to_cpu(lmac->ucode_major);
321
fwrt->dump.fw_ver.lmac_minor = le32_to_cpu(lmac->ucode_minor);
322
}
323
324
if (umac) {
325
fwrt->dump.fw_ver.umac_major = le32_to_cpu(umac->umac_major);
326
fwrt->dump.fw_ver.umac_minor = le32_to_cpu(umac->umac_minor);
327
}
328
}
329
330
void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt);
331
bool iwl_fwrt_read_err_table(struct iwl_trans *trans, u32 base, u32 *err_id);
332
void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt);
333
void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt);
334
335
#define IWL_FW_CHECK_FAILED(_obj, ...) \
336
IWL_ERR_LIMIT(_obj, __VA_ARGS__)
337
338
#define IWL_FW_CHECK(_obj, _cond, _fmt, ...) \
339
({ \
340
bool __cond = (_cond); \
341
\
342
if (unlikely(__cond)) \
343
IWL_FW_CHECK_FAILED(_obj, _fmt, ##__VA_ARGS__); \
344
\
345
unlikely(__cond); \
346
})
347
348
#endif /* __iwl_fw_dbg_h__ */
349
350