Commit 26f6cbad authored by Tian Jiang's avatar Tian Jiang Committed by Jiantao Xiao
Browse files

net: hns3: add supports pfc storm detection and suppression

driver inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I6QRKC


CVE: NA

----------------------------------------------------------------------

To solve the problem of abnormal transmission of pauses or PFC frames,
the IMP periodically checks the transmission and reception status of
packets. If a pause frame storm occurs, the pause storm response of
the MAC address is disabled for a period of time.

Signed-off-by: default avatarTian Jiang <jiangtian6@h-partners.com>
Signed-off-by: default avatarshaojijie <shaojijie@huawei.com>
Signed-off-by: default avatarJiantao Xiao <xiaojiantao1@h-partners.com>
parent 62aede9f
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -28,5 +28,15 @@ enum hnae3_event_type_custom {
enum hnae3_ext_opcode {
	HNAE3_EXT_OPC_RESET,
	HNAE3_EXT_OPC_EVENT_CALLBACK,
	HNAE3_EXT_OPC_GET_PFC_STORM_PARA,
	HNAE3_EXT_OPC_SET_PFC_STORM_PARA,
};

struct hnae3_pfc_storm_para {
	u32 dir;
	u32 enable;
	u32 period_ms;
	u32 times;
	u32 recovery_period_ms;
};
#endif
+70 −0
Original line number Diff line number Diff line
@@ -73,3 +73,73 @@ void nic_chip_recover_handler(struct net_device *ndev,
	nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_RESET, &event_t, sizeof(event_t));
}
EXPORT_SYMBOL(nic_chip_recover_handler);

static int nic_check_pfc_storm_para(int dir, int enable, int period_ms,
				    int times, int recovery_period_ms)
{
	if ((dir != HNS3_PFC_STORM_PARA_DIR_RX &&
	     dir != HNS3_PFC_STORM_PARA_DIR_TX) ||
	     (enable != HNS3_PFC_STORM_PARA_DISABLE &&
	      enable != HNS3_PFC_STORM_PARA_ENABLE))
		return -EINVAL;

	if (period_ms < HNS3_PFC_STORM_PARA_PERIOD_MIN ||
	    period_ms > HNS3_PFC_STORM_PARA_PERIOD_MAX ||
	    recovery_period_ms < HNS3_PFC_STORM_PARA_PERIOD_MIN ||
	    recovery_period_ms > HNS3_PFC_STORM_PARA_PERIOD_MAX ||
	    times <= 0)
		return -EINVAL;

	return 0;
}

int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable,
			   int period_ms, int times, int recovery_period_ms)
{
	struct hnae3_pfc_storm_para para;

	if (nic_check_pfc_storm_para(dir, enable, period_ms, times,
				     recovery_period_ms)) {
		dev_err(&ndev->dev,
			"set pfc storm para failed because invalid input param.\n");
		return -EINVAL;
	}

	para.dir = dir;
	para.enable = enable;
	para.period_ms = period_ms;
	para.times = times;
	para.recovery_period_ms = recovery_period_ms;

	return nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_SET_PFC_STORM_PARA,
				  &para, sizeof(para));
}
EXPORT_SYMBOL(nic_set_pfc_storm_para);

int nic_get_pfc_storm_para(struct net_device *ndev, int dir, int *enable,
			   int *period_ms, int *times, int *recovery_period_ms)
{
	struct hnae3_pfc_storm_para para;
	int ret;

	if (!enable || !period_ms || !times || !recovery_period_ms ||
	    (dir != HNS3_PFC_STORM_PARA_DIR_RX &&
	     dir != HNS3_PFC_STORM_PARA_DIR_TX)) {
		dev_err(&ndev->dev,
			"get pfc storm para failed because invalid input param.\n");
		return -EINVAL;
	}

	para.dir = dir;
	ret = nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_GET_PFC_STORM_PARA,
				 &para, sizeof(para));
	if (ret)
		return ret;

	*enable = para.enable;
	*period_ms = para.period_ms;
	*times = para.times;
	*recovery_period_ms = para.recovery_period_ms;
	return 0;
}
EXPORT_SYMBOL(nic_get_pfc_storm_para);
+11 −0
Original line number Diff line number Diff line
@@ -7,7 +7,18 @@
#include "hns3_enet.h"
#include "hnae3_ext.h"

#define HNS3_PFC_STORM_PARA_DIR_RX 0
#define HNS3_PFC_STORM_PARA_DIR_TX 1
#define HNS3_PFC_STORM_PARA_DISABLE 0
#define HNS3_PFC_STORM_PARA_ENABLE 1
#define HNS3_PFC_STORM_PARA_PERIOD_MIN 5
#define HNS3_PFC_STORM_PARA_PERIOD_MAX 2000

int nic_netdev_match_check(struct net_device *netdev);
void nic_chip_recover_handler(struct net_device *ndev,
			      enum hnae3_event_type_custom event_t);
int nic_set_pfc_storm_para(struct net_device *ndev, int dir, int enable,
			   int period_ms, int times, int recovery_period_ms);
int nic_get_pfc_storm_para(struct net_device *ndev, int dir, int *enable,
			   int *period_ms, int *times, int *recovery_period_ms);
#endif
+60 −0
Original line number Diff line number Diff line
@@ -15,6 +15,64 @@ static nic_event_fn_t nic_event_call;
 */
static DEFINE_MUTEX(hclge_nic_event_lock);

static int hclge_set_pfc_storm_para(struct hclge_dev *hdev, void *data,
				    size_t length)
{
	struct hclge_pfc_storm_para_cmd *para_cmd;
	struct hnae3_pfc_storm_para *para;
	struct hclge_desc desc;
	int ret;

	if (length != sizeof(struct hnae3_pfc_storm_para))
		return -EINVAL;

	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA,
				   false);
	para = (struct hnae3_pfc_storm_para *)data;
	para_cmd = (struct hclge_pfc_storm_para_cmd *)desc.data;
	para_cmd->dir = cpu_to_le32(para->dir);
	para_cmd->enable = cpu_to_le32(para->enable);
	para_cmd->period_ms = cpu_to_le32(para->period_ms);
	para_cmd->times = cpu_to_le32(para->times);
	para_cmd->recovery_period_ms = cpu_to_le32(para->recovery_period_ms);

	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
	if (ret)
		dev_err(&hdev->pdev->dev,
			"failed to set pfc storm para, ret = %d\n", ret);
	return ret;
}

static int hclge_get_pfc_storm_para(struct hclge_dev *hdev, void *data,
				    size_t length)
{
	struct hclge_pfc_storm_para_cmd *para_cmd;
	struct hnae3_pfc_storm_para *para;
	struct hclge_desc desc;
	int ret;

	if (length != sizeof(struct hnae3_pfc_storm_para))
		return -EINVAL;

	hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CFG_PAUSE_STORM_PARA, true);
	para = (struct hnae3_pfc_storm_para *)data;
	para_cmd = (struct hclge_pfc_storm_para_cmd *)desc.data;
	para_cmd->dir = cpu_to_le32(para->dir);
	ret = hclge_cmd_send(&hdev->hw, &desc, 1);
	if (ret) {
		dev_err(&hdev->pdev->dev,
			"failed to get pfc storm para, ret = %d\n", ret);
		return ret;
	}

	para->enable = le32_to_cpu(para_cmd->enable);
	para->period_ms = le32_to_cpu(para_cmd->period_ms);
	para->times = le32_to_cpu(para_cmd->times);
	para->recovery_period_ms = le32_to_cpu(para_cmd->recovery_period_ms);

	return 0;
}

static int hclge_set_reset_task(struct hclge_dev *hdev, void *data,
				size_t length)
{
@@ -151,6 +209,8 @@ void hclge_ext_reset_end(struct hclge_dev *hdev, bool done)
static const hclge_priv_ops_fn hclge_ext_func_arr[] = {
	[HNAE3_EXT_OPC_RESET] = hclge_set_reset_task,
	[HNAE3_EXT_OPC_EVENT_CALLBACK] = hclge_nic_call_event,
	[HNAE3_EXT_OPC_GET_PFC_STORM_PARA] = hclge_get_pfc_storm_para,
	[HNAE3_EXT_OPC_SET_PFC_STORM_PARA] = hclge_set_pfc_storm_para,
};

int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
+13 −0
Original line number Diff line number Diff line
@@ -5,6 +5,19 @@
#define __HCLGE_EXT_H
#include <linux/types.h>

struct hclge_pfc_storm_para_cmd {
	__le32 dir;
	__le32 enable;
	__le32 period_ms;
	__le32 times;
	__le32 recovery_period_ms;
	__le32 rsv;
};

enum hclge_ext_opcode_type {
	HCLGE_OPC_CFG_PAUSE_STORM_PARA = 0x7019,
};

struct hclge_reset_fail_type_map {
	enum hnae3_reset_type reset_type;
	enum hnae3_event_type_custom custom_type;