775 lines
25 KiB
Diff
775 lines
25 KiB
Diff
From 66962d2f2ca31c150b28b43e99654f6c85889357 Mon Sep 17 00:00:00 2001
|
|
From: Tian Jiang <jiangtian6@h-partners.com>
|
|
Date: Thu, 9 Mar 2023 10:59:36 +0800
|
|
Subject: [PATCH 191/283] net: hns3: add support customized exception handling
|
|
interfaces.
|
|
|
|
driver inclusion
|
|
category: feature
|
|
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I8EN3D
|
|
CVE: NA
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
Establish a framework to support customization requirement. Provides
|
|
interfaces to register special processing functions. When the system
|
|
is reset due to an abnormal interrupt, the registered handler is
|
|
called first.
|
|
|
|
Signed-off-by: Tian Jiang <jiangtian6@h-partners.com>
|
|
Signed-off-by: shaojijie <shaojijie@huawei.com>
|
|
Signed-off-by: Jiantao Xiao <xiaojiantao1@h-partners.com>
|
|
Signed-off-by: Xiaodong Li <lixiaodong67@huawei.com>
|
|
|
|
Conflicts:
|
|
drivers/net/ethernet/hisilicon/hns3/Makefile
|
|
drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
|
|
---
|
|
drivers/net/ethernet/hisilicon/hns3/Makefile | 3 +
|
|
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +
|
|
.../net/ethernet/hisilicon/hns3/hnae3_ext.h | 32 ++++
|
|
.../net/ethernet/hisilicon/hns3/hns3_enet.c | 5 +
|
|
.../net/ethernet/hisilicon/hns3/hns3_ext.c | 76 ++++++++
|
|
.../net/ethernet/hisilicon/hns3/hns3_ext.h | 13 ++
|
|
.../hns3_extension/hns3pf/hclge_main_it.c | 22 +--
|
|
.../hns3_extension/hns3pf/hclge_main_it.h | 32 ----
|
|
.../hisilicon/hns3/hns3pf/hclge_ext.c | 178 ++++++++++++++++++
|
|
.../hisilicon/hns3/hns3pf/hclge_ext.h | 43 +++++
|
|
.../hisilicon/hns3/hns3pf/hclge_main.c | 45 ++---
|
|
.../hisilicon/hns3/hns3pf/hclge_main.h | 5 +-
|
|
.../hisilicon/hns3/hns3pf/hclge_mbx.c | 2 +-
|
|
13 files changed, 382 insertions(+), 76 deletions(-)
|
|
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hnae3_ext.h
|
|
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_ext.c
|
|
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3_ext.h
|
|
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.c
|
|
create mode 100644 drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.h
|
|
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/Makefile b/drivers/net/ethernet/hisilicon/hns3/Makefile
|
|
index 70bf49da5591..d0f56781b558 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/Makefile
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/Makefile
|
|
@@ -26,6 +26,7 @@ HNS3_OBJS = hns3_enet.o \
|
|
HNS3_OBJS_IT = hns3_extension/hns3_enet_it.o
|
|
obj-$(CONFIG_HNS3_ENET) += hns3.o
|
|
hns3-objs = $(HNS3_OBJS) $(HNS3_OBJS_IT)
|
|
+hns3-objs += hns3_ext.o
|
|
|
|
hns3-$(CONFIG_HNS3_DCB) += hns3_dcbnl.o
|
|
|
|
@@ -44,6 +45,8 @@ HCLGE_OBJ_IT_MAIN = hns3_extension/hns3pf/hclge_main_it.o \
|
|
hns3_extension/hns3pf/hclge_sysfs.o
|
|
obj-$(CONFIG_HNS3_HCLGE) += hclge.o
|
|
hclge-objs := $(HCLGE_OBJ) $(HCLGE_OBJ_IT_MAIN)
|
|
+hclge-objs += hns3pf/hclge_ext.o
|
|
+
|
|
hclge-$(CONFIG_HNS3_DCB) += hns3pf/hclge_dcb.o
|
|
#### compile hclgevf.ko
|
|
obj-$(CONFIG_HNS3_HCLGEVF) += hclgevf.o
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
index d15038e8bcb5..970ef08ce9cc 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h
|
|
@@ -787,6 +787,8 @@ struct hnae3_ae_ops {
|
|
struct ethtool_wolinfo *wol);
|
|
int (*set_wol)(struct hnae3_handle *handle,
|
|
struct ethtool_wolinfo *wol);
|
|
+ int (*priv_ops)(struct hnae3_handle *handle, int opcode,
|
|
+ void *data, size_t length);
|
|
/* Notice! If the function is not for test, the definition must before
|
|
* CONFIG_HNS3_TEST! Because RoCE will use this head file, and it won't
|
|
* set CONFIG_HNS3_TEST, that may cause RoCE calling the wrong function.
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3_ext.h b/drivers/net/ethernet/hisilicon/hns3/hnae3_ext.h
|
|
new file mode 100644
|
|
index 000000000000..0b1fa53dfb41
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3_ext.h
|
|
@@ -0,0 +1,32 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ */
|
|
+// Copyright (c) 2023 Hisilicon Limited.
|
|
+
|
|
+#ifndef __HNAE3_EXT_H
|
|
+#define __HNAE3_EXT_H
|
|
+
|
|
+enum hnae3_event_type_custom {
|
|
+ HNAE3_VF_RESET_CUSTOM,
|
|
+ HNAE3_VF_FUNC_RESET_CUSTOM,
|
|
+ HNAE3_VF_PF_FUNC_RESET_CUSTOM,
|
|
+ HNAE3_VF_FULL_RESET_CUSTOM,
|
|
+ HNAE3_FLR_RESET_CUSTOM,
|
|
+ HNAE3_FUNC_RESET_CUSTOM,
|
|
+ HNAE3_GLOBAL_RESET_CUSTOM,
|
|
+ HNAE3_IMP_RESET_CUSTOM,
|
|
+ HNAE3_UNKNOWN_RESET_CUSTOM,
|
|
+ HNAE3_NONE_RESET_CUSTOM,
|
|
+ HNAE3_PORT_FAULT,
|
|
+ HNAE3_RESET_DONE_CUSTOM,
|
|
+ HNAE3_FUNC_RESET_FAIL_CUSTOM,
|
|
+ HNAE3_GLOBAL_RESET_FAIL_CUSTOM,
|
|
+ HNAE3_IMP_RESET_FAIL_CUSTOM,
|
|
+ HNAE3_PPU_POISON_CUSTOM,
|
|
+ HNAE3_IMP_RD_POISON_CUSTOM,
|
|
+ HNAE3_INVALID_EVENT_CUSTOM
|
|
+};
|
|
+
|
|
+enum hnae3_ext_opcode {
|
|
+ HNAE3_EXT_OPC_RESET,
|
|
+ HNAE3_EXT_OPC_EVENT_CALLBACK,
|
|
+};
|
|
+#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
index 2ca9e369c4bc..72cc7f16aa7e 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
|
|
@@ -23,6 +23,7 @@
|
|
|
|
#include "kcompat.h"
|
|
#include "hnae3.h"
|
|
+#include "hnae3_ext.h"
|
|
#include "hns3_enet.h"
|
|
/* All hns3 tracepoints are defined by the include below, which
|
|
* must be included exactly once across the whole kernel with
|
|
@@ -5526,6 +5527,10 @@ static void hns3_process_hw_error(struct hnae3_handle *handle,
|
|
if (hns3_hw_err[i].type == type) {
|
|
dev_err(&handle->pdev->dev, "Detected %s!\n",
|
|
hns3_hw_err[i].msg);
|
|
+ if (handle->ae_algo->ops->priv_ops)
|
|
+ handle->ae_algo->ops->priv_ops(handle,
|
|
+ HNAE3_EXT_OPC_EVENT_CALLBACK, &type,
|
|
+ sizeof(type));
|
|
break;
|
|
}
|
|
}
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ext.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ext.c
|
|
new file mode 100644
|
|
index 000000000000..34aadd10feb8
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ext.c
|
|
@@ -0,0 +1,76 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+// Copyright (c) 2023 Hisilicon Limited.
|
|
+
|
|
+#include "hns3_ext.h"
|
|
+
|
|
+int nic_netdev_match_check(struct net_device *ndev)
|
|
+{
|
|
+#define HNS3_DRIVER_NAME_LEN 5
|
|
+
|
|
+ struct ethtool_drvinfo drv_info;
|
|
+ struct hnae3_handle *h;
|
|
+
|
|
+ if (!ndev || !ndev->ethtool_ops ||
|
|
+ !ndev->ethtool_ops->get_drvinfo)
|
|
+ return -EINVAL;
|
|
+
|
|
+ ndev->ethtool_ops->get_drvinfo(ndev, &drv_info);
|
|
+
|
|
+ if (strncmp(drv_info.driver, "hns3", HNS3_DRIVER_NAME_LEN))
|
|
+ return -EINVAL;
|
|
+
|
|
+ h = hns3_get_handle(ndev);
|
|
+ if (h->flags & HNAE3_SUPPORT_VF)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(nic_netdev_match_check);
|
|
+
|
|
+static int nic_invoke_pri_ops(struct net_device *ndev, int opcode,
|
|
+ void *data, size_t length)
|
|
+
|
|
+{
|
|
+ struct hnae3_handle *h;
|
|
+ int ret;
|
|
+
|
|
+ if ((!data && length) || (data && !length)) {
|
|
+ netdev_err(ndev, "failed to check data and length");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (nic_netdev_match_check(ndev))
|
|
+ return -ENODEV;
|
|
+
|
|
+ h = hns3_get_handle(ndev);
|
|
+ if (!h->ae_algo->ops->priv_ops)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ ret = h->ae_algo->ops->priv_ops(h, opcode, data, length);
|
|
+ if (ret)
|
|
+ netdev_err(ndev,
|
|
+ "failed to invoke pri ops, opcode = %#x, ret = %d\n",
|
|
+ opcode, ret);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void nic_chip_recover_handler(struct net_device *ndev,
|
|
+ enum hnae3_event_type_custom event_t)
|
|
+{
|
|
+ dev_info(&ndev->dev, "reset type is %d!!\n", event_t);
|
|
+
|
|
+ if (event_t == HNAE3_PPU_POISON_CUSTOM)
|
|
+ event_t = HNAE3_FUNC_RESET_CUSTOM;
|
|
+
|
|
+ if (event_t != HNAE3_FUNC_RESET_CUSTOM &&
|
|
+ event_t != HNAE3_GLOBAL_RESET_CUSTOM &&
|
|
+ event_t != HNAE3_IMP_RESET_CUSTOM) {
|
|
+ dev_err(&ndev->dev, "reset type err!!\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ nic_invoke_pri_ops(ndev, HNAE3_EXT_OPC_RESET,
|
|
+ &event_t, sizeof(event_t));
|
|
+}
|
|
+EXPORT_SYMBOL(nic_chip_recover_handler);
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ext.h b/drivers/net/ethernet/hisilicon/hns3/hns3_ext.h
|
|
new file mode 100644
|
|
index 000000000000..ce92a666db17
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ext.h
|
|
@@ -0,0 +1,13 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ */
|
|
+/* Copyright (c) 2023 Hisilicon Limited. */
|
|
+
|
|
+#ifndef __HNS3_EXT_H
|
|
+#define __HNS3_EXT_H
|
|
+#include <linux/types.h>
|
|
+#include "hns3_enet.h"
|
|
+#include "hnae3_ext.h"
|
|
+
|
|
+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);
|
|
+#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.c b/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.c
|
|
index 0118b9577a66..37b121632ddc 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.c
|
|
@@ -18,6 +18,7 @@
|
|
#include "hclge_main.h"
|
|
#include "hnae3.h"
|
|
#include "hclge_main_it.h"
|
|
+#include "hclge_ext.h"
|
|
#ifdef CONFIG_HNS3_TEST
|
|
#include "hclge_sysfs.h"
|
|
#endif
|
|
@@ -27,27 +28,6 @@
|
|
|
|
static nic_event_fn_t nic_event_call;
|
|
|
|
-int nic_register_event(nic_event_fn_t event_call)
|
|
-{
|
|
- if (!event_call) {
|
|
- pr_err("register event handle is null.\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- nic_event_call = event_call;
|
|
-
|
|
- pr_info("netdev register success.\n");
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL(nic_register_event);
|
|
-
|
|
-int nic_unregister_event(void)
|
|
-{
|
|
- nic_event_call = NULL;
|
|
- return 0;
|
|
-}
|
|
-EXPORT_SYMBOL(nic_unregister_event);
|
|
-
|
|
static void nic_call_event(struct net_device *netdev,
|
|
enum hnae3_event_type_custom event_t)
|
|
{
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.h b/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.h
|
|
index 343e036412d4..290c221f1807 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_extension/hns3pf/hclge_main_it.h
|
|
@@ -7,25 +7,6 @@
|
|
extern struct hnae3_ae_algo ae_algo;
|
|
extern struct hnae3_ae_ops hclge_ops;
|
|
|
|
-enum hnae3_event_type_custom {
|
|
- HNAE3_VF_RESET_CUSTOM,
|
|
- HNAE3_VF_FUNC_RESET_CUSTOM,
|
|
- HNAE3_VF_PF_FUNC_RESET_CUSTOM,
|
|
- HNAE3_VF_FULL_RESET_CUSTOM,
|
|
- HNAE3_FLR_RESET_CUSTOM,
|
|
- HNAE3_FUNC_RESET_CUSTOM,
|
|
- HNAE3_GLOBAL_RESET_CUSTOM,
|
|
- HNAE3_IMP_RESET_CUSTOM,
|
|
- HNAE3_UNKNOWN_RESET_CUSTOM,
|
|
- HNAE3_NONE_RESET_CUSTOM,
|
|
- HNAE3_PORT_FAULT,
|
|
- HNAE3_RESET_DONE_CUSTOM,
|
|
- HNAE3_FUNC_RESET_FAIL_CUSTOM,
|
|
- HNAE3_GLOBAL_RESET_FAIL_CUSTOM,
|
|
- HNAE3_IMP_RESET_FAIL_CUSTOM,
|
|
- HNAE3_PPU_POISON_CUSTOM,
|
|
- HNAE3_IMP_RD_POISON_CUSTOM,
|
|
-};
|
|
|
|
/**
|
|
* nic_event_fn_t - nic event handler prototype
|
|
@@ -35,18 +16,5 @@ enum hnae3_event_type_custom {
|
|
typedef void (*nic_event_fn_t) (struct net_device *netdev,
|
|
enum hnae3_event_type_custom);
|
|
|
|
-/**
|
|
- * nic_register_event - register for nic event handling
|
|
- * @event_call: nic event handler
|
|
- * return 0 - success , negative - fail
|
|
- */
|
|
-int nic_register_event(nic_event_fn_t event_call);
|
|
-
|
|
-/**
|
|
- * nic_unregister_event - quit nic event handling
|
|
- * return 0 - success , negative - fail
|
|
- */
|
|
-int nic_unregister_event(void);
|
|
-
|
|
int hclge_init(void);
|
|
#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.c
|
|
new file mode 100644
|
|
index 000000000000..52c7f5085cfb
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.c
|
|
@@ -0,0 +1,178 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+// Copyright (c) 2023 Hisilicon Limited.
|
|
+
|
|
+#include "hclge_main.h"
|
|
+#include "hnae3.h"
|
|
+#include "hnae3_ext.h"
|
|
+#include "hclge_cmd.h"
|
|
+#include "hclge_ext.h"
|
|
+
|
|
+#define HCLGE_RESET_MAX_FAIL_CNT 5
|
|
+
|
|
+static nic_event_fn_t nic_event_call;
|
|
+
|
|
+/* We use a lock to ensure that the address of the nic_event_call function
|
|
+ * is valid when it is called. Avoid null pointer exceptions caused by
|
|
+ * external unregister during invoking.
|
|
+ */
|
|
+static DEFINE_MUTEX(hclge_nic_event_lock);
|
|
+
|
|
+static int hclge_set_reset_task(struct hclge_dev *hdev, void *data,
|
|
+ size_t length)
|
|
+{
|
|
+ u32 *reset_level = (u32 *)data;
|
|
+
|
|
+ if (length != sizeof(u32))
|
|
+ return -EINVAL;
|
|
+
|
|
+ dev_warn(&hdev->pdev->dev, "reset level is %u\n", *reset_level);
|
|
+
|
|
+ /* request reset & schedule reset task */
|
|
+ set_bit(*reset_level, &hdev->reset_request);
|
|
+ hclge_reset_task_schedule(hdev);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int hclge_ext_call_event(struct hclge_dev *hdev,
|
|
+ enum hnae3_event_type_custom event_t)
|
|
+{
|
|
+ if (event_t >= HNAE3_INVALID_EVENT_CUSTOM)
|
|
+ return -EINVAL;
|
|
+
|
|
+ mutex_lock(&hclge_nic_event_lock);
|
|
+ if (!nic_event_call) {
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ nic_event_call(hdev->vport[0].nic.netdev, event_t);
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int nic_register_event(nic_event_fn_t event_call)
|
|
+{
|
|
+ if (!event_call) {
|
|
+ pr_err("hns3: register event handle is null\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ mutex_lock(&hclge_nic_event_lock);
|
|
+ if (nic_event_call) {
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+ pr_err("hns3: event already register\n");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ nic_event_call = event_call;
|
|
+
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+ pr_info("hns3: event register success\n");
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(nic_register_event);
|
|
+
|
|
+int nic_unregister_event(void)
|
|
+{
|
|
+ mutex_lock(&hclge_nic_event_lock);
|
|
+ nic_event_call = NULL;
|
|
+
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+ pr_info("hns3: event unregister success\n");
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(nic_unregister_event);
|
|
+
|
|
+static int hclge_nic_call_event(struct hclge_dev *hdev, void *data,
|
|
+ size_t length)
|
|
+{
|
|
+#define ERROR_EVENT_TYPE_NUM 3
|
|
+
|
|
+ u32 event_type[ERROR_EVENT_TYPE_NUM] = {
|
|
+ HNAE3_PPU_POISON_CUSTOM,
|
|
+ HNAE3_IMP_RESET_CUSTOM,
|
|
+ HNAE3_IMP_RD_POISON_CUSTOM
|
|
+ };
|
|
+ u32 *index = (u32 *)data;
|
|
+
|
|
+ if (length != sizeof(u32))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if ((*index) >= ERROR_EVENT_TYPE_NUM)
|
|
+ return 0;
|
|
+
|
|
+ return hclge_ext_call_event(hdev, event_type[*index]);
|
|
+}
|
|
+
|
|
+static enum hnae3_event_type_custom
|
|
+hclge_get_reset_fail_type(enum hnae3_reset_type reset_type)
|
|
+{
|
|
+ const struct hclge_reset_fail_type_map fail_type_map[] = {
|
|
+ {HNAE3_FUNC_RESET, HNAE3_FUNC_RESET_FAIL_CUSTOM},
|
|
+ {HNAE3_GLOBAL_RESET, HNAE3_GLOBAL_RESET_FAIL_CUSTOM},
|
|
+ {HNAE3_IMP_RESET, HNAE3_IMP_RESET_FAIL_CUSTOM},
|
|
+ };
|
|
+ u32 i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(fail_type_map); i++)
|
|
+ if (fail_type_map[i].reset_type == reset_type)
|
|
+ return fail_type_map[i].custom_type;
|
|
+
|
|
+ return HNAE3_INVALID_EVENT_CUSTOM;
|
|
+}
|
|
+
|
|
+static void hclge_report_reset_fail_custom(struct hclge_dev *hdev)
|
|
+{
|
|
+#define HCLGE_RESET_MAX_FAIL_CNT_CUSTOM 1
|
|
+
|
|
+ u32 max_fail_custom_cnt = HCLGE_RESET_MAX_FAIL_CNT;
|
|
+
|
|
+ mutex_lock(&hclge_nic_event_lock);
|
|
+ if (nic_event_call)
|
|
+ max_fail_custom_cnt = HCLGE_RESET_MAX_FAIL_CNT_CUSTOM;
|
|
+ mutex_unlock(&hclge_nic_event_lock);
|
|
+
|
|
+ if (hdev->rst_stats.reset_fail_cnt < max_fail_custom_cnt)
|
|
+ return;
|
|
+
|
|
+ dev_err(&hdev->pdev->dev, "failed to report reset!\n");
|
|
+ hclge_ext_call_event(hdev, hclge_get_reset_fail_type(hdev->reset_type));
|
|
+}
|
|
+
|
|
+void hclge_ext_reset_end(struct hclge_dev *hdev, bool done)
|
|
+{
|
|
+ if (!done) {
|
|
+ hclge_report_reset_fail_custom(hdev);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ hclge_ext_call_event(hdev, HNAE3_RESET_DONE_CUSTOM);
|
|
+ dev_info(&hdev->pdev->dev, "report reset done!\n");
|
|
+}
|
|
+
|
|
+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,
|
|
+};
|
|
+
|
|
+int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
|
|
+ void *data, size_t length)
|
|
+{
|
|
+ struct hclge_vport *vport = hclge_get_vport(handle);
|
|
+ int cmd_num = ARRAY_SIZE(hclge_ext_func_arr);
|
|
+ struct hclge_dev *hdev = vport->back;
|
|
+ hclge_priv_ops_fn ext_opcode_func;
|
|
+
|
|
+ if (opcode >= cmd_num) {
|
|
+ dev_err(&hdev->pdev->dev, "invalid opcode %d\n", opcode);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ext_opcode_func = hclge_ext_func_arr[opcode];
|
|
+ if (!ext_opcode_func) {
|
|
+ dev_err(&hdev->pdev->dev, "unsupported opcode %d\n", opcode);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ return ext_opcode_func(hdev, data, length);
|
|
+}
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.h
|
|
new file mode 100644
|
|
index 000000000000..1c1b04765e7e
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_ext.h
|
|
@@ -0,0 +1,43 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ */
|
|
+/* Copyright (c) 2016-2017 Hisilicon Limited. */
|
|
+
|
|
+#ifndef __HCLGE_EXT_H
|
|
+#define __HCLGE_EXT_H
|
|
+#include <linux/types.h>
|
|
+
|
|
+struct hclge_reset_fail_type_map {
|
|
+ enum hnae3_reset_type reset_type;
|
|
+ enum hnae3_event_type_custom custom_type;
|
|
+};
|
|
+
|
|
+typedef int (*hclge_priv_ops_fn)(struct hclge_dev *hdev, void *data,
|
|
+ size_t length);
|
|
+
|
|
+/**
|
|
+ * nic_event_fn_t - nic event handler prototype
|
|
+ * @netdev: net device
|
|
+ * @hnae3_event_type_custom: nic device event type
|
|
+ */
|
|
+typedef void (*nic_event_fn_t) (struct net_device *netdev,
|
|
+ enum hnae3_event_type_custom);
|
|
+
|
|
+/**
|
|
+ * nic_register_event - register for nic event handling
|
|
+ * @event_call: nic event handler
|
|
+ * return 0 - success , negative - fail
|
|
+ */
|
|
+int nic_register_event(nic_event_fn_t event_call);
|
|
+
|
|
+/**
|
|
+ * nic_unregister_event - unregister for nic event handling
|
|
+ * return 0 - success , negative - fail
|
|
+ */
|
|
+int nic_unregister_event(void);
|
|
+
|
|
+int hclge_ext_call_event(struct hclge_dev *hdev,
|
|
+ enum hnae3_event_type_custom event_t);
|
|
+void hclge_ext_reset_end(struct hclge_dev *hdev, bool done);
|
|
+
|
|
+int hclge_ext_ops_handle(struct hnae3_handle *handle, int opcode,
|
|
+ void *data, size_t length);
|
|
+#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
index bbc63c47d0df..3779181b8f59 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
|
|
@@ -18,6 +18,7 @@
|
|
#include "kcompat.h"
|
|
#include "hclge_cmd.h"
|
|
#include "hclge_dcb.h"
|
|
+#include "hclge_ext.h"
|
|
#include "hclge_main.h"
|
|
#include "hclge_mbx.h"
|
|
#include "hclge_mdio.h"
|
|
@@ -34,7 +35,6 @@
|
|
#define BUF_MAX_PERCENT 100
|
|
#define BUF_RESERVE_PERCENT 90
|
|
|
|
-#define HCLGE_RESET_MAX_FAIL_CNT 5
|
|
#define HCLGE_RESET_SYNC_TIME 100
|
|
#define HCLGE_PF_RESET_SYNC_TIME 20
|
|
#define HCLGE_PF_RESET_SYNC_CNT 1500
|
|
@@ -55,6 +55,8 @@
|
|
|
|
#define HCLGE_LINK_STATUS_MS 10
|
|
|
|
+#define HCLGE_RESET_MAX_FAIL_CNT 5
|
|
+
|
|
static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps);
|
|
static int hclge_init_vlan_config(struct hclge_dev *hdev);
|
|
static void hclge_sync_vlan_filter(struct hclge_dev *hdev);
|
|
@@ -67,6 +69,7 @@ static int hclge_set_default_loopback(struct hclge_dev *hdev);
|
|
static void hclge_sync_mac_table(struct hclge_dev *hdev);
|
|
static void hclge_restore_hw_table(struct hclge_dev *hdev);
|
|
static void hclge_sync_promisc_mode(struct hclge_dev *hdev);
|
|
+static void hclge_reset_end(struct hnae3_handle *handle, bool done);
|
|
|
|
static struct hnae3_ae_algo ae_algo;
|
|
|
|
@@ -2916,7 +2919,7 @@ static void hclge_mbx_task_schedule(struct hclge_dev *hdev)
|
|
}
|
|
}
|
|
|
|
-static void hclge_reset_task_schedule(struct hclge_dev *hdev)
|
|
+void hclge_reset_task_schedule(struct hclge_dev *hdev)
|
|
{
|
|
if (!test_bit(HCLGE_STATE_REMOVING, &hdev->state) &&
|
|
test_bit(HCLGE_STATE_SERVICE_INITED, &hdev->state) &&
|
|
@@ -3399,7 +3402,7 @@ static int hclge_get_status(struct hnae3_handle *handle)
|
|
return hdev->hw.mac.link;
|
|
}
|
|
|
|
-static struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf)
|
|
+struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf)
|
|
{
|
|
if (!pci_num_vf(hdev->pdev)) {
|
|
dev_err(&hdev->pdev->dev,
|
|
@@ -4142,8 +4145,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev)
|
|
/* recover the handshake status when reset fail */
|
|
hclge_reset_handshake(hdev, true);
|
|
|
|
- if (handle && handle->ae_algo->ops->reset_end)
|
|
- handle->ae_algo->ops->reset_end(handle, false);
|
|
+ hclge_reset_end(handle, false);
|
|
|
|
hclge_show_rst_info(hdev);
|
|
|
|
@@ -4262,6 +4264,7 @@ static int hclge_reset_prepare(struct hclge_dev *hdev)
|
|
|
|
static int hclge_reset_rebuild(struct hclge_dev *hdev)
|
|
{
|
|
+ struct hnae3_handle *handle = &hdev->vport[0].nic;
|
|
int ret;
|
|
|
|
hdev->rst_stats.hw_reset_done_cnt++;
|
|
@@ -4307,6 +4310,8 @@ static int hclge_reset_rebuild(struct hclge_dev *hdev)
|
|
|
|
hclge_update_reset_level(hdev);
|
|
|
|
+ hclge_reset_end(handle, true);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -4328,10 +4333,11 @@ static void hclge_reset(struct hclge_dev *hdev)
|
|
hclge_reset_task_schedule(hdev);
|
|
}
|
|
|
|
-static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle)
|
|
+void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle)
|
|
{
|
|
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(pdev);
|
|
struct hclge_dev *hdev = ae_dev->priv;
|
|
+ int ret;
|
|
|
|
/* We might end up getting called broadly because of 2 below cases:
|
|
* 1. Recoverable error was conveyed through APEI and only way to bring
|
|
@@ -4366,9 +4372,12 @@ static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle)
|
|
dev_info(&hdev->pdev->dev, "received reset event, reset type is %d\n",
|
|
hdev->reset_level);
|
|
|
|
- /* request reset & schedule reset task */
|
|
- set_bit(hdev->reset_level, &hdev->reset_request);
|
|
- hclge_reset_task_schedule(hdev);
|
|
+ ret = hclge_ext_call_event(hdev, hdev->reset_level);
|
|
+ if (ret) {
|
|
+ /* request reset & schedule reset task */
|
|
+ set_bit(hdev->reset_level, &hdev->reset_request);
|
|
+ hclge_reset_task_schedule(hdev);
|
|
+ }
|
|
|
|
if (hdev->reset_level < HNAE3_GLOBAL_RESET)
|
|
hdev->reset_level++;
|
|
@@ -4385,7 +4394,6 @@ static void hclge_set_def_reset_request(struct hnae3_ae_dev *ae_dev,
|
|
static void hclge_reset_timer(struct timer_list *t)
|
|
{
|
|
struct hclge_dev *hdev = from_timer(hdev, t, reset_timer);
|
|
- struct hnae3_ae_dev *ae_dev = pci_get_drvdata(hdev->pdev);
|
|
|
|
/* if default_reset_request has no value, it means that this reset
|
|
* request has already be handled, so just return here
|
|
@@ -4395,20 +4403,15 @@ static void hclge_reset_timer(struct timer_list *t)
|
|
|
|
dev_info(&hdev->pdev->dev,
|
|
"triggering reset in reset timer\n");
|
|
-
|
|
- if (ae_dev->ops->reset_event)
|
|
- ae_dev->ops->reset_event(hdev->pdev, NULL);
|
|
+ hclge_reset_event(hdev->pdev, &hdev->vport[0].nic);
|
|
}
|
|
|
|
-static bool hclge_reset_end(struct hnae3_handle *handle, bool done)
|
|
+static void hclge_reset_end(struct hnae3_handle *handle, bool done)
|
|
{
|
|
struct hclge_vport *vport = hclge_get_vport(handle);
|
|
struct hclge_dev *hdev = vport->back;
|
|
|
|
- if (hdev->rst_stats.reset_fail_cnt >= HCLGE_RESET_MAX_FAIL_CNT)
|
|
- dev_err(&hdev->pdev->dev, "Reset fail!\n");
|
|
-
|
|
- return done;
|
|
+ hclge_ext_reset_end(hdev, done);
|
|
}
|
|
|
|
static void hclge_reset_subtask(struct hclge_dev *hdev)
|
|
@@ -4448,8 +4451,8 @@ static void hclge_handle_err_reset_request(struct hclge_dev *hdev)
|
|
hclge_set_def_reset_request(ae_dev, reset_type);
|
|
}
|
|
|
|
- if (hdev->default_reset_request && ae_dev->ops->reset_event)
|
|
- ae_dev->ops->reset_event(hdev->pdev, NULL);
|
|
+ if (hdev->default_reset_request)
|
|
+ hclge_reset_event(hdev->pdev, &hdev->vport[0].nic);
|
|
|
|
/* enable interrupt after error handling complete */
|
|
hclge_enable_vector(&hdev->misc_vector, true);
|
|
@@ -12836,7 +12839,6 @@ struct hnae3_ae_ops hclge_ops = {
|
|
.set_timer_task = hclge_set_timer_task,
|
|
.mac_connect_phy = hclge_mac_connect_phy,
|
|
.mac_disconnect_phy = hclge_mac_disconnect_phy,
|
|
- .reset_end = hclge_reset_end,
|
|
.get_vf_config = hclge_get_vf_config,
|
|
.set_vf_link_state = hclge_set_vf_link_state,
|
|
.set_vf_spoofchk = hclge_set_vf_spoofchk,
|
|
@@ -12853,6 +12855,7 @@ struct hnae3_ae_ops hclge_ops = {
|
|
.get_link_diagnosis_info = hclge_get_link_diagnosis_info,
|
|
.get_wol = hclge_get_wol,
|
|
.set_wol = hclge_set_wol,
|
|
+ .priv_ops = hclge_ext_ops_handle,
|
|
};
|
|
|
|
static struct hnae3_ae_algo ae_algo = {
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
|
|
index 9d739033daab..f32c8b52f022 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
|
|
@@ -11,7 +11,7 @@
|
|
|
|
#include "hclge_cmd.h"
|
|
#include "hclge_ptp.h"
|
|
-#include "hnae3.h"
|
|
+#include "hnae3_ext.h"
|
|
|
|
#define HCLGE_MOD_VERSION "24.3.1"
|
|
#define HCLGE_DRIVER_NAME "hclge"
|
|
@@ -1168,4 +1168,7 @@ void hclge_unregister_sysfs(struct hclge_dev *hdev);
|
|
int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed, u8 duplex);
|
|
int hclge_get_wol_supported_mode(struct hclge_dev *hdev, u32 *wol_supported);
|
|
int hclge_get_wol_cfg(struct hclge_dev *hdev, u32 *mode);
|
|
+struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf);
|
|
+void hclge_reset_task_schedule(struct hclge_dev *hdev);
|
|
+void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle);
|
|
#endif
|
|
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
|
|
index 305f11c854bf..4c270073c607 100644
|
|
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
|
|
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
|
|
@@ -802,7 +802,7 @@ static void hclge_handle_ncsi_error(struct hclge_dev *hdev)
|
|
|
|
ae_dev->ops->set_default_reset_request(ae_dev, HNAE3_GLOBAL_RESET);
|
|
dev_warn(&hdev->pdev->dev, "requesting reset due to NCSI error\n");
|
|
- ae_dev->ops->reset_event(hdev->pdev, NULL);
|
|
+ hclge_reset_event(hdev->pdev, &hdev->vport[0].nic);
|
|
}
|
|
|
|
static void hclge_handle_vf_tbl(struct hclge_vport *vport,
|
|
--
|
|
2.34.1
|
|
|