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
ice_health_status_lookup_compare(const void * a,const void * b)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
ice_get_health_status(u16 code)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
ice_describe_status_code(struct devlink_fmsg * fmsg,struct ice_aqc_health_status_elem * hse)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
ice_port_reporter_diagnose(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,struct netlink_ext_ack * extack)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
ice_port_reporter_dump(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,void * priv_ctx,struct netlink_ext_ack __always_unused * extack)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
ice_fw_reporter_diagnose(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,struct netlink_ext_ack * extack)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
ice_fw_reporter_dump(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,void * priv_ctx,struct netlink_ext_ack * extack)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
ice_config_health_events(struct ice_pf * pf,bool enable)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 */
ice_process_health_status_event(struct ice_pf * pf,struct ice_rq_event_info * event)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 */
ice_devlink_health_report(struct devlink_health_reporter * reporter,const char * msg,void * priv_ctx)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
ice_mdd_src_to_str(enum ice_mdd_src src)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
ice_mdd_reporter_dump(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,void * priv_ctx,struct netlink_ext_ack * extack)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 */
ice_report_mdd_event(struct ice_pf * pf,enum ice_mdd_src src,u8 pf_num,u16 vf_num,u8 event,u16 queue)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 */
ice_fmsg_put_ptr(struct devlink_fmsg * fmsg,const char * name,void * ptr)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
ice_tx_hang_reporter_dump(struct devlink_health_reporter * reporter,struct devlink_fmsg * fmsg,void * priv_ctx,struct netlink_ext_ack * extack)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
ice_prep_tx_hang_report(struct ice_pf * pf,struct ice_tx_ring * tx_ring,u16 vsi_num,u32 head,u32 intr)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
ice_report_tx_hang(struct ice_pf * pf)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 *
ice_init_devlink_rep(struct ice_pf * pf,const struct devlink_health_reporter_ops * ops)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 */
ice_health_init(struct ice_pf * pf)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 */
ice_deinit_devl_reporter(struct devlink_health_reporter * reporter)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 */
ice_health_deinit(struct ice_pf * pf)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
ice_health_assign_healthy_state(struct devlink_health_reporter * reporter)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 */
ice_health_clear(struct ice_pf * pf)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