Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/intel/ice/devlink/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 18 kB image not shown  

Quelle  health.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024, Intel Corporation. */

#include "ice.h"
#include "ice_adminq_cmd.h" /* for enum ice_aqc_health_status_elem */
#include "health.h"

#define ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, obj, name) \
 devlink_fmsg_put(fmsg, #name, (obj)->name)

#define ICE_HEALTH_STATUS_DATA_SIZE 2

struct ice_health_status {
 enum ice_aqc_health_status code;
 const char *description;
 const char *solution;
 const char *data_label[ICE_HEALTH_STATUS_DATA_SIZE];
};

/*
 * In addition to the health status codes provided below, the firmware might
 * generate Health Status Codes that are not pertinent to the end-user.
 * For instance, Health Code 0x1002 is triggered when the command fails.
 * Such codes should be disregarded by the end-user.
 * The below lookup requires to be sorted by code.
 */


static const char ice_common_port_solutions[] =
 "Check your cable connection. Change or replace the module or cable. Manually set speed and duplex.";
static const char ice_port_number_label[] = "Port Number";
static const char ice_update_nvm_solution[] = "Update to the latest NVM image.";

static const struct ice_health_status ice_health_status_lookup[] = {
 {ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_STRICT, "An unsupported module was detected.",
  ice_common_port_solutions, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_MOD_TYPE, "Module type is not supported.",
  "Change or replace the module or cable.", {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_MOD_QUAL, "Module is not qualified.",
  ice_common_port_solutions, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_MOD_COMM,
  "Device cannot communicate with the module.",
  "Check your cable connection. Change or replace the module or cable. Manually set speed and duplex.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_MOD_CONFLICT, "Unresolved module conflict.",
  "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.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_MOD_NOT_PRESENT, "Module is not present.",
  "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.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_INFO_MOD_UNDERUTILIZED, "Underutilized module.",
  "Change or replace the module or cable. Change the port option.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_LENIENT, "An unsupported module was detected.",
  ice_common_port_solutions, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_INVALID_LINK_CFG, "Invalid link configuration.",
  NULL, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_PORT_ACCESS, "Port hardware access error.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_PORT_UNREACHABLE, "A port is unreachable.",
  "Change the port option. Update to the latest NVM image."},
 {ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_MOD_LIMITED, "Port speed is limited due to module.",
  "Change the module or configure the port option to match the current module speed. Change the port option.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_PARALLEL_FAULT,
  "All configured link modes were attempted but failed to establish link. The device will restart the process to establish link.",
  "Check link partner connection and configuration.",
  {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_PHY_LIMITED,
  "Port speed is limited by PHY capabilities.",
  "Change the module to align to port option.", {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_NETLIST_TOPO, "LOM topology netlist is corrupted.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_NETLIST, "Unrecoverable netlist error.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_TOPO_CONFLICT, "Port topology conflict.",
  "Change the port option. Update to the latest NVM image."},
 {ICE_AQC_HEALTH_STATUS_ERR_LINK_HW_ACCESS, "Unrecoverable hardware access error.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_LINK_RUNTIME, "Unrecoverable runtime error.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_DNL_INIT, "Link management engine failed to initialize.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_ERR_PHY_FW_LOAD,
  "Failed to load the firmware image in the external PHY.",
  ice_update_nvm_solution, {ice_port_number_label}},
 {ICE_AQC_HEALTH_STATUS_INFO_RECOVERY, "The device is in firmware recovery mode.",
  ice_update_nvm_solution, {"Extended Error"}},
 {ICE_AQC_HEALTH_STATUS_ERR_FLASH_ACCESS, "The flash chip cannot be accessed.",
  "If issue persists, call customer support.", {"Access Type"}},
 {ICE_AQC_HEALTH_STATUS_ERR_NVM_AUTH, "NVM authentication failed.",
  ice_update_nvm_solution},
 {ICE_AQC_HEALTH_STATUS_ERR_OROM_AUTH, "Option ROM authentication failed.",
  ice_update_nvm_solution},
 {ICE_AQC_HEALTH_STATUS_ERR_DDP_AUTH, "DDP package authentication failed.",
  "Update to latest base driver and DDP package."},
 {ICE_AQC_HEALTH_STATUS_ERR_NVM_COMPAT, "NVM image is incompatible.",
  ice_update_nvm_solution},
 {ICE_AQC_HEALTH_STATUS_ERR_OROM_COMPAT, "Option ROM is incompatible.",
  ice_update_nvm_solution, {"Expected PCI Device ID""Expected Module ID"}},
 {ICE_AQC_HEALTH_STATUS_ERR_DCB_MIB,
  "Supplied MIB file is invalid. DCB reverted to default configuration.",
  "Disable FW-LLDP and check DCBx system configuration.",
  {ice_port_number_label, "MIB ID"}},
};

static int ice_health_status_lookup_compare(const void *a, const void *b)
{
 return ((struct ice_health_status *)a)->code - ((struct ice_health_status *)b)->code;
}

static const struct ice_health_status *ice_get_health_status(u16 code)
{
 struct ice_health_status key = { .code = code };

 return bsearch(&key, ice_health_status_lookup, ARRAY_SIZE(ice_health_status_lookup),
         sizeof(struct ice_health_status), ice_health_status_lookup_compare);
}

static void ice_describe_status_code(struct devlink_fmsg *fmsg,
         struct ice_aqc_health_status_elem *hse)
{
 static const char *const aux_label[] = { "Aux Data 1""Aux Data 2" };
 const struct ice_health_status *health_code;
 u32 internal_data[2];
 u16 status_code;

 status_code = le16_to_cpu(hse->health_status_code);

 devlink_fmsg_put(fmsg, "Syndrome", status_code);
 if (status_code) {
  internal_data[0] = le32_to_cpu(hse->internal_data1);
  internal_data[1] = le32_to_cpu(hse->internal_data2);

  health_code = ice_get_health_status(status_code);
  if (!health_code)
   return;

  devlink_fmsg_string_pair_put(fmsg, "Description", health_code->description);
  if (health_code->solution)
   devlink_fmsg_string_pair_put(fmsg, "Possible Solution",
           health_code->solution);

  for (size_t i = 0; i < ICE_HEALTH_STATUS_DATA_SIZE; i++) {
   if (internal_data[i] != ICE_AQC_HEALTH_STATUS_UNDEFINED_DATA)
    devlink_fmsg_u32_pair_put(fmsg,
         health_code->data_label[i] ?
         health_code->data_label[i] :
         aux_label[i],
         internal_data[i]);
  }
 }
}

static int
ice_port_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
      struct netlink_ext_ack *extack)
{
 struct ice_pf *pf = devlink_health_reporter_priv(reporter);

 ice_describe_status_code(fmsg, &pf->health_reporters.port_status);
 return 0;
}

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)
{
 struct ice_pf *pf = devlink_health_reporter_priv(reporter);

 ice_describe_status_code(fmsg, &pf->health_reporters.port_status);
 return 0;
}

static int
ice_fw_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
    struct netlink_ext_ack *extack)
{
 struct ice_pf *pf = devlink_health_reporter_priv(reporter);

 ice_describe_status_code(fmsg, &pf->health_reporters.fw_status);
 return 0;
}

static int
ice_fw_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg,
       void *priv_ctx, struct netlink_ext_ack *extack)
{
 struct ice_pf *pf = devlink_health_reporter_priv(reporter);

 ice_describe_status_code(fmsg, &pf->health_reporters.fw_status);
 return 0;
}

static void ice_config_health_events(struct ice_pf *pf, bool enable)
{
 u8 enable_bits = 0;
 int ret;

 if (enable)
  enable_bits = ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK |
         ICE_AQC_HEALTH_STATUS_SET_GLOBAL_MASK;

 ret = ice_aq_set_health_status_cfg(&pf->hw, enable_bits);
 if (ret)
  dev_err(ice_pf_to_dev(pf), "Failed to %s firmware health events, err %d aq_err %s\n",
   str_enable_disable(enable), ret,
   libie_aq_str(pf->hw.adminq.sq_last_status));
}

/**
 * ice_process_health_status_event - Process the health status event from FW
 * @pf: pointer to the PF structure
 * @event: event structure containing the Health Status Event opcode
 *
 * Decode the Health Status Events and print the associated messages
 */

void ice_process_health_status_event(struct ice_pf *pf, struct ice_rq_event_info *event)
{
 const struct ice_aqc_health_status_elem *health_info;
 const struct ice_aqc_get_health_status *cmd;
 u16 count;

 health_info = (struct ice_aqc_health_status_elem *)event->msg_buf;
 cmd = libie_aq_raw(&event->desc);
 count = le16_to_cpu(cmd->health_status_count);

 if (count > (event->buf_len / sizeof(*health_info))) {
  dev_err(ice_pf_to_dev(pf), "Received a health status event with invalid element count\n");
  return;
 }

 for (size_t i = 0; i < count; i++) {
  const struct ice_health_status *health_code;
  u16 status_code;

  status_code = le16_to_cpu(health_info->health_status_code);
  health_code = ice_get_health_status(status_code);

  if (health_code) {
   switch (le16_to_cpu(health_info->event_source)) {
   case ICE_AQC_HEALTH_STATUS_GLOBAL:
    pf->health_reporters.fw_status = *health_info;
    devlink_health_report(pf->health_reporters.fw,
            "FW syndrome reported", NULL);
    break;
   case ICE_AQC_HEALTH_STATUS_PF:
   case ICE_AQC_HEALTH_STATUS_PORT:
    pf->health_reporters.port_status = *health_info;
    devlink_health_report(pf->health_reporters.port,
            "Port syndrome reported", NULL);
    break;
   default:
    dev_err(ice_pf_to_dev(pf), "Health code with unknown source\n");
   }
  } else {
   u32 data1, data2;
   u16 source;

   source = le16_to_cpu(health_info->event_source);
   data1 = le32_to_cpu(health_info->internal_data1);
   data2 = le32_to_cpu(health_info->internal_data2);
   dev_dbg(ice_pf_to_dev(pf),
    "Received internal health status code 0x%08x, source: 0x%08x, data1: 0x%08x, data2: 0x%08x",
    status_code, source, data1, data2);
  }
  health_info++;
 }
}

/**
 * ice_devlink_health_report - boilerplate to call given @reporter
 *
 * @reporter: devlink health reporter to call, do nothing on NULL
 * @msg: message to pass up, "event name" is fine
 * @priv_ctx: typically some event struct
 */

static void ice_devlink_health_report(struct devlink_health_reporter *reporter,
          const char *msg, void *priv_ctx)
{
 if (!reporter)
  return;

 /* We do not do auto recovering, so return value of the below function
 * will always be 0, thus we do ignore it.
 */

 devlink_health_report(reporter, msg, priv_ctx);
}

struct ice_mdd_event {
 enum ice_mdd_src src;
 u16 vf_num;
 u16 queue;
 u8 pf_num;
 u8 event;
};

static const char *ice_mdd_src_to_str(enum ice_mdd_src src)
{
 switch (src) {
 case ICE_MDD_SRC_TX_PQM:
  return "tx_pqm";
 case ICE_MDD_SRC_TX_TCLAN:
  return "tx_tclan";
 case ICE_MDD_SRC_TX_TDPU:
  return "tx_tdpu";
 case ICE_MDD_SRC_RX:
  return "rx";
 default:
  return "invalid";
 }
}

static int
ice_mdd_reporter_dump(struct devlink_health_reporter *reporter,
        struct devlink_fmsg *fmsg, void *priv_ctx,
        struct netlink_ext_ack *extack)
{
 struct ice_mdd_event *mdd_event = priv_ctx;
 const char *src;

 if (!mdd_event)
  return 0;

 src = ice_mdd_src_to_str(mdd_event->src);

 devlink_fmsg_obj_nest_start(fmsg);
 devlink_fmsg_put(fmsg, "src", src);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, pf_num);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, vf_num);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, event);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, mdd_event, queue);
 devlink_fmsg_obj_nest_end(fmsg);

 return 0;
}

/**
 * ice_report_mdd_event - Report an MDD event through devlink health
 * @pf: the PF device structure
 * @src: the HW block that was the source of this MDD event
 * @pf_num: the pf_num on which the MDD event occurred
 * @vf_num: the vf_num on which the MDD event occurred
 * @event: the event type of the MDD event
 * @queue: the queue on which the MDD event occurred
 *
 * Report an MDD event that has occurred on this PF.
 */

void ice_report_mdd_event(struct ice_pf *pf, enum ice_mdd_src src, u8 pf_num,
     u16 vf_num, u8 event, u16 queue)
{
 struct ice_mdd_event ev = {
  .src = src,
  .pf_num = pf_num,
  .vf_num = vf_num,
  .event = event,
  .queue = queue,
 };

 ice_devlink_health_report(pf->health_reporters.mdd, "MDD event", &ev);
}

/**
 * ice_fmsg_put_ptr - put hex value of pointer into fmsg
 *
 * @fmsg: devlink fmsg under construction
 * @name: name to pass
 * @ptr: 64 bit value to print as hex and put into fmsg
 */

static void ice_fmsg_put_ptr(struct devlink_fmsg *fmsg, const char *name,
        void *ptr)
{
 char buf[sizeof(ptr) * 3];

 sprintf(buf, "%p", ptr);
 devlink_fmsg_put(fmsg, name, buf);
}

struct ice_tx_hang_event {
 u32 head;
 u32 intr;
 u16 vsi_num;
 u16 queue;
 u16 next_to_clean;
 u16 next_to_use;
 struct ice_tx_ring *tx_ring;
};

static int ice_tx_hang_reporter_dump(struct devlink_health_reporter *reporter,
         struct devlink_fmsg *fmsg, void *priv_ctx,
         struct netlink_ext_ack *extack)
{
 struct ice_tx_hang_event *event = priv_ctx;
 struct sk_buff *skb;

 if (!event)
  return 0;

 skb = event->tx_ring->tx_buf->skb;
 devlink_fmsg_obj_nest_start(fmsg);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, head);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, intr);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, vsi_num);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, queue);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_clean);
 ICE_DEVLINK_FMSG_PUT_FIELD(fmsg, event, next_to_use);
 devlink_fmsg_put(fmsg, "irq-mapping", event->tx_ring->q_vector->name);
 ice_fmsg_put_ptr(fmsg, "desc-ptr", event->tx_ring->desc);
 ice_fmsg_put_ptr(fmsg, "dma-ptr", (void *)(long)event->tx_ring->dma);
 ice_fmsg_put_ptr(fmsg, "skb-ptr", skb);
 devlink_fmsg_binary_pair_put(fmsg, "desc", event->tx_ring->desc,
         event->tx_ring->count * sizeof(struct ice_tx_desc));
 devlink_fmsg_dump_skb(fmsg, skb);
 devlink_fmsg_obj_nest_end(fmsg);

 return 0;
}

void ice_prep_tx_hang_report(struct ice_pf *pf, struct ice_tx_ring *tx_ring,
        u16 vsi_num, u32 head, u32 intr)
{
 struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf;

 buf->tx_ring = tx_ring;
 buf->vsi_num = vsi_num;
 buf->head = head;
 buf->intr = intr;
}

void ice_report_tx_hang(struct ice_pf *pf)
{
 struct ice_health_tx_hang_buf *buf = &pf->health_reporters.tx_hang_buf;
 struct ice_tx_ring *tx_ring = buf->tx_ring;

 struct ice_tx_hang_event ev = {
  .head = buf->head,
  .intr = buf->intr,
  .vsi_num = buf->vsi_num,
  .queue = tx_ring->q_index,
  .next_to_clean = tx_ring->next_to_clean,
  .next_to_use = tx_ring->next_to_use,
  .tx_ring = tx_ring,
 };

 ice_devlink_health_report(pf->health_reporters.tx_hang, "Tx hang", &ev);
}

static struct devlink_health_reporter *
ice_init_devlink_rep(struct ice_pf *pf,
       const struct devlink_health_reporter_ops *ops)
{
 struct devlink *devlink = priv_to_devlink(pf);
 struct devlink_health_reporter *rep;
 const u64 graceful_period = 0;

 rep = devl_health_reporter_create(devlink, ops, graceful_period, pf);
 if (IS_ERR(rep)) {
  struct device *dev = ice_pf_to_dev(pf);

  dev_err(dev, "failed to create devlink %s health report er",
   ops->name);
  return NULL;
 }
 return rep;
}

#define ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field) \
 ._field = ice_##_name##_reporter_##_field,

#define ICE_DEFINE_HEALTH_REPORTER_OPS_1(_name, _field1) \
 static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
 .name = #_name, \
 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
 }

#define ICE_DEFINE_HEALTH_REPORTER_OPS_2(_name, _field1, _field2) \
 static const struct devlink_health_reporter_ops ice_##_name##_reporter_ops = { \
 .name = #_name, \
 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field1) \
 ICE_HEALTH_REPORTER_OPS_FIELD(_name, _field2) \
 }

ICE_DEFINE_HEALTH_REPORTER_OPS_1(mdd, dump);
ICE_DEFINE_HEALTH_REPORTER_OPS_1(tx_hang, dump);
ICE_DEFINE_HEALTH_REPORTER_OPS_2(fw, dump, diagnose);
ICE_DEFINE_HEALTH_REPORTER_OPS_2(port, dump, diagnose);

/**
 * ice_health_init - allocate and init all ice devlink health reporters and
 * accompanied data
 *
 * @pf: PF struct
 */

void ice_health_init(struct ice_pf *pf)
{
 struct ice_health *reps = &pf->health_reporters;

 reps->mdd = ice_init_devlink_rep(pf, &ice_mdd_reporter_ops);
 reps->tx_hang = ice_init_devlink_rep(pf, &ice_tx_hang_reporter_ops);

 if (ice_is_fw_health_report_supported(&pf->hw)) {
  reps->fw = ice_init_devlink_rep(pf, &ice_fw_reporter_ops);
  reps->port = ice_init_devlink_rep(pf, &ice_port_reporter_ops);
  ice_config_health_events(pf, true);
 }
}

/**
 * ice_deinit_devl_reporter - destroy given devlink health reporter
 * @reporter: reporter to destroy
 */

static void ice_deinit_devl_reporter(struct devlink_health_reporter *reporter)
{
 if (reporter)
  devl_health_reporter_destroy(reporter);
}

/**
 * ice_health_deinit - deallocate all ice devlink health reporters and
 * accompanied data
 *
 * @pf: PF struct
 */

void ice_health_deinit(struct ice_pf *pf)
{
 ice_deinit_devl_reporter(pf->health_reporters.mdd);
 ice_deinit_devl_reporter(pf->health_reporters.tx_hang);
 if (ice_is_fw_health_report_supported(&pf->hw)) {
  ice_deinit_devl_reporter(pf->health_reporters.fw);
  ice_deinit_devl_reporter(pf->health_reporters.port);
  ice_config_health_events(pf, false);
 }
}

static
void ice_health_assign_healthy_state(struct devlink_health_reporter *reporter)
{
 if (reporter)
  devlink_health_reporter_state_update(reporter,
           DEVLINK_HEALTH_REPORTER_STATE_HEALTHY);
}

/**
 * ice_health_clear - clear devlink health issues after a reset
 * @pf: the PF device structure
 *
 * Mark the PF in healthy state again after a reset has completed.
 */

void ice_health_clear(struct ice_pf *pf)
{
 ice_health_assign_healthy_state(pf->health_reporters.mdd);
 ice_health_assign_healthy_state(pf->health_reporters.tx_hang);
}

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.