Skip to content

Commit

Permalink
Merge branch 'hinic-add-some-error-messages-for-debug'
Browse files Browse the repository at this point in the history
Luo bin says:

====================
hinic: add some error messages for debug

patch #1: support to handle hw abnormal event
patch #2: improve the error messages when functions return failure and
	  dump relevant registers in some exception handling processes
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 29, 2020
2 parents aff7543 + 90f86b8 commit 1255457
Show file tree
Hide file tree
Showing 21 changed files with 855 additions and 81 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,14 @@ struct hinic_dev {
int lb_pkt_len;
u8 *lb_test_rx_buf;
struct devlink *devlink;
bool cable_unplugged;
bool module_unrecognized;
};

struct hinic_devlink_priv {
struct hinic_hwdev *hwdev;
struct devlink_health_reporter *hw_fault_reporter;
struct devlink_health_reporter *fw_fault_reporter;
};

#endif
286 changes: 283 additions & 3 deletions drivers/net/ethernet/huawei/hinic/hinic_devlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
#include <net/devlink.h>
#include <linux/firmware.h>

#include "hinic_dev.h"
#include "hinic_port.h"
#include "hinic_devlink.h"
#include "hinic_hw_dev.h"

static bool check_image_valid(struct hinic_devlink_priv *priv, const u8 *buf,
u32 image_size, struct host_image_st *host_image)
Expand Down Expand Up @@ -317,12 +317,292 @@ void hinic_devlink_free(struct devlink *devlink)
devlink_free(devlink);
}

int hinic_devlink_register(struct devlink *devlink, struct device *dev)
int hinic_devlink_register(struct hinic_devlink_priv *priv, struct device *dev)
{
struct devlink *devlink = priv_to_devlink(priv);

return devlink_register(devlink, dev);
}

void hinic_devlink_unregister(struct devlink *devlink)
void hinic_devlink_unregister(struct hinic_devlink_priv *priv)
{
struct devlink *devlink = priv_to_devlink(priv);

devlink_unregister(devlink);
}

static int chip_fault_show(struct devlink_fmsg *fmsg,
struct hinic_fault_event *event)
{
char fault_level[FAULT_TYPE_MAX][FAULT_SHOW_STR_LEN + 1] = {
"fatal", "reset", "flr", "general", "suggestion"};
char level_str[FAULT_SHOW_STR_LEN + 1] = {0};
u8 level;
int err;

level = event->event.chip.err_level;
if (level < FAULT_LEVEL_MAX)
strncpy(level_str, fault_level[level], strlen(fault_level[level]));
else
strncpy(level_str, "Unknown", strlen("Unknown"));

if (level == FAULT_LEVEL_SERIOUS_FLR) {
err = devlink_fmsg_u32_pair_put(fmsg, "Function level err func_id",
(u32)event->event.chip.func_id);
if (err)
return err;
}

err = devlink_fmsg_u8_pair_put(fmsg, "module_id", event->event.chip.node_id);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "err_type", (u32)event->event.chip.err_type);
if (err)
return err;

err = devlink_fmsg_string_pair_put(fmsg, "err_level", level_str);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "err_csr_addr",
event->event.chip.err_csr_addr);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "err_csr_value",
event->event.chip.err_csr_value);
if (err)
return err;

return 0;
}

static int fault_report_show(struct devlink_fmsg *fmsg,
struct hinic_fault_event *event)
{
char fault_type[FAULT_TYPE_MAX][FAULT_SHOW_STR_LEN + 1] = {
"chip", "ucode", "mem rd timeout", "mem wr timeout",
"reg rd timeout", "reg wr timeout", "phy fault"};
char type_str[FAULT_SHOW_STR_LEN + 1] = {0};
int err;

if (event->type < FAULT_TYPE_MAX)
strncpy(type_str, fault_type[event->type], strlen(fault_type[event->type]));
else
strncpy(type_str, "Unknown", strlen("Unknown"));

err = devlink_fmsg_string_pair_put(fmsg, "Fault type", type_str);
if (err)
return err;

err = devlink_fmsg_binary_pair_put(fmsg, "Fault raw data",
event->event.val, sizeof(event->event.val));
if (err)
return err;

switch (event->type) {
case FAULT_TYPE_CHIP:
err = chip_fault_show(fmsg, event);
if (err)
return err;
break;
case FAULT_TYPE_UCODE:
err = devlink_fmsg_u8_pair_put(fmsg, "Cause_id", event->event.ucode.cause_id);
if (err)
return err;
err = devlink_fmsg_u8_pair_put(fmsg, "core_id", event->event.ucode.core_id);
if (err)
return err;
err = devlink_fmsg_u8_pair_put(fmsg, "c_id", event->event.ucode.c_id);
if (err)
return err;
err = devlink_fmsg_u8_pair_put(fmsg, "epc", event->event.ucode.epc);
if (err)
return err;
break;
case FAULT_TYPE_MEM_RD_TIMEOUT:
case FAULT_TYPE_MEM_WR_TIMEOUT:
err = devlink_fmsg_u32_pair_put(fmsg, "Err_csr_ctrl",
event->event.mem_timeout.err_csr_ctrl);
if (err)
return err;
err = devlink_fmsg_u32_pair_put(fmsg, "err_csr_data",
event->event.mem_timeout.err_csr_data);
if (err)
return err;
err = devlink_fmsg_u32_pair_put(fmsg, "ctrl_tab",
event->event.mem_timeout.ctrl_tab);
if (err)
return err;
err = devlink_fmsg_u32_pair_put(fmsg, "mem_index",
event->event.mem_timeout.mem_index);
if (err)
return err;
break;
case FAULT_TYPE_REG_RD_TIMEOUT:
case FAULT_TYPE_REG_WR_TIMEOUT:
err = devlink_fmsg_u32_pair_put(fmsg, "Err_csr", event->event.reg_timeout.err_csr);
if (err)
return err;
break;
case FAULT_TYPE_PHY_FAULT:
err = devlink_fmsg_u8_pair_put(fmsg, "Op_type", event->event.phy_fault.op_type);
if (err)
return err;
err = devlink_fmsg_u8_pair_put(fmsg, "port_id", event->event.phy_fault.port_id);
if (err)
return err;
err = devlink_fmsg_u8_pair_put(fmsg, "dev_ad", event->event.phy_fault.dev_ad);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "csr_addr", event->event.phy_fault.csr_addr);
if (err)
return err;
err = devlink_fmsg_u32_pair_put(fmsg, "op_data", event->event.phy_fault.op_data);
if (err)
return err;
break;
default:
break;
}

return 0;
}

static int hinic_hw_reporter_dump(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg, void *priv_ctx,
struct netlink_ext_ack *extack)
{
if (priv_ctx)
return fault_report_show(fmsg, priv_ctx);

return 0;
}

static int mgmt_watchdog_report_show(struct devlink_fmsg *fmsg,
struct hinic_mgmt_watchdog_info *watchdog_info)
{
int err;

err = devlink_fmsg_u32_pair_put(fmsg, "Mgmt deadloop time_h", watchdog_info->curr_time_h);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "time_l", watchdog_info->curr_time_l);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "task_id", watchdog_info->task_id);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "sp", watchdog_info->sp);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "stack_current_used", watchdog_info->curr_used);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "peak_used", watchdog_info->peak_used);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "\n Overflow_flag", watchdog_info->is_overflow);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "stack_top", watchdog_info->stack_top);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "stack_bottom", watchdog_info->stack_bottom);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "mgmt_pc", watchdog_info->pc);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "lr", watchdog_info->lr);
if (err)
return err;

err = devlink_fmsg_u32_pair_put(fmsg, "cpsr", watchdog_info->cpsr);
if (err)
return err;

err = devlink_fmsg_binary_pair_put(fmsg, "Mgmt register info",
watchdog_info->reg, sizeof(watchdog_info->reg));
if (err)
return err;

err = devlink_fmsg_binary_pair_put(fmsg, "Mgmt dump stack(start from sp)",
watchdog_info->data, sizeof(watchdog_info->data));
if (err)
return err;

return 0;
}

static int hinic_fw_reporter_dump(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg, void *priv_ctx,
struct netlink_ext_ack *extack)
{
if (priv_ctx)
return mgmt_watchdog_report_show(fmsg, priv_ctx);

return 0;
}

static const struct devlink_health_reporter_ops hinic_hw_fault_reporter_ops = {
.name = "hw",
.dump = hinic_hw_reporter_dump,
};

static const struct devlink_health_reporter_ops hinic_fw_fault_reporter_ops = {
.name = "fw",
.dump = hinic_fw_reporter_dump,
};

int hinic_health_reporters_create(struct hinic_devlink_priv *priv)
{
struct devlink *devlink = priv_to_devlink(priv);

priv->hw_fault_reporter =
devlink_health_reporter_create(devlink, &hinic_hw_fault_reporter_ops,
0, priv);
if (IS_ERR(priv->hw_fault_reporter)) {
dev_warn(&priv->hwdev->hwif->pdev->dev, "Failed to create hw fault reporter, err: %ld\n",
PTR_ERR(priv->hw_fault_reporter));
return PTR_ERR(priv->hw_fault_reporter);
}

priv->fw_fault_reporter =
devlink_health_reporter_create(devlink, &hinic_fw_fault_reporter_ops,
0, priv);
if (IS_ERR(priv->fw_fault_reporter)) {
dev_warn(&priv->hwdev->hwif->pdev->dev, "Failed to create fw fault reporter, err: %ld\n",
PTR_ERR(priv->fw_fault_reporter));
devlink_health_reporter_destroy(priv->hw_fault_reporter);
priv->hw_fault_reporter = NULL;
return PTR_ERR(priv->fw_fault_reporter);
}

return 0;
}

void hinic_health_reporters_destroy(struct hinic_devlink_priv *priv)
{
if (!IS_ERR_OR_NULL(priv->fw_fault_reporter)) {
devlink_health_reporter_destroy(priv->fw_fault_reporter);
priv->fw_fault_reporter = NULL;
}

if (!IS_ERR_OR_NULL(priv->hw_fault_reporter)) {
devlink_health_reporter_destroy(priv->hw_fault_reporter);
priv->hw_fault_reporter = NULL;
}
}
8 changes: 6 additions & 2 deletions drivers/net/ethernet/huawei/hinic/hinic_devlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define __HINIC_DEVLINK_H__

#include <net/devlink.h>
#include "hinic_dev.h"

#define MAX_FW_TYPE_NUM 30
#define HINIC_MAGIC_NUM 0x18221100
Expand Down Expand Up @@ -109,7 +110,10 @@ struct host_image_st {

struct devlink *hinic_devlink_alloc(void);
void hinic_devlink_free(struct devlink *devlink);
int hinic_devlink_register(struct devlink *devlink, struct device *dev);
void hinic_devlink_unregister(struct devlink *devlink);
int hinic_devlink_register(struct hinic_devlink_priv *priv, struct device *dev);
void hinic_devlink_unregister(struct hinic_devlink_priv *priv);

int hinic_health_reporters_create(struct hinic_devlink_priv *priv);
void hinic_health_reporters_destroy(struct hinic_devlink_priv *priv);

#endif /* __HINIC_DEVLINK_H__ */
20 changes: 20 additions & 0 deletions drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,25 @@ static int hinic_get_module_eeprom(struct net_device *netdev,
return 0;
}

static int
hinic_get_link_ext_state(struct net_device *netdev,
struct ethtool_link_ext_state_info *link_ext_state_info)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);

if (netif_carrier_ok(netdev))
return -ENODATA;

if (nic_dev->cable_unplugged)
link_ext_state_info->link_ext_state =
ETHTOOL_LINK_EXT_STATE_NO_CABLE;
else if (nic_dev->module_unrecognized)
link_ext_state_info->link_ext_state =
ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH;

return 0;
}

static const struct ethtool_ops hinic_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
ETHTOOL_COALESCE_RX_MAX_FRAMES |
Expand All @@ -1776,6 +1795,7 @@ static const struct ethtool_ops hinic_ethtool_ops = {
.set_link_ksettings = hinic_set_link_ksettings,
.get_drvinfo = hinic_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_link_ext_state = hinic_get_link_ext_state,
.get_ringparam = hinic_get_ringparam,
.set_ringparam = hinic_set_ringparam,
.get_coalesce = hinic_get_coalesce,
Expand Down
Loading

0 comments on commit 1255457

Please sign in to comment.