xref: /freebsd/sys/dev/ixgbe/ixgbe_fw_logging.c (revision 6b58d10fc6d51ddcf5ee81628ead74d3dadb9bf6)
1 /**
2  * @file ixgbe_fw_logging.c
3  * @brief firmware logging sysctls
4  *
5  * Contains sysctls to enable and configure firmware logging debug support.
6  */
7 
8  #include "ixgbe.h"
9 
10  /**
11   * ixgbe_reconfig_fw_log - Re-program firmware logging configuration
12   * @sc: private softc structure
13   * @cfg: firmware log configuration to latch
14   *
15   * If the adminq is currently active, ask firmware to update the logging
16   * configuration. If the adminq is currently down, then do nothing. In this
17   * case, ixgbe_init_hw() will re-configure firmware logging as soon as it brings
18   * up the adminq.
19   */
20  static int
ixgbe_reconfig_fw_log(struct ixgbe_softc * sc,struct ixgbe_fwlog_cfg * cfg)21  ixgbe_reconfig_fw_log(struct ixgbe_softc *sc, struct ixgbe_fwlog_cfg *cfg)
22  {
23          int status;
24 
25          ixgbe_fwlog_init(&sc->hw, cfg);
26 
27          if (!ixgbe_fwlog_supported(&sc->hw))
28                  return (0);
29 
30          status = ixgbe_fwlog_set(&sc->hw, cfg);
31          if (status != IXGBE_SUCCESS) {
32                  DEBUGOUT1("Failed to reconfigure firmware logging, status %d\n",
33                      status);
34                  return (ENODEV);
35          }
36 
37          return (0);
38  }
39 
40  /**
41   * ixgbe_sysctl_fwlog_set_cfg_options - Sysctl for setting fwlog cfg options
42   * @oidp: sysctl oid structure
43   * @arg1: private softc structure
44   * @arg2: option to adjust
45   * @req: sysctl request pointer
46   *
47   * On read: displays whether firmware logging was reported during attachment
48   * On write: enables/disables firmware logging during attach phase
49   *
50   * This has no effect on the legacy (V1) version of firmware logging.
51   */
52  static int
ixgbe_sysctl_fwlog_set_cfg_options(SYSCTL_HANDLER_ARGS)53  ixgbe_sysctl_fwlog_set_cfg_options(SYSCTL_HANDLER_ARGS)
54  {
55          struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
56          struct ixgbe_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
57          int error;
58          u16 option = (u16)arg2;
59          bool enabled;
60 
61          enabled = !!(cfg->options & option);
62 
63          error = sysctl_handle_bool(oidp, &enabled, 0, req);
64          if ((error) || (req->newptr == NULL))
65                  return (error);
66 
67          if (enabled)
68                  cfg->options |= option;
69          else
70                  cfg->options &= ~option;
71 
72          return ixgbe_reconfig_fw_log(sc, cfg);
73  }
74 
75  /**
76   * ixgbe_sysctl_fwlog_log_resolution - Sysctl for setting log message resolution
77   * @oidp: sysctl oid structure
78   * @arg1: private softc structure
79   * @arg2: __unused__
80   * @req: sysctl request pointer
81   *
82   * On read: displays message queue limit before posting
83   * On write: sets message queue limit before posting
84   *
85   * This has no effect on the legacy (V1) version of firmware logging.
86   */
87  static int
ixgbe_sysctl_fwlog_log_resolution(SYSCTL_HANDLER_ARGS)88  ixgbe_sysctl_fwlog_log_resolution(SYSCTL_HANDLER_ARGS)
89  {
90          struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
91          struct ixgbe_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
92          int error;
93          u8 resolution;
94 
95          UNREFERENCED_PARAMETER(arg2);
96 
97          resolution = cfg->log_resolution;
98 
99          error = sysctl_handle_8(oidp, &resolution, 0, req);
100          if ((error) || (req->newptr == NULL))
101                  return (error);
102 
103          if ((resolution < IXGBE_ACI_FW_LOG_MIN_RESOLUTION) ||
104              (resolution > IXGBE_ACI_FW_LOG_MAX_RESOLUTION)) {
105                  DEBUGOUT("Log resolution out-of-bounds\n");
106                  return (EINVAL);
107          }
108 
109          cfg->log_resolution = resolution;
110 
111          return ixgbe_reconfig_fw_log(sc, cfg);
112  }
113 
114  /**
115   * ixgbe_sysctl_fwlog_register - Sysctl for (de)registering firmware logs
116   * @oidp: sysctl oid structure
117   * @arg1: private softc structure
118   * @arg2: __unused__
119   * @req: sysctl request pointer
120   *
121   * On read: displays whether firmware logging is registered
122   * On write: (de)registers firmware logging.
123   */
124  static int
ixgbe_sysctl_fwlog_register(SYSCTL_HANDLER_ARGS)125  ixgbe_sysctl_fwlog_register(SYSCTL_HANDLER_ARGS)
126  {
127          struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
128          struct ixgbe_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
129          int status;
130          int error;
131          u8 enabled;
132 
133          UNREFERENCED_PARAMETER(arg2);
134 
135          if (cfg->options & IXGBE_FWLOG_OPTION_IS_REGISTERED)
136                  enabled = true;
137          else
138                  enabled = false;
139 
140          error = sysctl_handle_bool(oidp, &enabled, 0, req);
141          if ((error) || (req->newptr == NULL))
142                  return (error);
143 
144          if (enabled) {
145                  status = ixgbe_fwlog_register(&sc->hw);
146                  if (status == IXGBE_SUCCESS)
147                          sc->feat_en |= IXGBE_FEATURE_FW_LOGGING;
148          } else {
149                  status = ixgbe_fwlog_unregister(&sc->hw);
150                  if (status == IXGBE_SUCCESS)
151                          sc->feat_en &= ~IXGBE_FEATURE_FW_LOGGING;
152          }
153 
154          if (status != IXGBE_SUCCESS)
155                  return (EIO);
156 
157          return (0);
158  }
159 
160  /**
161   * ixgbe_log_sev_str - Convert log level to a string
162   * @log_level: the log level to convert
163   *
164   * Convert the u8 log level of a FW logging module into a readable
165   * string for outputting in a sysctl.
166   */
167  struct ixgbe_str_buf {
168          char str[IXGBE_STR_BUF_LEN];
169  };
170 
171  static struct ixgbe_str_buf
_ixgbe_log_sev_str(u8 log_level)172  _ixgbe_log_sev_str(u8 log_level)
173  {
174          struct ixgbe_str_buf buf = { .str = "" };
175          const char *str = NULL;
176 
177          switch (log_level) {
178          case IXGBE_FWLOG_LEVEL_NONE:
179                  str = "none";
180                  break;
181          case IXGBE_FWLOG_LEVEL_ERROR:
182                  str = "error";
183                  break;
184          case IXGBE_FWLOG_LEVEL_WARNING:
185                  str = "warning";
186                  break;
187          case IXGBE_FWLOG_LEVEL_NORMAL:
188                  str = "normal";
189                  break;
190          case IXGBE_FWLOG_LEVEL_VERBOSE:
191                  str = "verbose";
192                  break;
193          default:
194                  break;
195          }
196 
197          if (str)
198                  snprintf(buf.str, IXGBE_STR_BUF_LEN, "%s", str);
199          else
200                  snprintf(buf.str, IXGBE_STR_BUF_LEN, "%u", log_level);
201 
202          return buf;
203  }
204 
205  #define ixgbe_log_sev_str(log_level) _ixgbe_log_sev_str(log_level).str
206 
207  /**
208   * ixgbe_sysctl_fwlog_module_log_severity - Add tunables for a FW logging module
209   * @oidp: sysctl oid structure
210   * @arg1: private softc structure
211   * @arg2: index to logging module
212   * @req: sysctl request pointer
213   */
214  static int
ixgbe_sysctl_fwlog_module_log_severity(SYSCTL_HANDLER_ARGS)215  ixgbe_sysctl_fwlog_module_log_severity(SYSCTL_HANDLER_ARGS)
216  {
217          struct ixgbe_softc *sc = (struct ixgbe_softc *)arg1;
218          struct ixgbe_fwlog_cfg *cfg = &sc->hw.fwlog_cfg;
219          struct sbuf *sbuf;
220          char *sev_str_end;
221          enum ixgbe_aci_fw_logging_mod module = (enum ixgbe_aci_fw_logging_mod)arg2;
222          int error, ll_num;
223          u8 log_level;
224          char sev_str[16];
225          bool sev_set = false;
226 
227          log_level = cfg->module_entries[module].log_level;
228          sbuf = sbuf_new(NULL, sev_str, sizeof(sev_str), SBUF_FIXEDLEN);
229          sbuf_printf(sbuf, "%d<%s>", log_level, ixgbe_log_sev_str(log_level));
230          sbuf_finish(sbuf);
231          sbuf_delete(sbuf);
232 
233          error = sysctl_handle_string(oidp, sev_str, sizeof(sev_str), req);
234          if ((error) || (req->newptr == NULL))
235                  return (error);
236 
237          if (strcasecmp(ixgbe_log_sev_str(IXGBE_FWLOG_LEVEL_VERBOSE), sev_str) == 0) {
238                  log_level = IXGBE_FWLOG_LEVEL_VERBOSE;
239                  sev_set = true;
240          } else if (strcasecmp(ixgbe_log_sev_str(IXGBE_FWLOG_LEVEL_NORMAL), sev_str) == 0) {
241                  log_level = IXGBE_FWLOG_LEVEL_NORMAL;
242                  sev_set = true;
243          } else if (strcasecmp(ixgbe_log_sev_str(IXGBE_FWLOG_LEVEL_WARNING), sev_str) == 0) {
244                  log_level = IXGBE_FWLOG_LEVEL_WARNING;
245                  sev_set = true;
246          } else if (strcasecmp(ixgbe_log_sev_str(IXGBE_FWLOG_LEVEL_ERROR), sev_str) == 0) {
247                  log_level = IXGBE_FWLOG_LEVEL_ERROR;
248                  sev_set = true;
249          } else if (strcasecmp(ixgbe_log_sev_str(IXGBE_FWLOG_LEVEL_NONE), sev_str) == 0) {
250                  log_level = IXGBE_FWLOG_LEVEL_NONE;
251                  sev_set = true;
252          }
253 
254          if (!sev_set) {
255                  ll_num = strtol(sev_str, &sev_str_end, 0);
256                  if (sev_str_end == sev_str)
257                          ll_num = -1;
258                  if ((ll_num >= IXGBE_FWLOG_LEVEL_NONE) &&
259                      (ll_num < IXGBE_FWLOG_LEVEL_INVALID))
260                          log_level = ll_num;
261                  else {
262                          DEBUGOUT2("%s: \"%s\" is not a valid log level\n",
263                              __func__, sev_str);
264                          return (EINVAL);
265                  }
266          }
267 
268          cfg->module_entries[module].log_level = log_level;
269 
270          return ixgbe_reconfig_fw_log(sc, cfg);
271  }
272 
273  #define IXGBE_SYSCTL_HELP_FWLOG_LOG_RESOLUTION				\
274  "\nControl firmware message limit to send per ARQ event"		\
275  "\t\nMin: 1"								\
276  "\t\nMax: 128"
277 
278  #define IXGBE_SYSCTL_HELP_FWLOG_ARQ_ENA					\
279  "\nControl whether to enable/disable reporting to admin Rx queue"	\
280  "\n1 - Enable firmware reporting via ARQ"				\
281  "\n0 - Disable firmware reporting via ARQ"
282 
283  #define IXGBE_SYSCTL_HELP_FWLOG_UART_ENA					\
284  "\nControl whether to enable/disable reporting to UART"			\
285  "\n1 - Enable firmware reporting via UART"				\
286  "\n0 - Disable firmware reporting via UART"
287 
288  #define IXGBE_SYSCTL_HELP_FWLOG_ENABLE_ON_LOAD				\
289  "\nControl whether to enable logging during the attach phase"		\
290  "\n1 - Enable firmware logging during attach phase"			\
291  "\n0 - Disable firmware logging during attach phase"
292 
293  #define IXGBE_SYSCTL_HELP_FWLOG_REGISTER					\
294  "\nControl whether to enable/disable firmware logging"			\
295  "\n1 - Enable firmware logging"						\
296  "\n0 - Disable firmware logging"
297 
298  #define IXGBE_SYSCTL_HELP_FWLOG_MODULE_SEVERITY				\
299  "\nControl the level of log output messages for this module"		\
300  "\n\tverbose <4> - Verbose messages + (Error|Warning|Normal)"		\
301  "\n\tnormal  <3> - Normal messages  + (Error|Warning)"			\
302  "\n\twarning <2> - Warning messages + (Error)"				\
303  "\n\terror   <1> - Error messages"					\
304  "\n\tnone    <0> - Disables all logging for this module"
305 
306  /**
307   * ixgbe_fw_module_str - Convert a FW logging module to a string name
308   * @module: the module to convert
309   *
310   * Given a FW logging module id, convert it to a shorthand human readable
311   * name, for generating sysctl tunables.
312   */
313  static const char *
ixgbe_fw_module_str(enum ixgbe_aci_fw_logging_mod module)314  ixgbe_fw_module_str(enum ixgbe_aci_fw_logging_mod module)
315  {
316          switch (module) {
317          case IXGBE_ACI_FW_LOG_ID_GENERAL:
318                  return "general";
319          case IXGBE_ACI_FW_LOG_ID_CTRL:
320                  return "ctrl";
321          case IXGBE_ACI_FW_LOG_ID_LINK:
322                  return "link";
323          case IXGBE_ACI_FW_LOG_ID_LINK_TOPO:
324                  return "link_topo";
325          case IXGBE_ACI_FW_LOG_ID_DNL:
326                  return "dnl";
327          case IXGBE_ACI_FW_LOG_ID_I2C:
328                  return "i2c";
329          case IXGBE_ACI_FW_LOG_ID_SDP:
330                  return "sdp";
331          case IXGBE_ACI_FW_LOG_ID_MDIO:
332                  return "mdio";
333          case IXGBE_ACI_FW_LOG_ID_ADMINQ:
334                  return "adminq";
335          case IXGBE_ACI_FW_LOG_ID_HDMA:
336                  return "hdma";
337          case IXGBE_ACI_FW_LOG_ID_LLDP:
338                  return "lldp";
339          case IXGBE_ACI_FW_LOG_ID_DCBX:
340                  return "dcbx";
341          case IXGBE_ACI_FW_LOG_ID_DCB:
342                  return "dcb";
343          case IXGBE_ACI_FW_LOG_ID_XLR:
344                  return "xlr";
345          case IXGBE_ACI_FW_LOG_ID_NVM:
346                  return "nvm";
347          case IXGBE_ACI_FW_LOG_ID_AUTH:
348                  return "auth";
349          case IXGBE_ACI_FW_LOG_ID_VPD:
350                  return "vpd";
351          case IXGBE_ACI_FW_LOG_ID_IOSF:
352                  return "iosf";
353          case IXGBE_ACI_FW_LOG_ID_PARSER:
354                  return "parser";
355          case IXGBE_ACI_FW_LOG_ID_SW:
356                  return "sw";
357          case IXGBE_ACI_FW_LOG_ID_SCHEDULER:
358                  return "scheduler";
359          case IXGBE_ACI_FW_LOG_ID_TXQ:
360                  return "txq";
361          case IXGBE_ACI_FW_LOG_ID_ACL:
362                  return "acl";
363          case IXGBE_ACI_FW_LOG_ID_POST:
364                  return "post";
365          case IXGBE_ACI_FW_LOG_ID_WATCHDOG:
366                  return "watchdog";
367          case IXGBE_ACI_FW_LOG_ID_TASK_DISPATCH:
368                  return "task_dispatch";
369          case IXGBE_ACI_FW_LOG_ID_MNG:
370                  return "mng";
371          case IXGBE_ACI_FW_LOG_ID_SYNCE:
372                  return "synce";
373          case IXGBE_ACI_FW_LOG_ID_HEALTH:
374                  return "health";
375          case IXGBE_ACI_FW_LOG_ID_TSDRV:
376                  return "tsdrv";
377          case IXGBE_ACI_FW_LOG_ID_PFREG:
378                  return "pfreg";
379          case IXGBE_ACI_FW_LOG_ID_MDLVER:
380                  return "mdlver";
381          case IXGBE_ACI_FW_LOG_ID_MAX:
382                  return "unknown";
383          }
384 
385          /* The compiler generates errors on unhandled enum values if we omit
386           * the default case.
387           */
388          return "unknown";
389  }
390 
391  /**
392   * ixgbe_add_fw_logging_tunables - Add tunables to configure FW logging events
393   * @sc: private softc structure
394   * @parent: parent node to add the tunables under
395   *
396   * Add tunables for configuring the firmware logging support. This includes
397   * a control to enable the logging, and controls for each module to configure
398   * which events to receive.
399   */
400  void
ixgbe_add_fw_logging_tunables(struct ixgbe_softc * sc,struct sysctl_oid * parent)401  ixgbe_add_fw_logging_tunables(struct ixgbe_softc *sc, struct sysctl_oid *parent)
402  {
403          struct sysctl_oid_list *parent_list, *fwlog_list, *module_list;
404          struct sysctl_oid *fwlog_node, *module_node;
405          struct sysctl_ctx_list *ctx;
406          struct ixgbe_hw *hw = &sc->hw;
407          struct ixgbe_fwlog_cfg *cfg;
408          device_t dev = sc->dev;
409          enum ixgbe_aci_fw_logging_mod module;
410          u16 i;
411 
412          cfg = &hw->fwlog_cfg;
413          ctx = device_get_sysctl_ctx(dev);
414          parent_list = SYSCTL_CHILDREN(parent);
415 
416          fwlog_node = SYSCTL_ADD_NODE(ctx, parent_list, OID_AUTO, "fw_log",
417                                       CTLFLAG_RD, NULL,
418                                       "Firmware Logging");
419          fwlog_list = SYSCTL_CHILDREN(fwlog_node);
420 
421          cfg->log_resolution = 10;
422          SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "log_resolution",
423              CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
424              0, ixgbe_sysctl_fwlog_log_resolution,
425              "CU", IXGBE_SYSCTL_HELP_FWLOG_LOG_RESOLUTION);
426 
427          cfg->options |= IXGBE_FWLOG_OPTION_ARQ_ENA;
428          SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "arq_en",
429              CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
430              IXGBE_FWLOG_OPTION_ARQ_ENA, ixgbe_sysctl_fwlog_set_cfg_options,
431              "CU", IXGBE_SYSCTL_HELP_FWLOG_ARQ_ENA);
432 
433          SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "uart_en",
434              CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
435              IXGBE_FWLOG_OPTION_UART_ENA, ixgbe_sysctl_fwlog_set_cfg_options,
436              "CU", IXGBE_SYSCTL_HELP_FWLOG_UART_ENA);
437 
438          SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "on_load",
439              CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
440              IXGBE_FWLOG_OPTION_REGISTER_ON_INIT, ixgbe_sysctl_fwlog_set_cfg_options,
441              "CU", IXGBE_SYSCTL_HELP_FWLOG_ENABLE_ON_LOAD);
442 
443          SYSCTL_ADD_PROC(ctx, fwlog_list, OID_AUTO, "register",
444              CTLTYPE_U8 | CTLFLAG_RWTUN, sc,
445              0, ixgbe_sysctl_fwlog_register,
446              "CU", IXGBE_SYSCTL_HELP_FWLOG_REGISTER);
447 
448          module_node = SYSCTL_ADD_NODE(ctx, fwlog_list, OID_AUTO, "severity",
449                                        CTLFLAG_RD, NULL,
450                                        "Level of log output");
451 
452          module_list = SYSCTL_CHILDREN(module_node);
453 
454          for (i = 0; i < IXGBE_ACI_FW_LOG_ID_MAX; i++) {
455                  /* Setup some defaults */
456                  cfg->module_entries[i].module_id = i;
457                  cfg->module_entries[i].log_level = IXGBE_FWLOG_LEVEL_NONE;
458                  module = (enum ixgbe_aci_fw_logging_mod)i;
459 
460                  SYSCTL_ADD_PROC(ctx, module_list,
461                      OID_AUTO, ixgbe_fw_module_str(module),
462                      CTLTYPE_STRING | CTLFLAG_RWTUN, sc,
463                      module, ixgbe_sysctl_fwlog_module_log_severity,
464                      "A", IXGBE_SYSCTL_HELP_FWLOG_MODULE_SEVERITY);
465          }
466  }
467