1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2024, Intel Corporation. */ 3 4 #include "ice.h" 5 #include "ice_adminq_cmd.h" /* for enum ice_aqc_health_status_elem */ 6 #include "health.h" 7 8 #define ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, obj, name) \ 9 devlink_fmsg_put(fmsg, #name, (obj)->name) 10 11 #define ICE_HEALTH_STATUS_DATA_SIZE 2 12 13 struct ice_health_status { 14 enum ice_aqc_health_status code; 15 const char *description; 16 const char *solution; 17 const char *data_label[ICE_HEALTH_STATUS_DATA_SIZE]; 18 }; 19 20 /* 21 * In addition to the health status codes provided below, the firmware might 22 * generate Health Status Codes that are not pertinent to the end-user. 23 * For instance, Health Code 0x1002 is triggered when the command fails. 24 * Such codes should be disregarded by the end-user. 25 * The below lookup requires to be sorted by code. 26 */ 27 28 static const char ice_common_port_solutions[] = 29 "Check your cable connection. Change or replace the module or cable. Manually set speed and duplex."; 30 static const char ice_port_number_label[] = "Port Number"; 31 static const char ice_update_nvm_solution[] = "Update to the latest NVM image."; 32 33 static const struct ice_health_status ice_health_status_lookup[] = { 34 {ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_STRICT, "An unsupported module was detected.", 35 ice_common_port_solutions, {ice_port_number_label}}, 36 {ICE_AQC_HEALTH_STATUS_ERR_MOD_TYPE, "Module type is not supported.", 37 "Change or replace the module or cable.", {ice_port_number_label}}, 38 {ICE_AQC_HEALTH_STATUS_ERR_MOD_QUAL, "Module is not qualified.", 39 ice_common_port_solutions, {ice_port_number_label}}, 40 {ICE_AQC_HEALTH_STATUS_ERR_MOD_COMM, 41 "Device cannot communicate with the module.", 42 "Check your cable connection. Change or replace the module or cable. Manually set speed and duplex.", 43 {ice_port_number_label}}, 44 {ICE_AQC_HEALTH_STATUS_ERR_MOD_CONFLICT, "Unresolved module conflict.", 45 "Manually set speed/duplex or change the port option. If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.", 46 {ice_port_number_label}}, 47 {ICE_AQC_HEALTH_STATUS_ERR_MOD_NOT_PRESENT, "Module is not present.", 48 "Check that the module is inserted correctly. If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.", 49 {ice_port_number_label}}, 50 {ICE_AQC_HEALTH_STATUS_INFO_MOD_UNDERUTILIZED, "Underutilized module.", 51 "Change or replace the module or cable. Change the port option.", 52 {ice_port_number_label}}, 53 {ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_LENIENT, "An unsupported module was detected.", 54 ice_common_port_solutions, {ice_port_number_label}}, 55 {ICE_AQC_HEALTH_STATUS_ERR_INVALID_LINK_CFG, "Invalid link configuration.", 56 NULL, {ice_port_number_label}}, 57 {ICE_AQC_HEALTH_STATUS_ERR_PORT_ACCESS, "Port hardware access error.", 58 ice_update_nvm_solution, {ice_port_number_label}}, 59 {ICE_AQC_HEALTH_STATUS_ERR_PORT_UNREACHABLE, "A port is unreachable.", 60 "Change the port option. Update to the latest NVM image."}, 61 {ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_MOD_LIMITED, "Port speed is limited due to module.", 62 "Change the module or configure the port option to match the current module speed. Change the port option.", 63 {ice_port_number_label}}, 64 {ICE_AQC_HEALTH_STATUS_ERR_PARALLEL_FAULT, 65 "All configured link modes were attempted but failed to establish link. The device will restart the process to establish link.", 66 "Check link partner connection and configuration.", 67 {ice_port_number_label}}, 68 {ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_PHY_LIMITED, 69 "Port speed is limited by PHY capabilities.", 70 "Change the module to align to port option.", {ice_port_number_label}}, 71 {ICE_AQC_HEALTH_STATUS_ERR_NETLIST_TOPO, "LOM topology netlist is corrupted.", 72 ice_update_nvm_solution, {ice_port_number_label}}, 73 {ICE_AQC_HEALTH_STATUS_ERR_NETLIST, "Unrecoverable netlist error.", 74 ice_update_nvm_solution, {ice_port_number_label}}, 75 {ICE_AQC_HEALTH_STATUS_ERR_TOPO_CONFLICT, "Port topology conflict.", 76 "Change the port option. Update to the latest NVM image."}, 77 {ICE_AQC_HEALTH_STATUS_ERR_LINK_HW_ACCESS, "Unrecoverable hardware access error.", 78 ice_update_nvm_solution, {ice_port_number_label}}, 79 {ICE_AQC_HEALTH_STATUS_ERR_LINK_RUNTIME, "Unrecoverable runtime error.", 80 ice_update_nvm_solution, {ice_port_number_label}}, 81 {ICE_AQC_HEALTH_STATUS_ERR_DNL_INIT, "Link management engine failed to initialize.", 82 ice_update_nvm_solution, {ice_port_number_label}}, 83 {ICE_AQC_HEALTH_STATUS_ERR_PHY_FW_LOAD, 84 "Failed to load the firmware image in the external PHY.", 85 ice_update_nvm_solution, {ice_port_number_label}}, 86 {ICE_AQC_HEALTH_STATUS_INFO_RECOVERY, "The device is in firmware recovery mode.", 87 ice_update_nvm_solution, {"Extended Error"}}, 88 {ICE_AQC_HEALTH_STATUS_ERR_FLASH_ACCESS, "The flash chip cannot be accessed.", 89 "If issue persists, call customer support.", {"Access Type"}}, 90 {ICE_AQC_HEALTH_STATUS_ERR_NVM_AUTH, "NVM authentication failed.", 91 ice_update_nvm_solution}, 92 {ICE_AQC_HEALTH_STATUS_ERR_OROM_AUTH, "Option ROM authentication failed.", 93 ice_update_nvm_solution}, 94 {ICE_AQC_HEALTH_STATUS_ERR_DDP_AUTH, "DDP package authentication failed.", 95 "Update to latest base driver and DDP package."}, 96 {ICE_AQC_HEALTH_STATUS_ERR_NVM_COMPAT, "NVM image is incompatible.", 97 ice_update_nvm_solution}, 98 {ICE_AQC_HEALTH_STATUS_ERR_OROM_COMPAT, "Option ROM is incompatible.", 99 ice_update_nvm_solution, {"Expected PCI Device ID", "Expected Module ID"}}, 100 {ICE_AQC_HEALTH_STATUS_ERR_DCB_MIB, 101 "Supplied MIB file is invalid. DCB reverted to default configuration.", 102 "Disable FW-LLDP and check DCBx system configuration.", 103 {ice_port_number_label, "MIB ID"}}, 104 }; 105 106 static int ice_health_status_lookup_compare(const void *a, const void *b) 107 { 108 return ((struct ice_health_status *)a)->code - ((struct ice_health_status *)b)->code; 109 } 110 111 static const struct ice_health_status *ice_get_health_status(u16 code) 112 { 113 struct ice_health_status key = { .code = code }; 114 115 return bsearch(&key, ice_health_status_lookup, ARRAY_SIZE(ice_health_status_lookup), 116 sizeof(struct ice_health_status), ice_health_status_lookup_compare); 117 } 118 119 static void ice_describe_status_code(struct devlink_fmsg *fmsg, 120 struct ice_aqc_health_status_elem *hse) 121 { 122 static const char *const aux_label[] = { "Aux Data 1", "Aux Data 2" }; 123 const struct ice_health_status *health_code; 124 u32 internal_data[2]; 125 u16 status_code; 126 127 status_code = le16_to_cpu(hse->health_status_code); 128 129 devlink_fmsg_put(fmsg, "Syndrome", status_code); 130 if (status_code) { 131 internal_data[0] = le32_to_cpu(hse->internal_data1); 132 internal_data[1] = le32_to_cpu(hse->internal_data2); 133 134 health_code = ice_get_health_status(status_code); 135 if (!health_code) 136 return; 137 138 devlink_fmsg_string_pair_put(fmsg, "Description", health_code->description); 139 if (health_code->solution) 140 devlink_fmsg_string_pair_put(fmsg, "Possible Solution", 141 health_code->solution); 142 143 for (size_t i = 0; i < ICE_HEALTH_STATUS_DATA_SIZE; i++) { 144 if (internal_data[i] != ICE_AQC_HEALTH_STATUS_UNDEFINED_DATA) 145 devlink_fmsg_u32_pair_put(fmsg, 146 health_code->data_label[i] ? 147 health_code->data_label[i] : 148 aux_label[i], 149 internal_data[i]); 150 } 151 } 152 } 153 154 static int 155 ice_port_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, 156 struct netlink_ext_ack *extack) 157 { 158 struct ice_pf *pf = devlink_health_reporter_priv(reporter); 159 160 ice_describe_status_code(fmsg, &pf->health_reporters.port_status); 161 return 0; 162 } 163 164 static int 165 ice_port_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, 166 void *priv_ctx, struct netlink_ext_ack __always_unused *extack) 167 { 168 struct ice_pf *pf = devlink_health_reporter_priv(reporter); 169 170 ice_describe_status_code(fmsg, &pf->health_reporters.port_status); 171 return 0; 172 } 173 174 static int 175 ice_fw_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, 176 struct netlink_ext_ack *extack) 177 { 178 struct ice_pf *pf = devlink_health_reporter_priv(reporter); 179 180 ice_describe_status_code(fmsg, &pf->health_reporters.fw_status); 181 return 0; 182 } 183 184 static int 185 ice_fw_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, 186 void *priv_ctx, struct netlink_ext_ack *extack) 187 { 188 struct ice_pf *pf = devlink_health_reporter_priv(reporter); 189 190 ice_describe_status_code(fmsg, &pf->health_reporters.fw_status); 191 return 0; 192 } 193 194 static void ice_config_health_events(struct ice_pf *pf, bool enable) 195 { 196 u8 enable_bits = 0; 197 int ret; 198 199 if (enable) 200 enable_bits = ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK | 201 ICE_AQC_HEALTH_STATUS_SET_GLOBAL_MASK; 202 203 ret = ice_aq_set_health_status_cfg(&pf->hw, enable_bits); 204 if (ret) 205 dev_err(ice_pf_to_dev(pf), "Failed to %s firmware health events, err %d aq_err %s\n", 206 str_enable_disable(enable), ret, 207 libie_aq_str(pf->hw.adminq.sq_last_status)); 208 } 209 210 /** 211 * ice_process_health_status_event - Process the health status event from FW 212 * @pf: pointer to the PF structure 213 * @event: event structure containing the Health Status Event opcode 214 * 215 * Decode the Health Status Events and print the associated messages 216 */ 217 void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info *event) 218 { 219 const struct ice_aqc_health_status_elem *health_info; 220 const struct ice_aqc_get_health_status *cmd; 221 u16 count; 222 223 health_info = (struct ice_aqc_health_status_elem *)event->msg_buf; 224 cmd = libie_aq_raw(&event->desc); 225 count = le16_to_cpu(cmd->health_status_count); 226 227 if (count > (event->buf_len / sizeof(*health_info))) { 228 dev_err(ice_pf_to_dev(pf), "Received a health status event with invalid element count\n"); 229 return; 230 } 231 232 for (size_t i = 0; i < count; i++) { 233 const struct ice_health_status *health_code; 234 u16 status_code; 235 236 status_code = le16_to_cpu(health_info->health_status_code); 237 health_code = ice_get_health_status(status_code); 238 239 if (health_code) { 240 switch (le16_to_cpu(health_info->event_source)) { 241 case ICE_AQC_HEALTH_STATUS_GLOBAL: 242 pf->health_reporters.fw_status = *health_info; 243 devlink_health_report(pf->health_reporters.fw, 244 "FW syndrome reported", NULL); 245 break; 246 case ICE_AQC_HEALTH_STATUS_PF: 247 case ICE_AQC_HEALTH_STATUS_PORT: 248 pf->health_reporters.port_status = *health_info; 249 devlink_health_report(pf->health_reporters.port, 250 "Port syndrome reported", NULL); 251 break; 252 default: 253 dev_err(ice_pf_to_dev(pf), "Health code with unknown source\n"); 254 } 255 } else { 256 u32 data1, data2; 257 u16 source; 258 259 source = le16_to_cpu(health_info->event_source); 260 data1 = le32_to_cpu(health_info->internal_data1); 261 data2 = le32_to_cpu(health_info->internal_data2); 262 dev_dbg(ice_pf_to_dev(pf), 263 "Received internal health status code 0x%08x, source: 0x%08x, data1: 0x%08x, data2: 0x%08x", 264 status_code, source, data1, data2); 265 } 266 health_info++; 267 } 268 } 269 270 /** 271 * ice_devlink_health_report - boilerplate to call given @reporter 272 * 273 * @reporter: devlink health reporter to call, do nothing on NULL 274 * @msg: message to pass up, "event name" is fine 275 * @priv_ctx: typically some event struct 276 */ 277 static void ice_devlink_health_report(struct devlink_health_reporter *reporter, 278 const char *msg, void *priv_ctx) 279 { 280 if (!reporter) 281 return; 282 283 /* We do not do auto recovering, so return value of the below function 284 * will always be 0, thus we do ignore it. 285 */ 286 devlink_health_report(reporter, msg, priv_ctx); 287 } 288 289 struct ice_mdd_event { 290 enum ice_mdd_src src; 291 u16 vf_num; 292 u16 queue; 293 u8 pf_num; 294 u8 event; 295 }; 296 297 static const char *ice_mdd_src_to_str(enum ice_mdd_src src) 298 { 299 switch (src) { 300 case ICE_MDD_SRC_TX_PQM: 301 return "tx_pqm"; 302 case ICE_MDD_SRC_TX_TCLAN: 303 return "tx_tclan"; 304 case ICE_MDD_SRC_TX_TDPU: 305 return "tx_tdpu"; 306 case ICE_MDD_SRC_RX: 307 return "rx"; 308 default: 309 return "invalid"; 310 } 311 } 312 313 static int 314 ice_mdd_reporter_dump(struct devlink_health_reporter *reporter, 315 struct devlink_fmsg *fmsg, void *priv_ctx, 316 struct netlink_ext_ack *extack) 317 { 318 struct ice_mdd_event *mdd_event = priv_ctx; 319 const char *src; 320 321 if (!mdd_event) 322 return 0; 323 324 src = ice_mdd_src_to_str(mdd_event->src); 325 326 devlink_fmsg_obj_nest_start(fmsg); 327 devlink_fmsg_put(fmsg, "src", src); 328 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, pf_num); 329 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, vf_num); 330 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, event); 331 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, queue); 332 devlink_fmsg_obj_nest_end(fmsg); 333 334 return 0; 335 } 336 337 /** 338 * ice_report_mdd_event - Report an MDD event through devlink health 339 * @pf: the PF device structure 340 * @src: the HW block that was the source of this MDD event 341 * @pf_num: the pf_num on which the MDD event occurred 342 * @vf_num: the vf_num on which the MDD event occurred 343 * @event: the event type of the MDD event 344 * @queue: the queue on which the MDD event occurred 345 * 346 * Report an MDD event that has occurred on this PF. 347 */ 348 void ice_report_mdd_event(struct ice_pf *pf, enum ice_mdd_src src, u8 pf_num, 349 u16 vf_num, u8 event, u16 queue) 350 { 351 struct ice_mdd_event ev = { 352 .src = src, 353 .pf_num = pf_num, 354 .vf_num = vf_num, 355 .event = event, 356 .queue = queue, 357 }; 358 359 ice_devlink_health_report(pf->health_reporters.mdd, "MDD event", &ev); 360 } 361 362 /** 363 * ice_fmsg_put_ptr - put hex value of pointer into fmsg 364 * 365 * @fmsg: devlink fmsg under construction 366 * @name: name to pass 367 * @ptr: 64 bit value to print as hex and put into fmsg 368 */ 369 static void ice_fmsg_put_ptr(struct devlink_fmsg *fmsg, const char *name, 370 void *ptr) 371 { 372 char buf[sizeof(ptr) * 3]; 373 374 sprintf(buf, "%p", ptr); 375 devlink_fmsg_put(fmsg, name, buf); 376 } 377 378 struct ice_tx_hang_event { 379 u32 head; 380 u32 intr; 381 u16 vsi_num; 382 u16 queue; 383 u16 next_to_clean; 384 u16 next_to_use; 385 struct ice_tx_ring *tx_ring; 386 }; 387 388 static int ice_tx_hang_reporter_dump(struct devlink_health_reporter *reporter, 389 struct devlink_fmsg *fmsg, void *priv_ctx, 390 struct netlink_ext_ack *extack) 391 { 392 struct ice_tx_hang_event *event = priv_ctx; 393 struct sk_buff *skb; 394 395 if (!event) 396 return 0; 397 398 skb = event->tx_ring->tx_buf->skb; 399 devlink_fmsg_obj_nest_start(fmsg); 400 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, head); 401 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, intr); 402 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, vsi_num); 403 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, queue); 404 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_clean); 405 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_use); 406 devlink_fmsg_put(fmsg, "irq-mapping", event->tx_ring->q_vector->name); 407 ice_fmsg_put_ptr(fmsg, "desc-ptr", event->tx_ring->desc); 408 ice_fmsg_put_ptr(fmsg, "dma-ptr", (void *)(long)event->tx_ring->dma); 409 ice_fmsg_put_ptr(fmsg, "skb-ptr", skb); 410 devlink_fmsg_binary_pair_put(fmsg, "desc", event->tx_ring->desc, 411 event->tx_ring->count * sizeof(struct ice_tx_desc)); 412 devlink_fmsg_dump_skb(fmsg, skb); 413 devlink_fmsg_obj_nest_end(fmsg); 414 415 return 0; 416 } 417 418 void ice_prep_tx_hang_report(struct ice_pf *pf, struct ice_tx_ring *tx_ring, 419 u16 vsi_num, u32 head, u32 intr) 420 { 421 struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf; 422 423 buf->tx_ring = tx_ring; 424 buf->vsi_num = vsi_num; 425 buf->head = head; 426 buf->intr = intr; 427 } 428 429 void ice_report_tx_hang(struct ice_pf *pf) 430 { 431 struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf; 432 struct ice_tx_ring *tx_ring = buf->tx_ring; 433 434 struct ice_tx_hang_event ev = { 435 .head = buf->head, 436 .intr = buf->intr, 437 .vsi_num = buf->vsi_num, 438 .queue = tx_ring->q_index, 439 .next_to_clean = tx_ring->next_to_clean, 440 .next_to_use = tx_ring->next_to_use, 441 .tx_ring = tx_ring, 442 }; 443 444 ice_devlink_health_report(pf->health_reporters.tx_hang, "Tx hang", &ev); 445 } 446 447 static struct devlink_health_reporter * 448 ice_init_devlink_rep(struct ice_pf *pf, 449 const struct devlink_health_reporter_ops *ops) 450 { 451 struct devlink *devlink = priv_to_devlink(pf); 452 struct devlink_health_reporter *rep; 453 const u64 graceful_period = 0; 454 455 rep = devl_health_reporter_create(devlink, ops, graceful_period, pf); 456 if (IS_ERR(rep)) { 457 struct device *dev = ice_pf_to_dev(pf); 458 459 dev_err(dev, "failed to create devlink %s health report er", 460 ops->name); 461 return NULL; 462 } 463 return rep; 464 } 465 466 #define ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field) \ 467 ._field = ice_##_name##_reporter_##_field, 468 469 #define ICE_DEFINE_HEALTH_REPORTER_OPS_1(_name, _field1) \ 470 static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \ 471 .name = #_name, \ 472 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \ 473 } 474 475 #define ICE_DEFINE_HEALTH_REPORTER_OPS_2(_name, _field1, _field2) \ 476 static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \ 477 .name = #_name, \ 478 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \ 479 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field2) \ 480 } 481 482 ICE_DEFINE_HEALTH_REPORTER_OPS_1(mdd, dump); 483 ICE_DEFINE_HEALTH_REPORTER_OPS_1(tx_hang, dump); 484 ICE_DEFINE_HEALTH_REPORTER_OPS_2(fw, dump, diagnose); 485 ICE_DEFINE_HEALTH_REPORTER_OPS_2(port, dump, diagnose); 486 487 /** 488 * ice_health_init - allocate and init all ice devlink health reporters and 489 * accompanied data 490 * 491 * @pf: PF struct 492 */ 493 void ice_health_init(struct ice_pf *pf) 494 { 495 struct ice_health *reps = &pf->health_reporters; 496 497 reps->mdd = ice_init_devlink_rep(pf, &ice_mdd_reporter_ops); 498 reps->tx_hang = ice_init_devlink_rep(pf, &ice_tx_hang_reporter_ops); 499 500 if (ice_is_fw_health_report_supported(&pf->hw)) { 501 reps->fw = ice_init_devlink_rep(pf, &ice_fw_reporter_ops); 502 reps->port = ice_init_devlink_rep(pf, &ice_port_reporter_ops); 503 ice_config_health_events(pf, true); 504 } 505 } 506 507 /** 508 * ice_deinit_devl_reporter - destroy given devlink health reporter 509 * @reporter: reporter to destroy 510 */ 511 static void ice_deinit_devl_reporter(struct devlink_health_reporter *reporter) 512 { 513 if (reporter) 514 devl_health_reporter_destroy(reporter); 515 } 516 517 /** 518 * ice_health_deinit - deallocate all ice devlink health reporters and 519 * accompanied data 520 * 521 * @pf: PF struct 522 */ 523 void ice_health_deinit(struct ice_pf *pf) 524 { 525 ice_deinit_devl_reporter(pf->health_reporters.mdd); 526 ice_deinit_devl_reporter(pf->health_reporters.tx_hang); 527 if (ice_is_fw_health_report_supported(&pf->hw)) { 528 ice_deinit_devl_reporter(pf->health_reporters.fw); 529 ice_deinit_devl_reporter(pf->health_reporters.port); 530 ice_config_health_events(pf, false); 531 } 532 } 533 534 static 535 void ice_health_assign_healthy_state(struct devlink_health_reporter *reporter) 536 { 537 if (reporter) 538 devlink_health_reporter_state_update(reporter, 539 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); 540 } 541 542 /** 543 * ice_health_clear - clear devlink health issues after a reset 544 * @pf: the PF device structure 545 * 546 * Mark the PF in healthy state again after a reset has completed. 547 */ 548 void ice_health_clear(struct ice_pf *pf) 549 { 550 ice_health_assign_healthy_state(pf->health_reporters.mdd); 551 ice_health_assign_healthy_state(pf->health_reporters.tx_hang); 552 } 553