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