1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2024, 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 32 #include "ice_osdep.h" 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 int 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 0; 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 int 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 int 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 int 213 ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg) 214 { 215 int 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 int 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 int 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 int 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 int ice_fwlog_register(struct ice_hw *hw) 329 { 330 int 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 int ice_fwlog_unregister(struct ice_hw *hw) 349 { 350 int 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 int 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 u16 i, module_id_cnt; 376 int status; 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 int 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 int 470 ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg) 471 { 472 int 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 0; 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 } 506 507