xref: /linux/drivers/net/ethernet/intel/ice/devlink/health.c (revision 0ad9617c78acbc71373fb341a6f75d4012b01d69)
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 *const 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 *const ice_port_number_label = "Port Number";
31 static const char *const 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 			ice_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 	u16 count;
221 
222 	health_info = (struct ice_aqc_health_status_elem *)event->msg_buf;
223 	count = le16_to_cpu(event->desc.params.get_health_status.health_status_count);
224 
225 	if (count > (event->buf_len / sizeof(*health_info))) {
226 		dev_err(ice_pf_to_dev(pf), "Received a health status event with invalid element count\n");
227 		return;
228 	}
229 
230 	for (size_t i = 0; i < count; i++) {
231 		const struct ice_health_status *health_code;
232 		u16 status_code;
233 
234 		status_code = le16_to_cpu(health_info->health_status_code);
235 		health_code = ice_get_health_status(status_code);
236 
237 		if (health_code) {
238 			switch (le16_to_cpu(health_info->event_source)) {
239 			case ICE_AQC_HEALTH_STATUS_GLOBAL:
240 				pf->health_reporters.fw_status = *health_info;
241 				devlink_health_report(pf->health_reporters.fw,
242 						      "FW syndrome reported", NULL);
243 				break;
244 			case ICE_AQC_HEALTH_STATUS_PF:
245 			case ICE_AQC_HEALTH_STATUS_PORT:
246 				pf->health_reporters.port_status = *health_info;
247 				devlink_health_report(pf->health_reporters.port,
248 						      "Port syndrome reported", NULL);
249 				break;
250 			default:
251 				dev_err(ice_pf_to_dev(pf), "Health code with unknown source\n");
252 			}
253 		} else {
254 			u32 data1, data2;
255 			u16 source;
256 
257 			source = le16_to_cpu(health_info->event_source);
258 			data1 = le32_to_cpu(health_info->internal_data1);
259 			data2 = le32_to_cpu(health_info->internal_data2);
260 			dev_dbg(ice_pf_to_dev(pf),
261 				"Received internal health status code 0x%08x, source: 0x%08x, data1: 0x%08x, data2: 0x%08x",
262 				status_code, source, data1, data2);
263 		}
264 		health_info++;
265 	}
266 }
267 
268 /**
269  * ice_devlink_health_report - boilerplate to call given @reporter
270  *
271  * @reporter: devlink health reporter to call, do nothing on NULL
272  * @msg: message to pass up, "event name" is fine
273  * @priv_ctx: typically some event struct
274  */
275 static void ice_devlink_health_report(struct devlink_health_reporter *reporter,
276 				      const char *msg, void *priv_ctx)
277 {
278 	if (!reporter)
279 		return;
280 
281 	/* We do not do auto recovering, so return value of the below function
282 	 * will always be 0, thus we do ignore it.
283 	 */
284 	devlink_health_report(reporter, msg, priv_ctx);
285 }
286 
287 struct ice_mdd_event {
288 	enum ice_mdd_src src;
289 	u16 vf_num;
290 	u16 queue;
291 	u8 pf_num;
292 	u8 event;
293 };
294 
295 static const char *ice_mdd_src_to_str(enum ice_mdd_src src)
296 {
297 	switch (src) {
298 	case ICE_MDD_SRC_TX_PQM:
299 		return "tx_pqm";
300 	case ICE_MDD_SRC_TX_TCLAN:
301 		return "tx_tclan";
302 	case ICE_MDD_SRC_TX_TDPU:
303 		return "tx_tdpu";
304 	case ICE_MDD_SRC_RX:
305 		return "rx";
306 	default:
307 		return "invalid";
308 	}
309 }
310 
311 static int
312 ice_mdd_reporter_dump(struct devlink_health_reporter *reporter,
313 		      struct devlink_fmsg *fmsg, void *priv_ctx,
314 		      struct netlink_ext_ack *extack)
315 {
316 	struct ice_mdd_event *mdd_event = priv_ctx;
317 	const char *src;
318 
319 	if (!mdd_event)
320 		return 0;
321 
322 	src = ice_mdd_src_to_str(mdd_event->src);
323 
324 	devlink_fmsg_obj_nest_start(fmsg);
325 	devlink_fmsg_put(fmsg, "src", src);
326 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, pf_num);
327 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, vf_num);
328 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, event);
329 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, queue);
330 	devlink_fmsg_obj_nest_end(fmsg);
331 
332 	return 0;
333 }
334 
335 /**
336  * ice_report_mdd_event - Report an MDD event through devlink health
337  * @pf: the PF device structure
338  * @src: the HW block that was the source of this MDD event
339  * @pf_num: the pf_num on which the MDD event occurred
340  * @vf_num: the vf_num on which the MDD event occurred
341  * @event: the event type of the MDD event
342  * @queue: the queue on which the MDD event occurred
343  *
344  * Report an MDD event that has occurred on this PF.
345  */
346 void ice_report_mdd_event(struct ice_pf *pf, enum ice_mdd_src src, u8 pf_num,
347 			  u16 vf_num, u8 event, u16 queue)
348 {
349 	struct ice_mdd_event ev = {
350 		.src = src,
351 		.pf_num = pf_num,
352 		.vf_num = vf_num,
353 		.event = event,
354 		.queue = queue,
355 	};
356 
357 	ice_devlink_health_report(pf->health_reporters.mdd, "MDD event", &ev);
358 }
359 
360 /**
361  * ice_fmsg_put_ptr - put hex value of pointer into fmsg
362  *
363  * @fmsg: devlink fmsg under construction
364  * @name: name to pass
365  * @ptr: 64 bit value to print as hex and put into fmsg
366  */
367 static void ice_fmsg_put_ptr(struct devlink_fmsg *fmsg, const char *name,
368 			     void *ptr)
369 {
370 	char buf[sizeof(ptr) * 3];
371 
372 	sprintf(buf, "%p", ptr);
373 	devlink_fmsg_put(fmsg, name, buf);
374 }
375 
376 struct ice_tx_hang_event {
377 	u32 head;
378 	u32 intr;
379 	u16 vsi_num;
380 	u16 queue;
381 	u16 next_to_clean;
382 	u16 next_to_use;
383 	struct ice_tx_ring *tx_ring;
384 };
385 
386 static int ice_tx_hang_reporter_dump(struct devlink_health_reporter *reporter,
387 				     struct devlink_fmsg *fmsg, void *priv_ctx,
388 				     struct netlink_ext_ack *extack)
389 {
390 	struct ice_tx_hang_event *event = priv_ctx;
391 	struct sk_buff *skb;
392 
393 	if (!event)
394 		return 0;
395 
396 	skb = event->tx_ring->tx_buf->skb;
397 	devlink_fmsg_obj_nest_start(fmsg);
398 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, head);
399 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, intr);
400 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, vsi_num);
401 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, queue);
402 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_clean);
403 	ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_use);
404 	devlink_fmsg_put(fmsg, "irq-mapping", event->tx_ring->q_vector->name);
405 	ice_fmsg_put_ptr(fmsg, "desc-ptr", event->tx_ring->desc);
406 	ice_fmsg_put_ptr(fmsg, "dma-ptr", (void *)(long)event->tx_ring->dma);
407 	ice_fmsg_put_ptr(fmsg, "skb-ptr", skb);
408 	devlink_fmsg_binary_pair_put(fmsg, "desc", event->tx_ring->desc,
409 				     event->tx_ring->count * sizeof(struct ice_tx_desc));
410 	devlink_fmsg_dump_skb(fmsg, skb);
411 	devlink_fmsg_obj_nest_end(fmsg);
412 
413 	return 0;
414 }
415 
416 void ice_prep_tx_hang_report(struct ice_pf *pf, struct ice_tx_ring *tx_ring,
417 			     u16 vsi_num, u32 head, u32 intr)
418 {
419 	struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf;
420 
421 	buf->tx_ring = tx_ring;
422 	buf->vsi_num = vsi_num;
423 	buf->head = head;
424 	buf->intr = intr;
425 }
426 
427 void ice_report_tx_hang(struct ice_pf *pf)
428 {
429 	struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf;
430 	struct ice_tx_ring *tx_ring = buf->tx_ring;
431 
432 	struct ice_tx_hang_event ev = {
433 		.head = buf->head,
434 		.intr = buf->intr,
435 		.vsi_num = buf->vsi_num,
436 		.queue = tx_ring->q_index,
437 		.next_to_clean = tx_ring->next_to_clean,
438 		.next_to_use = tx_ring->next_to_use,
439 		.tx_ring = tx_ring,
440 	};
441 
442 	ice_devlink_health_report(pf->health_reporters.tx_hang, "Tx hang", &ev);
443 }
444 
445 static struct devlink_health_reporter *
446 ice_init_devlink_rep(struct ice_pf *pf,
447 		     const struct devlink_health_reporter_ops *ops)
448 {
449 	struct devlink *devlink = priv_to_devlink(pf);
450 	struct devlink_health_reporter *rep;
451 	const u64 graceful_period = 0;
452 
453 	rep = devl_health_reporter_create(devlink, ops, graceful_period, pf);
454 	if (IS_ERR(rep)) {
455 		struct device *dev = ice_pf_to_dev(pf);
456 
457 		dev_err(dev, "failed to create devlink %s health report er",
458 			ops->name);
459 		return NULL;
460 	}
461 	return rep;
462 }
463 
464 #define ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field) \
465 	._field = ice_##_name##_reporter_##_field,
466 
467 #define ICE_DEFINE_HEALTH_REPORTER_OPS_1(_name, _field1) \
468 	static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
469 	.name = #_name, \
470 	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
471 	}
472 
473 #define ICE_DEFINE_HEALTH_REPORTER_OPS_2(_name, _field1, _field2) \
474 	static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
475 	.name = #_name, \
476 	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
477 	ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field2) \
478 	}
479 
480 ICE_DEFINE_HEALTH_REPORTER_OPS_1(mdd, dump);
481 ICE_DEFINE_HEALTH_REPORTER_OPS_1(tx_hang, dump);
482 ICE_DEFINE_HEALTH_REPORTER_OPS_2(fw, dump, diagnose);
483 ICE_DEFINE_HEALTH_REPORTER_OPS_2(port, dump, diagnose);
484 
485 /**
486  * ice_health_init - allocate and init all ice devlink health reporters and
487  * accompanied data
488  *
489  * @pf: PF struct
490  */
491 void ice_health_init(struct ice_pf *pf)
492 {
493 	struct ice_health *reps = &pf->health_reporters;
494 
495 	reps->mdd = ice_init_devlink_rep(pf, &ice_mdd_reporter_ops);
496 	reps->tx_hang = ice_init_devlink_rep(pf, &ice_tx_hang_reporter_ops);
497 
498 	if (ice_is_fw_health_report_supported(&pf->hw)) {
499 		reps->fw = ice_init_devlink_rep(pf, &ice_fw_reporter_ops);
500 		reps->port = ice_init_devlink_rep(pf, &ice_port_reporter_ops);
501 		ice_config_health_events(pf, true);
502 	}
503 }
504 
505 /**
506  * ice_deinit_devl_reporter - destroy given devlink health reporter
507  * @reporter: reporter to destroy
508  */
509 static void ice_deinit_devl_reporter(struct devlink_health_reporter *reporter)
510 {
511 	if (reporter)
512 		devl_health_reporter_destroy(reporter);
513 }
514 
515 /**
516  * ice_health_deinit - deallocate all ice devlink health reporters and
517  * accompanied data
518  *
519  * @pf: PF struct
520  */
521 void ice_health_deinit(struct ice_pf *pf)
522 {
523 	ice_deinit_devl_reporter(pf->health_reporters.mdd);
524 	ice_deinit_devl_reporter(pf->health_reporters.tx_hang);
525 	if (ice_is_fw_health_report_supported(&pf->hw)) {
526 		ice_deinit_devl_reporter(pf->health_reporters.fw);
527 		ice_deinit_devl_reporter(pf->health_reporters.port);
528 		ice_config_health_events(pf, false);
529 	}
530 }
531 
532 static
533 void ice_health_assign_healthy_state(struct devlink_health_reporter *reporter)
534 {
535 	if (reporter)
536 		devlink_health_reporter_state_update(reporter,
537 						     DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
538 }
539 
540 /**
541  * ice_health_clear - clear devlink health issues after a reset
542  * @pf: the PF device structure
543  *
544  * Mark the PF in healthy state again after a reset has completed.
545  */
546 void ice_health_clear(struct ice_pf *pf)
547 {
548 	ice_health_assign_healthy_state(pf->health_reporters.mdd);
549 	ice_health_assign_healthy_state(pf->health_reporters.tx_hang);
550 }
551