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 /**
34 * @file ice_fw_logging.c
35 * @brief firmware logging sysctls
36 *
37 * Contains sysctls to enable and configure firmware logging debug support.
38 */
39
40 #include "ice_lib.h"
41 #include "ice_iflib.h"
42 #include <sys/queue.h>
43 #include <sys/sdt.h>
44
45 /*
46 * SDT provider for DTrace probes related to firmware logging events
47 */
48 SDT_PROVIDER_DEFINE(ice_fwlog);
49
50 /*
51 * SDT DTrace probe fired when a firmware log message is received over the
52 * AdminQ. It passes the buffer of the firwmare log message along with its
53 * length in bytes to the DTrace framework.
54 */
55 SDT_PROBE_DEFINE2(ice_fwlog, , , message, "uint8_t *", "int");
56
57 /*
58 * Helper function prototypes
59 */
60 static int ice_reconfig_fw_log(struct ice_softc *sc, struct ice_fwlog_cfg *cfg);
61
62 /*
63 * dynamic sysctl handlers
64 */
65 static int ice_sysctl_fwlog_set_cfg_options(SYSCTL_HANDLER_ARGS);
66 static int ice_sysctl_fwlog_log_resolution(SYSCTL_HANDLER_ARGS);
67 static int ice_sysctl_fwlog_register(SYSCTL_HANDLER_ARGS);
68 static int ice_sysctl_fwlog_module_log_severity(SYSCTL_HANDLER_ARGS);
69
70 /**
71 * ice_reconfig_fw_log - Re-program firmware logging configuration
72 * @sc: private softc structure
73 * @cfg: firmware log configuration to latch
74 *
75 * If the adminq is currently active, ask firmware to update the logging
76 * configuration. If the adminq is currently down, then do nothing. In this
77 * case, ice_init_hw() will re-configure firmware logging as soon as it brings
78 * up the adminq.
79 */
80 static int
81 ice_reconfig_fw_log(struct ice_softc *sc, struct ice_fwlog_cfg *cfg)
82 {
83 enum ice_status status;
84
85 ice_fwlog_init(&sc->hw, cfg);
86
87 if (!ice_check_sq_alive(&sc->hw, &sc->hw.adminq))
88 return (0);
89
90 if (!ice_fwlog_supported(&sc->hw))
91 return (0);
92
93 status = ice_fwlog_set(&sc->hw, cfg);
94 if (status) {
95 device_printf(sc->dev,
96 "Failed to reconfigure firmware logging, err %s aq_err %s\n",
97 ice_status_str(status),
98 ice_aq_str(sc->hw.adminq.sq_last_status));
99 return (ENODEV);
100 }
101
102 return (0);
103 }
104
105 #define ICE_SYSCTL_HELP_FWLOG_LOG_RESOLUTION \
106 "\nControl firmware message limit to send per ARQ event" \
107 "\t\nMin: 1" \
108 "\t\nMax: 128"
109
110 #define ICE_SYSCTL_HELP_FWLOG_ARQ_ENA \
111 "\nControl whether to enable/disable reporing to admin Rx queue" \
112 "\n0 - Enable firmware reporting via ARQ" \
113 "\n1 - Disable firmware reporting via ARQ"
114
115 #define ICE_SYSCTL_HELP_FWLOG_UART_ENA \
116 "\nControl whether to enable/disable reporing to UART" \
117 "\n0 - Enable firmware reporting via UART" \
118 "\n1 - Disable firmware reporting via UART"
119
120 #define ICE_SYSCTL_HELP_FWLOG_ENABLE_ON_LOAD \
121 "\nControl whether to enable logging during the attach phase" \
122 "\n0 - Enable firmware logging during attach phase" \
123 "\n1 - Disable firmware logging during attach phase"
124
125 #define ICE_SYSCTL_HELP_FWLOG_REGISTER \
126 "\nControl whether to enable/disable firmware logging" \
127 "\n0 - Enable firmware logging" \
128 "\n1 - Disable firmware logging"
129
130 #define ICE_SYSCTL_HELP_FWLOG_MODULE_SEVERITY \
131 "\nControl the level of log output messages for this module" \
132 "\n\tverbose <4> - Verbose messages + (Error|Warning|Normal)" \
133 "\n\tnormal <3> - Normal messages + (Error|Warning)" \
134 "\n\twarning <2> - Warning messages + (Error)" \
135 "\n\terror <1> - Error messages" \
136 "\n\tnone <0> - Disables all logging for this module"
137
138 /**
139 * ice_sysctl_fwlog_set_cfg_options - Sysctl for setting fwlog cfg options
140 * @oidp: sysctl oid structure
141 * @arg1: private softc structure
142 * @arg2: option to adjust
143 * @req: sysctl request pointer
144 *
145 * On read: displays whether firmware logging was reported during attachment
146 * On write: enables/disables firmware logging during attach phase
147 *
148 * This has no effect on the legacy (V1) version of firmware logging.
149 */
150 static int
151 ice_sysctl_fwlog_set_cfg_options(SYSCTL_HANDLER_ARGS)
152 {
153 struct ice_softc *sc = (struct ice_softc *)arg1;
154 struct ice_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
155 int error;
156 u16 option = (u16)arg2;
157 bool enabled;
158
159 enabled = !!(cfg->options & option);
160
161 error = sysctl_handle_bool(oidp, &enabled, 0, req);
162 if ((error) || (req->newptr == NULL))
163 return (error);
164
165 if (enabled)
166 cfg->options |= option;
167 else
168 cfg->options &= ~option;
169
170 return ice_reconfig_fw_log(sc, cfg);
171 }
172
173 /**
174 * ice_sysctl_fwlog_log_resolution - Sysctl for setting log message resolution
175 * @oidp: sysctl oid structure
176 * @arg1: private softc structure
177 * @arg2: __unused__
178 * @req: sysctl request pointer
179 *
180 * On read: displays message queue limit before posting
181 * On write: sets message queue limit before posting
182 *
183 * This has no effect on the legacy (V1) version of firmware logging.
184 */
185 static int
186 ice_sysctl_fwlog_log_resolution(SYSCTL_HANDLER_ARGS)
187 {
188 struct ice_softc *sc = (struct ice_softc *)arg1;
189 struct ice_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
190 int error;
191 u8 resolution;
192
193 UNREFERENCED_PARAMETER(arg2);
194
195 resolution = cfg->log_resolution;
196
197 error = sysctl_handle_8(oidp, &resolution, 0, req);
198 if ((error) || (req->newptr == NULL))
199 return (error);
200
201 if ((resolution < ICE_AQC_FW_LOG_MIN_RESOLUTION) ||
202 (resolution > ICE_AQC_FW_LOG_MAX_RESOLUTION)) {
203 device_printf(sc->dev, "Log resolution out-of-bounds\n");
204 return (EINVAL);
205 }
206
207 cfg->log_resolution = resolution;
208
209 return ice_reconfig_fw_log(sc, cfg);
210 }
211
212 /**
213 * ice_sysctl_fwlog_register - Sysctl for (de)registering firmware logs
214 * @oidp: sysctl oid structure
215 * @arg1: private softc structure
216 * @arg2: __unused__
217 * @req: sysctl request pointer
218 *
219 * On read: displays whether firmware logging is registered
220 * On write: (de)registers firmware logging.
221 */
222 static int
223 ice_sysctl_fwlog_register(SYSCTL_HANDLER_ARGS)
224 {
225 struct ice_softc *sc = (struct ice_softc *)arg1;
226 struct ice_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
227 enum ice_status status;
228 int error;
229 u8 enabled;
230
231 UNREFERENCED_PARAMETER(arg2);
232
233 if (ice_test_state(&sc->state, ICE_STATE_ATTACHING)) {
234 device_printf(sc->dev, "Registering FW Logging via kenv is supported with the on_load option\n");
235 return (EIO);
236 }
237
238 if (cfg->options & ICE_FWLOG_OPTION_IS_REGISTERED)
239 enabled = true;
240 else
241 enabled = false;
242
243 error = sysctl_handle_bool(oidp, &enabled, 0, req);
244 if ((error) || (req->newptr == NULL))
245 return (error);
246
247 if (!ice_check_sq_alive(&sc->hw, &sc->hw.adminq))
248 return (0);
249
250 if (enabled) {
251 status = ice_fwlog_register(&sc->hw);
252 if (!status)
253 ice_set_bit(ICE_FEATURE_FW_LOGGING, sc->feat_en);
254 } else {
255 status = ice_fwlog_unregister(&sc->hw);
256 if (!status)
257 ice_clear_bit(ICE_FEATURE_FW_LOGGING, sc->feat_en);
258 }
259
260 if (status)
261 return (EIO);
262
263 return (0);
264 }
265
266 /**
267 * ice_sysctl_fwlog_module_log_severity - Add tunables for a FW logging module
268 * @oidp: sysctl oid structure
269 * @arg1: private softc structure
270 * @arg2: index to logging module
271 * @req: sysctl request pointer
272 */
273 static int
274 ice_sysctl_fwlog_module_log_severity(SYSCTL_HANDLER_ARGS)
275 {
276 struct ice_softc *sc = (struct ice_softc *)arg1;
277 struct ice_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
278 struct sbuf *sbuf;
279 char *sev_str_end;
280 enum ice_aqc_fw_logging_mod module = (enum ice_aqc_fw_logging_mod)arg2;
281 int error, ll_num;
282 u8 log_level;
283 char sev_str[16];
284 bool sev_set = false;
285
286 log_level = cfg->module_entries[module].log_level;
287 sbuf = sbuf_new(NULL, sev_str, sizeof(sev_str), SBUF_FIXEDLEN);
288 sbuf_printf(sbuf, "%d<%s>", log_level, ice_log_sev_str(log_level));
289 sbuf_finish(sbuf);
290 sbuf_delete(sbuf);
291
292 error = sysctl_handle_string(oidp, sev_str, sizeof(sev_str), req);
293 if ((error) || (req->newptr == NULL))
294 return (error);
295
296 if (strcasecmp(ice_log_sev_str(ICE_FWLOG_LEVEL_VERBOSE), sev_str) == 0) {
297 log_level = ICE_FWLOG_LEVEL_VERBOSE;
298 sev_set = true;
299 } else if (strcasecmp(ice_log_sev_str(ICE_FWLOG_LEVEL_NORMAL), sev_str) == 0) {
300 log_level = ICE_FWLOG_LEVEL_NORMAL;
301 sev_set = true;
302 } else if (strcasecmp(ice_log_sev_str(ICE_FWLOG_LEVEL_WARNING), sev_str) == 0) {
303 log_level = ICE_FWLOG_LEVEL_WARNING;
304 sev_set = true;
305 } else if (strcasecmp(ice_log_sev_str(ICE_FWLOG_LEVEL_ERROR), sev_str) == 0) {
306 log_level = ICE_FWLOG_LEVEL_ERROR;
307 sev_set = true;
308 } else if (strcasecmp(ice_log_sev_str(ICE_FWLOG_LEVEL_NONE), sev_str) == 0) {
309 log_level = ICE_FWLOG_LEVEL_NONE;
310 sev_set = true;
311 }
312
313 if (!sev_set) {
314 ll_num = strtol(sev_str, &sev_str_end, 0);
315 if (sev_str_end == sev_str)
316 ll_num = -1;
317 if ((ll_num >= ICE_FWLOG_LEVEL_NONE) &&
318 (ll_num < ICE_FWLOG_LEVEL_INVALID))
319 log_level = ll_num;
320 else {
321 device_printf(sc->dev,
322 "%s: \"%s\" is not a valid log level\n",
323 __func__, sev_str);
324 return (EINVAL);
325 }
326 }
327
328 cfg->module_entries[module].log_level = log_level;
329
330 return ice_reconfig_fw_log(sc, cfg);
331 }
332
333 /**
334 * ice_add_fw_logging_tunables - Add tunables to configure FW logging events
335 * @sc: private softc structure
336 * @parent: parent node to add the tunables under
337 *
338 * Add tunables for configuring the firmware logging support. This includes
339 * a control to enable the logging, and controls for each module to configure
340 * which events to receive.
341 */
342 void
343 ice_add_fw_logging_tunables(struct ice_softc *sc, struct sysctl_oid *parent)
344 {
345 struct sysctl_oid_list *parent_list, *fwlog_list, *module_list;
346 struct sysctl_oid *fwlog_node, *module_node;
347 struct sysctl_ctx_list *ctx;
348 struct ice_hw *hw = &sc->hw;
349 struct ice_fwlog_cfg *cfg;
350 device_t dev = sc->dev;
351 enum ice_aqc_fw_logging_mod module;
352 u16 i;
353
354 cfg = &hw->fwlog_cfg;
355 ctx = device_get_sysctl_ctx(dev);
356 parent_list = SYSCTL_CHILDREN(parent);
357
358 fwlog_node = SYSCTL_ADD_NODE(ctx, parent_list, OID_AUTO, "fw_log",
359 ICE_CTLFLAG_DEBUG | CTLFLAG_RD, NULL,
360 "Firmware Logging");
361 fwlog_list = SYSCTL_CHILDREN(fwlog_node);
362
363 cfg->log_resolution = 10;
364 SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "log_resolution",
365 ICE_CTLFLAG_DEBUG | CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
366 0, ice_sysctl_fwlog_log_resolution,
367 "CU", ICE_SYSCTL_HELP_FWLOG_LOG_RESOLUTION);
368
369 cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
370 SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "arq_en",
371 ICE_CTLFLAG_DEBUG | CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
372 ICE_FWLOG_OPTION_ARQ_ENA, ice_sysctl_fwlog_set_cfg_options,
373 "CU", ICE_SYSCTL_HELP_FWLOG_ARQ_ENA);
374
375 SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "uart_en",
376 ICE_CTLFLAG_DEBUG | CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
377 ICE_FWLOG_OPTION_UART_ENA, ice_sysctl_fwlog_set_cfg_options,
378 "CU", ICE_SYSCTL_HELP_FWLOG_UART_ENA);
379
380 SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "on_load",
381 ICE_CTLFLAG_DEBUG | CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
382 ICE_FWLOG_OPTION_REGISTER_ON_INIT, ice_sysctl_fwlog_set_cfg_options,
383 "CU", ICE_SYSCTL_HELP_FWLOG_ENABLE_ON_LOAD);
384
385 SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "register",
386 ICE_CTLFLAG_DEBUG | CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
387 0, ice_sysctl_fwlog_register,
388 "CU", ICE_SYSCTL_HELP_FWLOG_REGISTER);
389
390 module_node = SYSCTL_ADD_NODE(ctx, fwlog_list, OID_AUTO, "severity",
391 ICE_CTLFLAG_DEBUG | CTLFLAG_RD, NULL,
392 "Level of log output");
393
394 module_list = SYSCTL_CHILDREN(module_node);
395
396 for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
397 /* Setup some defaults */
398 cfg->module_entries[i].module_id = i;
399 cfg->module_entries[i].log_level = ICE_FWLOG_LEVEL_NONE;
400 module = (enum ice_aqc_fw_logging_mod)i;
401
402 SYSCTL_ADD_PROC(ctx, module_list,
403 OID_AUTO, ice_fw_module_str(module),
404 ICE_CTLFLAG_DEBUG | CTLTYPE_STRING | CTLFLAG_RWTUN, sc,
405 module, ice_sysctl_fwlog_module_log_severity,
406 "A", ICE_SYSCTL_HELP_FWLOG_MODULE_SEVERITY);
407 }
408 }
409
410 /**
411 * ice_handle_fw_log_event - Handle a firmware logging event from the AdminQ
412 * @sc: pointer to private softc structure
413 * @desc: the AdminQ descriptor for this firmware event
414 * @buf: pointer to the buffer accompanying the AQ message
415 */
416 void
417 ice_handle_fw_log_event(struct ice_softc *sc, struct ice_aq_desc *desc,
418 void *buf)
419 {
420 /* Trigger a DTrace probe event for this firmware message */
421 SDT_PROBE2(ice_fwlog, , , message, (const u8 *)buf, desc->datalen);
422
423 /* Possibly dump the firmware message to the console, if enabled */
424 ice_fwlog_event_dump(&sc->hw, desc, buf);
425 }
Cache object: 088dd353d791d8fdbee65fa77016c50c
|