Commit 188fa9b9 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'support-some-enhances-features-for-the-hibmcge-driver'

Jijie Shao says:

====================
Support some enhances features for the HIBMCGE driver

In this patch set, we mainly implement some enhanced features.
It mainly includes the statistics, diagnosis, and ioctl to
improve fault locating efficiency,
abnormal irq and MAC link exception handling feature
to enhance driver robustness,
and rx checksum offload feature to improve performance
(tx checksum feature has been implemented).

v3: https://lore.kernel.org/all/20250221115526.1082660-2-shaojijie@huawei.com/
v2: https://lore.kernel.org/all/20250218085829.3172126-1-shaojijie@huawei.com/
v1: https://lore.kernel.org/all/20250213035529.2402283-1-shaojijie@huawei.com/
====================

Link: https://patch.msgid.link/20250228115411.1750803-1-shaojijie@huawei.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents d1352f76 615552c6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -6,4 +6,4 @@
obj-$(CONFIG_HIBMCGE) += hibmcge.o

hibmcge-objs = hbg_main.o hbg_hw.o hbg_mdio.o hbg_irq.o hbg_txrx.o hbg_ethtool.o \
		hbg_debugfs.o hbg_err.o
		hbg_debugfs.o hbg_err.o hbg_diagnose.o
+122 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ enum hbg_nic_state {
	HBG_NIC_STATE_EVENT_HANDLING = 0,
	HBG_NIC_STATE_RESETTING,
	HBG_NIC_STATE_RESET_FAIL,
	HBG_NIC_STATE_NEED_RESET, /* trigger a reset in scheduled task */
	HBG_NIC_STATE_NP_LINK_FAIL,
};

enum hbg_reset_type {
@@ -81,6 +83,7 @@ enum hbg_hw_event_type {
	HBG_HW_EVENT_NONE = 0,
	HBG_HW_EVENT_INIT, /* driver is loading */
	HBG_HW_EVENT_RESET,
	HBG_HW_EVENT_CORE_RESET,
};

struct hbg_dev_specs {
@@ -104,6 +107,7 @@ struct hbg_irq_info {
	u32 mask;
	bool re_enable;
	bool need_print;
	bool need_reset;
	u64 count;

	void (*irq_handle)(struct hbg_priv *priv, struct hbg_irq_info *info);
@@ -142,6 +146,118 @@ struct hbg_user_def {
	struct ethtool_pauseparam pause_param;
};

struct hbg_stats {
	u64 rx_desc_drop;
	u64 rx_desc_l2_err_cnt;
	u64 rx_desc_pkt_len_err_cnt;
	u64 rx_desc_l3l4_err_cnt;
	u64 rx_desc_l3_wrong_head_cnt;
	u64 rx_desc_l3_csum_err_cnt;
	u64 rx_desc_l3_len_err_cnt;
	u64 rx_desc_l3_zero_ttl_cnt;
	u64 rx_desc_l3_other_cnt;
	u64 rx_desc_l4_err_cnt;
	u64 rx_desc_l4_wrong_head_cnt;
	u64 rx_desc_l4_len_err_cnt;
	u64 rx_desc_l4_csum_err_cnt;
	u64 rx_desc_l4_zero_port_num_cnt;
	u64 rx_desc_l4_other_cnt;
	u64 rx_desc_frag_cnt;
	u64 rx_desc_ip_ver_err_cnt;
	u64 rx_desc_ipv4_pkt_cnt;
	u64 rx_desc_ipv6_pkt_cnt;
	u64 rx_desc_no_ip_pkt_cnt;
	u64 rx_desc_ip_pkt_cnt;
	u64 rx_desc_tcp_pkt_cnt;
	u64 rx_desc_udp_pkt_cnt;
	u64 rx_desc_vlan_pkt_cnt;
	u64 rx_desc_icmp_pkt_cnt;
	u64 rx_desc_arp_pkt_cnt;
	u64 rx_desc_rarp_pkt_cnt;
	u64 rx_desc_multicast_pkt_cnt;
	u64 rx_desc_broadcast_pkt_cnt;
	u64 rx_desc_ipsec_pkt_cnt;
	u64 rx_desc_ip_opt_pkt_cnt;
	u64 rx_desc_key_not_match_cnt;

	u64 rx_octets_total_ok_cnt;
	u64 rx_uc_pkt_cnt;
	u64 rx_mc_pkt_cnt;
	u64 rx_bc_pkt_cnt;
	u64 rx_vlan_pkt_cnt;
	u64 rx_octets_bad_cnt;
	u64 rx_octets_total_filt_cnt;
	u64 rx_filt_pkt_cnt;
	u64 rx_trans_pkt_cnt;
	u64 rx_framesize_64;
	u64 rx_framesize_65_127;
	u64 rx_framesize_128_255;
	u64 rx_framesize_256_511;
	u64 rx_framesize_512_1023;
	u64 rx_framesize_1024_1518;
	u64 rx_framesize_bt_1518;
	u64 rx_fcs_error_cnt;
	u64 rx_data_error_cnt;
	u64 rx_align_error_cnt;
	u64 rx_pause_macctl_frame_cnt;
	u64 rx_unknown_macctl_frame_cnt;
	/* crc ok, > max_frm_size, < 2max_frm_size */
	u64 rx_frame_long_err_cnt;
	/* crc fail, > max_frm_size, < 2max_frm_size */
	u64 rx_jabber_err_cnt;
	/* > 2max_frm_size */
	u64 rx_frame_very_long_err_cnt;
	/* < 64byte, >= short_runts_thr */
	u64 rx_frame_runt_err_cnt;
	/* < short_runts_thr */
	u64 rx_frame_short_err_cnt;
	/* PCU: dropped when the RX FIFO is full.*/
	u64 rx_overflow_cnt;
	/* GMAC: the count of overflows of the RX FIFO */
	u64 rx_overrun_cnt;
	/* PCU: the count of buffer alloc errors in RX */
	u64 rx_bufrq_err_cnt;
	/* PCU: the count of write descriptor errors in RX */
	u64 rx_we_err_cnt;
	/* GMAC: the count of pkts that contain PAD but length is not 64 */
	u64 rx_lengthfield_err_cnt;
	u64 rx_fail_comma_cnt;

	u64 rx_dma_err_cnt;
	u64 rx_fifo_less_empty_thrsld_cnt;

	u64 tx_octets_total_ok_cnt;
	u64 tx_uc_pkt_cnt;
	u64 tx_mc_pkt_cnt;
	u64 tx_bc_pkt_cnt;
	u64 tx_vlan_pkt_cnt;
	u64 tx_octets_bad_cnt;
	u64 tx_trans_pkt_cnt;
	u64 tx_pause_frame_cnt;
	u64 tx_framesize_64;
	u64 tx_framesize_65_127;
	u64 tx_framesize_128_255;
	u64 tx_framesize_256_511;
	u64 tx_framesize_512_1023;
	u64 tx_framesize_1024_1518;
	u64 tx_framesize_bt_1518;
	/* GMAC: the count of times that frames fail to be transmitted
	 *       due to internal errors.
	 */
	u64 tx_underrun_err_cnt;
	u64 tx_add_cs_fail_cnt;
	/* PCU: the count of buffer free errors in TX */
	u64 tx_bufrl_err_cnt;
	u64 tx_crc_err_cnt;
	u64 tx_drop_cnt;
	u64 tx_excessive_length_drop_cnt;

	u64 tx_timeout_cnt;
	u64 tx_dma_err_cnt;

	u64 np_link_fail_cnt;
};

struct hbg_priv {
	struct net_device *netdev;
	struct pci_dev *pdev;
@@ -155,6 +271,12 @@ struct hbg_priv {
	struct hbg_mac_filter filter;
	enum hbg_reset_type reset_type;
	struct hbg_user_def user_def;
	struct hbg_stats stats;
	unsigned long last_update_stats_time;
	struct delayed_work service_task;
};

void hbg_err_reset_task_schedule(struct hbg_priv *priv);
void hbg_np_link_fail_task_schedule(struct hbg_priv *priv);

#endif
+6 −1
Original line number Diff line number Diff line
@@ -67,10 +67,11 @@ static int hbg_dbg_irq_info(struct seq_file *s, void *unused)
	for (i = 0; i < priv->vectors.info_array_len; i++) {
		info = &priv->vectors.info_array[i];
		seq_printf(s,
			   "%-20s: enabled: %-5s, logged: %-5s, count: %llu\n",
			   "%-20s: enabled: %-5s, reset: %-5s, logged: %-5s, count: %llu\n",
			   info->name,
			   str_true_false(hbg_hw_irq_is_enabled(priv,
								info->mask)),
			   str_true_false(info->need_reset),
			   str_true_false(info->need_print),
			   info->count);
	}
@@ -114,6 +115,10 @@ static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
		   state_str_true_false(priv, HBG_NIC_STATE_RESET_FAIL));
	seq_printf(s, "last reset type: %s\n",
		   reset_type_str[priv->reset_type]);
	seq_printf(s, "need reset state: %s\n",
		   state_str_true_false(priv, HBG_NIC_STATE_NEED_RESET));
	seq_printf(s, "np_link fail state: %s\n",
		   state_str_true_false(priv, HBG_NIC_STATE_NP_LINK_FAIL));

	return 0;
}
+348 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2025 Hisilicon Limited.

#include <linux/iopoll.h>
#include <linux/phy.h>
#include "hbg_common.h"
#include "hbg_ethtool.h"
#include "hbg_hw.h"
#include "hbg_diagnose.h"

#define HBG_MSG_DATA_MAX_NUM	64

struct hbg_diagnose_message {
	u32 opcode;
	u32 status;
	u32 data_num;
	struct hbg_priv *priv;

	u32 data[HBG_MSG_DATA_MAX_NUM];
};

#define HBG_HW_PUSH_WAIT_TIMEOUT_US	(2 * 1000 * 1000)
#define HBG_HW_PUSH_WAIT_INTERVAL_US	(1 * 1000)

enum hbg_push_cmd {
	HBG_PUSH_CMD_IRQ = 0,
	HBG_PUSH_CMD_STATS,
	HBG_PUSH_CMD_LINK,
};

struct hbg_push_stats_info {
	/* id is used to match the name of the current stats item.
	 * and is used for pretty print on BMC
	 */
	u32 id;
	u64 offset;
};

struct hbg_push_irq_info {
	/* id is used to match the name of the current irq.
	 * and is used for pretty print on BMC
	 */
	u32 id;
	u32 mask;
};

#define HBG_PUSH_IRQ_I(name, id) {id, HBG_INT_MSK_##name##_B}
static const struct hbg_push_irq_info hbg_push_irq_list[] = {
	HBG_PUSH_IRQ_I(RX, 0),
	HBG_PUSH_IRQ_I(TX, 1),
	HBG_PUSH_IRQ_I(TX_PKT_CPL, 2),
	HBG_PUSH_IRQ_I(MAC_MII_FIFO_ERR, 3),
	HBG_PUSH_IRQ_I(MAC_PCS_RX_FIFO_ERR, 4),
	HBG_PUSH_IRQ_I(MAC_PCS_TX_FIFO_ERR, 5),
	HBG_PUSH_IRQ_I(MAC_APP_RX_FIFO_ERR, 6),
	HBG_PUSH_IRQ_I(MAC_APP_TX_FIFO_ERR, 7),
	HBG_PUSH_IRQ_I(SRAM_PARITY_ERR, 8),
	HBG_PUSH_IRQ_I(TX_AHB_ERR, 9),
	HBG_PUSH_IRQ_I(RX_BUF_AVL, 10),
	HBG_PUSH_IRQ_I(REL_BUF_ERR, 11),
	HBG_PUSH_IRQ_I(TXCFG_AVL, 12),
	HBG_PUSH_IRQ_I(TX_DROP, 13),
	HBG_PUSH_IRQ_I(RX_DROP, 14),
	HBG_PUSH_IRQ_I(RX_AHB_ERR, 15),
	HBG_PUSH_IRQ_I(MAC_FIFO_ERR, 16),
	HBG_PUSH_IRQ_I(RBREQ_ERR, 17),
	HBG_PUSH_IRQ_I(WE_ERR, 18),
};

#define HBG_PUSH_STATS_I(name, id) {id, HBG_STATS_FIELD_OFF(name)}
static const struct hbg_push_stats_info hbg_push_stats_list[] = {
	HBG_PUSH_STATS_I(rx_desc_drop, 0),
	HBG_PUSH_STATS_I(rx_desc_l2_err_cnt, 1),
	HBG_PUSH_STATS_I(rx_desc_pkt_len_err_cnt, 2),
	HBG_PUSH_STATS_I(rx_desc_l3_wrong_head_cnt, 3),
	HBG_PUSH_STATS_I(rx_desc_l3_csum_err_cnt, 4),
	HBG_PUSH_STATS_I(rx_desc_l3_len_err_cnt, 5),
	HBG_PUSH_STATS_I(rx_desc_l3_zero_ttl_cnt, 6),
	HBG_PUSH_STATS_I(rx_desc_l3_other_cnt, 7),
	HBG_PUSH_STATS_I(rx_desc_l4_err_cnt, 8),
	HBG_PUSH_STATS_I(rx_desc_l4_wrong_head_cnt, 9),
	HBG_PUSH_STATS_I(rx_desc_l4_len_err_cnt, 10),
	HBG_PUSH_STATS_I(rx_desc_l4_csum_err_cnt, 11),
	HBG_PUSH_STATS_I(rx_desc_l4_zero_port_num_cnt, 12),
	HBG_PUSH_STATS_I(rx_desc_l4_other_cnt, 13),
	HBG_PUSH_STATS_I(rx_desc_frag_cnt, 14),
	HBG_PUSH_STATS_I(rx_desc_ip_ver_err_cnt, 15),
	HBG_PUSH_STATS_I(rx_desc_ipv4_pkt_cnt, 16),
	HBG_PUSH_STATS_I(rx_desc_ipv6_pkt_cnt, 17),
	HBG_PUSH_STATS_I(rx_desc_no_ip_pkt_cnt, 18),
	HBG_PUSH_STATS_I(rx_desc_ip_pkt_cnt, 19),
	HBG_PUSH_STATS_I(rx_desc_tcp_pkt_cnt, 20),
	HBG_PUSH_STATS_I(rx_desc_udp_pkt_cnt, 21),
	HBG_PUSH_STATS_I(rx_desc_vlan_pkt_cnt, 22),
	HBG_PUSH_STATS_I(rx_desc_icmp_pkt_cnt, 23),
	HBG_PUSH_STATS_I(rx_desc_arp_pkt_cnt, 24),
	HBG_PUSH_STATS_I(rx_desc_rarp_pkt_cnt, 25),
	HBG_PUSH_STATS_I(rx_desc_multicast_pkt_cnt, 26),
	HBG_PUSH_STATS_I(rx_desc_broadcast_pkt_cnt, 27),
	HBG_PUSH_STATS_I(rx_desc_ipsec_pkt_cnt, 28),
	HBG_PUSH_STATS_I(rx_desc_ip_opt_pkt_cnt, 29),
	HBG_PUSH_STATS_I(rx_desc_key_not_match_cnt, 30),
	HBG_PUSH_STATS_I(rx_octets_total_ok_cnt, 31),
	HBG_PUSH_STATS_I(rx_uc_pkt_cnt, 32),
	HBG_PUSH_STATS_I(rx_mc_pkt_cnt, 33),
	HBG_PUSH_STATS_I(rx_bc_pkt_cnt, 34),
	HBG_PUSH_STATS_I(rx_vlan_pkt_cnt, 35),
	HBG_PUSH_STATS_I(rx_octets_bad_cnt, 36),
	HBG_PUSH_STATS_I(rx_octets_total_filt_cnt, 37),
	HBG_PUSH_STATS_I(rx_filt_pkt_cnt, 38),
	HBG_PUSH_STATS_I(rx_trans_pkt_cnt, 39),
	HBG_PUSH_STATS_I(rx_framesize_64, 40),
	HBG_PUSH_STATS_I(rx_framesize_65_127, 41),
	HBG_PUSH_STATS_I(rx_framesize_128_255, 42),
	HBG_PUSH_STATS_I(rx_framesize_256_511, 43),
	HBG_PUSH_STATS_I(rx_framesize_512_1023, 44),
	HBG_PUSH_STATS_I(rx_framesize_1024_1518, 45),
	HBG_PUSH_STATS_I(rx_framesize_bt_1518, 46),
	HBG_PUSH_STATS_I(rx_fcs_error_cnt, 47),
	HBG_PUSH_STATS_I(rx_data_error_cnt, 48),
	HBG_PUSH_STATS_I(rx_align_error_cnt, 49),
	HBG_PUSH_STATS_I(rx_frame_long_err_cnt, 50),
	HBG_PUSH_STATS_I(rx_jabber_err_cnt, 51),
	HBG_PUSH_STATS_I(rx_pause_macctl_frame_cnt, 52),
	HBG_PUSH_STATS_I(rx_unknown_macctl_frame_cnt, 53),
	HBG_PUSH_STATS_I(rx_frame_very_long_err_cnt, 54),
	HBG_PUSH_STATS_I(rx_frame_runt_err_cnt, 55),
	HBG_PUSH_STATS_I(rx_frame_short_err_cnt, 56),
	HBG_PUSH_STATS_I(rx_overflow_cnt, 57),
	HBG_PUSH_STATS_I(rx_bufrq_err_cnt, 58),
	HBG_PUSH_STATS_I(rx_we_err_cnt, 59),
	HBG_PUSH_STATS_I(rx_overrun_cnt, 60),
	HBG_PUSH_STATS_I(rx_lengthfield_err_cnt, 61),
	HBG_PUSH_STATS_I(rx_fail_comma_cnt, 62),
	HBG_PUSH_STATS_I(rx_dma_err_cnt, 63),
	HBG_PUSH_STATS_I(rx_fifo_less_empty_thrsld_cnt, 64),
	HBG_PUSH_STATS_I(tx_octets_total_ok_cnt, 65),
	HBG_PUSH_STATS_I(tx_uc_pkt_cnt, 66),
	HBG_PUSH_STATS_I(tx_mc_pkt_cnt, 67),
	HBG_PUSH_STATS_I(tx_bc_pkt_cnt, 68),
	HBG_PUSH_STATS_I(tx_vlan_pkt_cnt, 69),
	HBG_PUSH_STATS_I(tx_octets_bad_cnt, 70),
	HBG_PUSH_STATS_I(tx_trans_pkt_cnt, 71),
	HBG_PUSH_STATS_I(tx_pause_frame_cnt, 72),
	HBG_PUSH_STATS_I(tx_framesize_64, 73),
	HBG_PUSH_STATS_I(tx_framesize_65_127, 74),
	HBG_PUSH_STATS_I(tx_framesize_128_255, 75),
	HBG_PUSH_STATS_I(tx_framesize_256_511, 76),
	HBG_PUSH_STATS_I(tx_framesize_512_1023, 77),
	HBG_PUSH_STATS_I(tx_framesize_1024_1518, 78),
	HBG_PUSH_STATS_I(tx_framesize_bt_1518, 79),
	HBG_PUSH_STATS_I(tx_underrun_err_cnt, 80),
	HBG_PUSH_STATS_I(tx_add_cs_fail_cnt, 81),
	HBG_PUSH_STATS_I(tx_bufrl_err_cnt, 82),
	HBG_PUSH_STATS_I(tx_crc_err_cnt, 83),
	HBG_PUSH_STATS_I(tx_drop_cnt, 84),
	HBG_PUSH_STATS_I(tx_excessive_length_drop_cnt, 85),
	HBG_PUSH_STATS_I(tx_dma_err_cnt, 86),
};

static int hbg_push_msg_send(struct hbg_priv *priv,
			     struct hbg_diagnose_message *msg)
{
	u32 header = 0;
	u32 i;

	if (msg->data_num == 0)
		return 0;

	for (i = 0; i < msg->data_num && i < HBG_MSG_DATA_MAX_NUM; i++)
		hbg_reg_write(priv,
			      HBG_REG_MSG_DATA_BASE_ADDR + i * sizeof(u32),
			      msg->data[i]);

	hbg_field_modify(header, HBG_REG_MSG_HEADER_OPCODE_M, msg->opcode);
	hbg_field_modify(header, HBG_REG_MSG_HEADER_DATA_NUM_M,  msg->data_num);
	hbg_field_modify(header, HBG_REG_MSG_HEADER_RESP_CODE_M, ETIMEDOUT);

	/* start status */
	hbg_field_modify(header, HBG_REG_MSG_HEADER_STATUS_M, 1);

	/* write header msg to start push */
	hbg_reg_write(priv, HBG_REG_MSG_HEADER_ADDR, header);

	/* wait done */
	readl_poll_timeout(priv->io_base + HBG_REG_MSG_HEADER_ADDR, header,
			   !FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header),
			   HBG_HW_PUSH_WAIT_INTERVAL_US,
			   HBG_HW_PUSH_WAIT_TIMEOUT_US);

	msg->status = FIELD_GET(HBG_REG_MSG_HEADER_STATUS_M, header);
	return -(int)FIELD_GET(HBG_REG_MSG_HEADER_RESP_CODE_M, header);
}

static int hbg_push_data(struct hbg_priv *priv,
			 u32 opcode, u32 *data, u32 data_num)
{
	struct hbg_diagnose_message msg = {0};
	u32 data_left_num;
	u32 i, j;
	int ret;

	msg.priv = priv;
	msg.opcode = opcode;
	for (i = 0; i < data_num / HBG_MSG_DATA_MAX_NUM + 1; i++) {
		if (i * HBG_MSG_DATA_MAX_NUM >= data_num)
			break;

		data_left_num = data_num - i * HBG_MSG_DATA_MAX_NUM;
		for (j = 0; j < data_left_num && j < HBG_MSG_DATA_MAX_NUM; j++)
			msg.data[j] = data[i * HBG_MSG_DATA_MAX_NUM + j];

		msg.data_num = j;
		ret = hbg_push_msg_send(priv, &msg);
		if (ret)
			return ret;
	}

	return 0;
}

static int hbg_push_data_u64(struct hbg_priv *priv, u32 opcode,
			     u64 *data, u32 data_num)
{
	/* The length of u64 is twice that of u32,
	 * the data_num must be multiplied by 2.
	 */
	return hbg_push_data(priv, opcode, (u32 *)data, data_num * 2);
}

static u64 hbg_get_irq_stats(struct hbg_vector *vectors, u32 mask)
{
	u32 i = 0;

	for (i = 0; i < vectors->info_array_len; i++)
		if (vectors->info_array[i].mask == mask)
			return vectors->info_array[i].count;

	return 0;
}

static int hbg_push_irq_cnt(struct hbg_priv *priv)
{
	/* An id needs to be added for each data.
	 * Therefore, the data_num must be multiplied by 2.
	 */
	u32 data_num = ARRAY_SIZE(hbg_push_irq_list) * 2;
	struct hbg_vector *vectors = &priv->vectors;
	const struct hbg_push_irq_info *info;
	u32 i, j = 0;
	u64 *data;
	int ret;

	data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	/* An id needs to be added for each data.
	 * So i + 2 for each loop.
	 */
	for (i = 0; i < data_num; i += 2) {
		info = &hbg_push_irq_list[j++];
		data[i] = info->id;
		data[i + 1] = hbg_get_irq_stats(vectors, info->mask);
	}

	ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_IRQ, data, data_num);
	kfree(data);
	return ret;
}

static int hbg_push_link_status(struct hbg_priv *priv)
{
	u32 link_status[2];

	/* phy link status */
	link_status[0] = priv->mac.phydev->link;
	/* mac link status */
	link_status[1] = hbg_reg_read_field(priv, HBG_REG_AN_NEG_STATE_ADDR,
					    HBG_REG_AN_NEG_STATE_NP_LINK_OK_B);

	return hbg_push_data(priv, HBG_PUSH_CMD_LINK,
			     link_status, ARRAY_SIZE(link_status));
}

static int hbg_push_stats(struct hbg_priv *priv)
{
	/* An id needs to be added for each data.
	 * Therefore, the data_num must be multiplied by 2.
	 */
	u64 data_num = ARRAY_SIZE(hbg_push_stats_list) * 2;
	struct hbg_stats *stats = &priv->stats;
	const struct hbg_push_stats_info *info;
	u32 i, j = 0;
	u64 *data;
	int ret;

	data = kcalloc(data_num, sizeof(u64), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	/* An id needs to be added for each data.
	 * So i + 2 for each loop.
	 */
	for (i = 0; i < data_num; i += 2) {
		info = &hbg_push_stats_list[j++];
		data[i] = info->id;
		data[i + 1] = HBG_STATS_R(stats, info->offset);
	}

	ret = hbg_push_data_u64(priv, HBG_PUSH_CMD_STATS, data, data_num);
	kfree(data);
	return ret;
}

void hbg_diagnose_message_push(struct hbg_priv *priv)
{
	int ret;

	if (test_bit(HBG_NIC_STATE_RESETTING, &priv->state))
		return;

	/* only 1 is the right value */
	if (hbg_reg_read(priv, HBG_REG_PUSH_REQ_ADDR) != 1)
		return;

	ret = hbg_push_irq_cnt(priv);
	if (ret) {
		dev_err(&priv->pdev->dev,
			"failed to push irq cnt, ret = %d\n", ret);
		goto push_done;
	}

	ret = hbg_push_link_status(priv);
	if (ret) {
		dev_err(&priv->pdev->dev,
			"failed to push link status, ret = %d\n", ret);
		goto push_done;
	}

	ret = hbg_push_stats(priv);
	if (ret)
		dev_err(&priv->pdev->dev,
			"failed to push stats, ret = %d\n", ret);

push_done:
	hbg_reg_write(priv, HBG_REG_PUSH_REQ_ADDR, 0);
}
+11 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2025 Hisilicon Limited. */

#ifndef __HBG_DIAGNOSE_H
#define __HBG_DIAGNOSE_H

#include "hbg_common.h"

void hbg_diagnose_message_push(struct hbg_priv *priv);

#endif
Loading