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