1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright (c) 2021, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the Intel Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 /*$FreeBSD$*/
32
33 #include "ice_common.h"
34 #include "ice_fwlog.h"
35
36 /**
37 * cache_cfg - Cache FW logging config
38 * @hw: pointer to the HW structure
39 * @cfg: config to cache
40 */
41 static void cache_cfg(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
42 {
43 hw->fwlog_cfg = *cfg;
44 }
45
46 /**
47 * valid_module_entries - validate all the module entry IDs and log levels
48 * @hw: pointer to the HW structure
49 * @entries: entries to validate
50 * @num_entries: number of entries to validate
51 */
52 static bool
53 valid_module_entries(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
54 u16 num_entries)
55 {
56 u16 i;
57
58 if (!entries) {
59 ice_debug(hw, ICE_DBG_FW_LOG, "Null ice_fwlog_module_entry array\n");
60 return false;
61 }
62
63 if (!num_entries) {
64 ice_debug(hw, ICE_DBG_FW_LOG, "num_entries must be non-zero\n");
65 return false;
66 }
67
68 for (i = 0; i < num_entries; i++) {
69 struct ice_fwlog_module_entry *entry = &entries[i];
70
71 if (entry->module_id >= ICE_AQC_FW_LOG_ID_MAX) {
72 ice_debug(hw, ICE_DBG_FW_LOG, "Invalid module_id %u, max valid module_id is %u\n",
73 entry->module_id, ICE_AQC_FW_LOG_ID_MAX - 1);
74 return false;
75 }
76
77 if (entry->log_level >= ICE_FWLOG_LEVEL_INVALID) {
78 ice_debug(hw, ICE_DBG_FW_LOG, "Invalid log_level %u, max valid log_level is %u\n",
79 entry->log_level,
80 ICE_AQC_FW_LOG_ID_MAX - 1);
81 return false;
82 }
83 }
84
85 return true;
86 }
87
88 /**
89 * valid_cfg - validate entire configuration
90 * @hw: pointer to the HW structure
91 * @cfg: config to validate
92 */
93 static bool valid_cfg(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
94 {
95 if (!cfg) {
96 ice_debug(hw, ICE_DBG_FW_LOG, "Null ice_fwlog_cfg\n");
97 return false;
98 }
99
100 if (cfg->log_resolution < ICE_AQC_FW_LOG_MIN_RESOLUTION ||
101 cfg->log_resolution > ICE_AQC_FW_LOG_MAX_RESOLUTION) {
102 ice_debug(hw, ICE_DBG_FW_LOG, "Unsupported log_resolution %u, must be between %u and %u\n",
103 cfg->log_resolution, ICE_AQC_FW_LOG_MIN_RESOLUTION,
104 ICE_AQC_FW_LOG_MAX_RESOLUTION);
105 return false;
106 }
107
108 if (!valid_module_entries(hw, cfg->module_entries,
109 ICE_AQC_FW_LOG_ID_MAX))
110 return false;
111
112 return true;
113 }
114
115 /**
116 * ice_fwlog_init - Initialize cached structures for tracking FW logging
117 * @hw: pointer to the HW structure
118 * @cfg: config used to initialize the cached structures
119 *
120 * This function should be called on driver initialization and before calling
121 * ice_init_hw(). Firmware logging will be configured based on these settings
122 * and also the PF will be registered on init.
123 */
124 enum ice_status
125 ice_fwlog_init(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
126 {
127 if (!valid_cfg(hw, cfg))
128 return ICE_ERR_PARAM;
129
130 cache_cfg(hw, cfg);
131
132 return ICE_SUCCESS;
133 }
134
135 /**
136 * ice_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30)
137 * @hw: pointer to the HW structure
138 * @entries: entries to configure
139 * @num_entries: number of @entries
140 * @options: options from ice_fwlog_cfg->options structure
141 * @log_resolution: logging resolution
142 */
143 static enum ice_status
144 ice_aq_fwlog_set(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
145 u16 num_entries, u16 options, u16 log_resolution)
146 {
147 struct ice_aqc_fw_log_cfg_resp *fw_modules;
148 struct ice_aqc_fw_log *cmd;
149 struct ice_aq_desc desc;
150 enum ice_status status;
151 u16 i;
152
153 fw_modules = (struct ice_aqc_fw_log_cfg_resp *)
154 ice_calloc(hw, num_entries, sizeof(*fw_modules));
155 if (!fw_modules)
156 return ICE_ERR_NO_MEMORY;
157
158 for (i = 0; i < num_entries; i++) {
159 fw_modules[i].module_identifier =
160 CPU_TO_LE16(entries[i].module_id);
161 fw_modules[i].log_level = entries[i].log_level;
162 }
163
164 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_config);
165 desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
166
167 cmd = &desc.params.fw_log;
168
169 cmd->cmd_flags = ICE_AQC_FW_LOG_CONF_SET_VALID;
170 cmd->ops.cfg.log_resolution = CPU_TO_LE16(log_resolution);
171 cmd->ops.cfg.mdl_cnt = CPU_TO_LE16(num_entries);
172
173 if (options & ICE_FWLOG_OPTION_ARQ_ENA)
174 cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_AQ_EN;
175 if (options & ICE_FWLOG_OPTION_UART_ENA)
176 cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_UART_EN;
177
178 status = ice_aq_send_cmd(hw, &desc, fw_modules,
179 sizeof(*fw_modules) * num_entries,
180 NULL);
181
182 ice_free(hw, fw_modules);
183
184 return status;
185 }
186
187 /**
188 * ice_fwlog_supported - Cached for whether FW supports FW logging or not
189 * @hw: pointer to the HW structure
190 *
191 * This will always return false if called before ice_init_hw(), so it must be
192 * called after ice_init_hw().
193 */
194 bool ice_fwlog_supported(struct ice_hw *hw)
195 {
196 return hw->fwlog_support_ena;
197 }
198
199 /**
200 * ice_fwlog_set - Set the firmware logging settings
201 * @hw: pointer to the HW structure
202 * @cfg: config used to set firmware logging
203 *
204 * This function should be called whenever the driver needs to set the firmware
205 * logging configuration. It can be called on initialization, reset, or during
206 * runtime.
207 *
208 * If the PF wishes to receive FW logging then it must register via
209 * ice_fwlog_register. Note, that ice_fwlog_register does not need to be called
210 * for init.
211 */
212 enum ice_status
213 ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
214 {
215 enum ice_status status;
216
217 if (!ice_fwlog_supported(hw))
218 return ICE_ERR_NOT_SUPPORTED;
219
220 if (!valid_cfg(hw, cfg))
221 return ICE_ERR_PARAM;
222
223 status = ice_aq_fwlog_set(hw, cfg->module_entries,
224 ICE_AQC_FW_LOG_ID_MAX, cfg->options,
225 cfg->log_resolution);
226 if (!status)
227 cache_cfg(hw, cfg);
228
229 return status;
230 }
231
232 /**
233 * update_cached_entries - Update module entries in cached FW logging config
234 * @hw: pointer to the HW structure
235 * @entries: entries to cache
236 * @num_entries: number of @entries
237 */
238 static void
239 update_cached_entries(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
240 u16 num_entries)
241 {
242 u16 i;
243
244 for (i = 0; i < num_entries; i++) {
245 struct ice_fwlog_module_entry *updated = &entries[i];
246 u16 j;
247
248 for (j = 0; j < ICE_AQC_FW_LOG_ID_MAX; j++) {
249 struct ice_fwlog_module_entry *cached =
250 &hw->fwlog_cfg.module_entries[j];
251
252 if (cached->module_id == updated->module_id) {
253 cached->log_level = updated->log_level;
254 break;
255 }
256 }
257 }
258 }
259
260 /**
261 * ice_fwlog_update_modules - Update the log level 1 or more FW logging modules
262 * @hw: pointer to the HW structure
263 * @entries: array of ice_fwlog_module_entry(s)
264 * @num_entries: number of entries
265 *
266 * This function should be called to update the log level of 1 or more FW
267 * logging modules via module ID.
268 *
269 * Only the entries passed in will be affected. All other firmware logging
270 * settings will be unaffected.
271 */
272 enum ice_status
273 ice_fwlog_update_modules(struct ice_hw *hw,
274 struct ice_fwlog_module_entry *entries,
275 u16 num_entries)
276 {
277 struct ice_fwlog_cfg *cfg;
278 enum ice_status status;
279
280 if (!ice_fwlog_supported(hw))
281 return ICE_ERR_NOT_SUPPORTED;
282
283 if (!valid_module_entries(hw, entries, num_entries))
284 return ICE_ERR_PARAM;
285
286 cfg = (struct ice_fwlog_cfg *)ice_calloc(hw, 1, sizeof(*cfg));
287 if (!cfg)
288 return ICE_ERR_NO_MEMORY;
289
290 status = ice_fwlog_get(hw, cfg);
291 if (status)
292 goto status_out;
293
294 status = ice_aq_fwlog_set(hw, entries, num_entries, cfg->options,
295 cfg->log_resolution);
296 if (!status)
297 update_cached_entries(hw, entries, num_entries);
298
299 status_out:
300 ice_free(hw, cfg);
301 return status;
302 }
303
304 /**
305 * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
306 * @hw: pointer to the HW structure
307 * @reg: true to register and false to unregister
308 */
309 static enum ice_status ice_aq_fwlog_register(struct ice_hw *hw, bool reg)
310 {
311 struct ice_aq_desc desc;
312
313 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register);
314
315 if (reg)
316 desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER;
317
318 return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
319 }
320
321 /**
322 * ice_fwlog_register - Register the PF for firmware logging
323 * @hw: pointer to the HW structure
324 *
325 * After this call the PF will start to receive firmware logging based on the
326 * configuration set in ice_fwlog_set.
327 */
328 enum ice_status ice_fwlog_register(struct ice_hw *hw)
329 {
330 enum ice_status status;
331
332 if (!ice_fwlog_supported(hw))
333 return ICE_ERR_NOT_SUPPORTED;
334
335 status = ice_aq_fwlog_register(hw, true);
336 if (status)
337 ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n");
338 else
339 hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED;
340
341 return status;
342 }
343
344 /**
345 * ice_fwlog_unregister - Unregister the PF from firmware logging
346 * @hw: pointer to the HW structure
347 */
348 enum ice_status ice_fwlog_unregister(struct ice_hw *hw)
349 {
350 enum ice_status status;
351
352 if (!ice_fwlog_supported(hw))
353 return ICE_ERR_NOT_SUPPORTED;
354
355 status = ice_aq_fwlog_register(hw, false);
356 if (status)
357 ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n");
358 else
359 hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED;
360
361 return status;
362 }
363
364 /**
365 * ice_aq_fwlog_get - Get the current firmware logging configuration (0xFF32)
366 * @hw: pointer to the HW structure
367 * @cfg: firmware logging configuration to populate
368 */
369 static enum ice_status
370 ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
371 {
372 struct ice_aqc_fw_log_cfg_resp *fw_modules;
373 struct ice_aqc_fw_log *cmd;
374 struct ice_aq_desc desc;
375 enum ice_status status;
376 u16 i, module_id_cnt;
377 void *buf;
378
379 ice_memset(cfg, 0, sizeof(*cfg), ICE_NONDMA_MEM);
380
381 buf = ice_calloc(hw, 1, ICE_AQ_MAX_BUF_LEN);
382 if (!buf)
383 return ICE_ERR_NO_MEMORY;
384
385 ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_query);
386 cmd = &desc.params.fw_log;
387
388 cmd->cmd_flags = ICE_AQC_FW_LOG_AQ_QUERY;
389
390 status = ice_aq_send_cmd(hw, &desc, buf, ICE_AQ_MAX_BUF_LEN, NULL);
391 if (status) {
392 ice_debug(hw, ICE_DBG_FW_LOG, "Failed to get FW log configuration\n");
393 goto status_out;
394 }
395
396 module_id_cnt = LE16_TO_CPU(cmd->ops.cfg.mdl_cnt);
397 if (module_id_cnt < ICE_AQC_FW_LOG_ID_MAX) {
398 ice_debug(hw, ICE_DBG_FW_LOG, "FW returned less than the expected number of FW log module IDs\n");
399 } else {
400 if (module_id_cnt > ICE_AQC_FW_LOG_ID_MAX)
401 ice_debug(hw, ICE_DBG_FW_LOG, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n",
402 ICE_AQC_FW_LOG_ID_MAX);
403 module_id_cnt = ICE_AQC_FW_LOG_ID_MAX;
404 }
405
406 cfg->log_resolution = LE16_TO_CPU(cmd->ops.cfg.log_resolution);
407 if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_AQ_EN)
408 cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
409 if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN)
410 cfg->options |= ICE_FWLOG_OPTION_UART_ENA;
411 if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED)
412 cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED;
413
414 fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf;
415
416 for (i = 0; i < module_id_cnt; i++) {
417 struct ice_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i];
418
419 cfg->module_entries[i].module_id =
420 LE16_TO_CPU(fw_module->module_identifier);
421 cfg->module_entries[i].log_level = fw_module->log_level;
422 }
423
424 status_out:
425 ice_free(hw, buf);
426 return status;
427 }
428
429 /**
430 * ice_fwlog_set_support_ena - Set if FW logging is supported by FW
431 * @hw: pointer to the HW struct
432 *
433 * If FW returns success to the ice_aq_fwlog_get call then it supports FW
434 * logging, else it doesn't. Set the fwlog_support_ena flag accordingly.
435 *
436 * This function is only meant to be called during driver init to determine if
437 * the FW support FW logging.
438 */
439 void ice_fwlog_set_support_ena(struct ice_hw *hw)
440 {
441 struct ice_fwlog_cfg *cfg;
442 enum ice_status status;
443
444 hw->fwlog_support_ena = false;
445
446 cfg = (struct ice_fwlog_cfg *)ice_calloc(hw, 1, sizeof(*cfg));
447 if (!cfg)
448 return;
449
450 /* don't call ice_fwlog_get() because that would overwrite the cached
451 * configuration from the call to ice_fwlog_init(), which is expected to
452 * be called prior to this function
453 */
454 status = ice_aq_fwlog_get(hw, cfg);
455 if (status)
456 ice_debug(hw, ICE_DBG_FW_LOG, "ice_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n",
457 status);
458 else
459 hw->fwlog_support_ena = true;
460
461 ice_free(hw, cfg);
462 }
463
464 /**
465 * ice_fwlog_get - Get the firmware logging settings
466 * @hw: pointer to the HW structure
467 * @cfg: config to populate based on current firmware logging settings
468 */
469 enum ice_status
470 ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
471 {
472 enum ice_status status;
473
474 if (!ice_fwlog_supported(hw))
475 return ICE_ERR_NOT_SUPPORTED;
476
477 if (!cfg)
478 return ICE_ERR_PARAM;
479
480 status = ice_aq_fwlog_get(hw, cfg);
481 if (status)
482 return status;
483
484 cache_cfg(hw, cfg);
485
486 return ICE_SUCCESS;
487 }
488
489 /**
490 * ice_fwlog_event_dump - Dump the event received over the Admin Receive Queue
491 * @hw: pointer to the HW structure
492 * @desc: Admin Receive Queue descriptor
493 * @buf: buffer that contains the FW log event data
494 *
495 * If the driver receives the ice_aqc_opc_fw_logs_event on the Admin Receive
496 * Queue, then it should call this function to dump the FW log data.
497 */
498 void
499 ice_fwlog_event_dump(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
500 {
501 if (!ice_fwlog_supported(hw))
502 return;
503
504 ice_info_fwlog(hw, 32, 1, (u8 *)buf, LE16_TO_CPU(desc->datalen));
505 }
Cache object: 37b9c33af12e8e4a1d3336b15da5beab
|