diff mbox series

[v1,07/16] net-next/yunsilicon: Device and interface management

Message ID 20241218105037.2237645-8-tianx@yunsilicon.com (mailing list archive)
State New
Delegated to: Netdev Maintainers
Headers show
Series net-next/yunsilicon: ADD Yunsilicon XSC Ethernet Driver | expand

Checks

Context Check Description
netdev/series_format fail Series longer than 15 patches
netdev/tree_selection success Guessed tree name to be net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 6 of 6 maintainers
netdev/build_clang fail Errors and warnings before: 39 this patch: 40
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 439 this patch: 493
netdev/checkpatch warning WARNING: Co-developed-by and Signed-off-by: name/email do not match WARNING: Co-developed-by: must be immediately followed by Signed-off-by: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: line length of 88 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

tianx Dec. 18, 2024, 10:50 a.m. UTC
The xsc device supports both Ethernet and RDMA interfaces.
This patch provides a set of APIs to implement the registration
of new interfaces and handle the interfaces during device
attach/detach or add/remove events.

 
Co-developed-by: Honggang Wei <weihg@yunsilicon.com>
Co-developed-by: Lei Yan <Jacky@yunsilicon.com>
Signed-off-by: Xin Tian <tianx@yunsilicon.com>
---
 .../ethernet/yunsilicon/xsc/common/xsc_core.h |  59 +++-
 .../net/ethernet/yunsilicon/xsc/pci/Makefile  |   3 +-
 .../net/ethernet/yunsilicon/xsc/pci/intf.c    | 279 ++++++++++++++++++
 .../net/ethernet/yunsilicon/xsc/pci/intf.h    |  22 ++
 .../net/ethernet/yunsilicon/xsc/pci/main.c    |  16 +
 5 files changed, 373 insertions(+), 6 deletions(-)
 create mode 100644 drivers/net/ethernet/yunsilicon/xsc/pci/intf.c
 create mode 100644 drivers/net/ethernet/yunsilicon/xsc/pci/intf.h
diff mbox series

Patch

diff --git a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
index 3541be638..fc2d3d01b 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
+++ b/drivers/net/ethernet/yunsilicon/xsc/common/xsc_core.h
@@ -294,11 +294,60 @@  struct xsc_eq_table {
 	spinlock_t		lock;
 };
 
+// irq
 struct xsc_irq_info {
 	cpumask_var_t mask;
 	char name[XSC_MAX_IRQ_NAME];
 };
 
+// intf
+enum xsc_dev_event {
+	XSC_DEV_EVENT_SYS_ERROR,
+	XSC_DEV_EVENT_PORT_UP,
+	XSC_DEV_EVENT_PORT_DOWN,
+	XSC_DEV_EVENT_PORT_INITIALIZED,
+	XSC_DEV_EVENT_LID_CHANGE,
+	XSC_DEV_EVENT_PKEY_CHANGE,
+	XSC_DEV_EVENT_GUID_CHANGE,
+	XSC_DEV_EVENT_CLIENT_REREG,
+};
+
+enum {
+	XSC_INTERFACE_ADDED,
+	XSC_INTERFACE_ATTACHED,
+};
+
+enum xsc_interface_state {
+	XSC_INTERFACE_STATE_UP = BIT(0),
+	XSC_INTERFACE_STATE_TEARDOWN = BIT(1),
+};
+
+enum {
+	XSC_INTERFACE_PROTOCOL_IB  = 0,
+	XSC_INTERFACE_PROTOCOL_ETH = 1,
+};
+
+struct xsc_interface {
+	struct list_head list;
+	int protocol;
+
+	void *(*add)(struct xsc_core_device *xdev);
+	void (*remove)(struct xsc_core_device *xdev, void *context);
+	int (*attach)(struct xsc_core_device *xdev, void *context);
+	void (*detach)(struct xsc_core_device *xdev, void *context);
+	void (*event)(struct xsc_core_device *xdev, void *context,
+		      enum xsc_dev_event event, unsigned long param);
+	void *(*get_dev)(void *context);
+};
+
+struct xsc_device_context {
+	struct list_head list;
+	struct xsc_interface *intf;
+	void *context;
+	unsigned long state;
+};
+
+// xsc_core
 struct xsc_dev_resource {
 	struct xsc_qp_table	qp_table;
 	struct xsc_cq_table	cq_table;
@@ -436,11 +485,6 @@  enum xsc_pci_state {
 	XSC_PCI_STATE_ENABLED,
 };
 
-enum xsc_interface_state {
-	XSC_INTERFACE_STATE_UP = BIT(0),
-	XSC_INTERFACE_STATE_TEARDOWN = BIT(1),
-};
-
 struct xsc_priv {
 	char			name[XSC_MAX_NAME_LEN];
 	struct list_head	dev_list;
@@ -456,6 +500,8 @@  struct xsc_core_device {
 	void			*eth_priv;
 	struct xsc_dev_resource	*dev_res;
 
+	void (*event)(struct xsc_core_device *xdev,
+		      enum xsc_dev_event event, unsigned long param);
 	void (*event_handler)(void *adapter);
 
 	void __iomem		*bar;
@@ -500,6 +546,9 @@  struct xsc_eq *xsc_core_eq_get(struct xsc_core_device *xdev, int i);
 int xsc_core_vector2eqn(struct xsc_core_device *xdev, int vector, int *eqn,
 			unsigned int *irqn);
 
+int xsc_register_interface(struct xsc_interface *intf);
+void xsc_unregister_interface(struct xsc_interface *intf);
+
 static inline void *xsc_buf_offset(struct xsc_buf *buf, int offset)
 {
 	if (likely(BITS_PER_LONG == 64 || buf->nbufs == 1))
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
index 3525d1c74..0f4b17dfa 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/Makefile
@@ -6,4 +6,5 @@  ccflags-y += -I$(srctree)/drivers/net/ethernet/yunsilicon/xsc
 
 obj-$(CONFIG_YUNSILICON_XSC_PCI) += xsc_pci.o
 
-xsc_pci-y := main.o cmdq.o hw.o qp.o cq.o alloc.o eq.o pci_irq.o
+xsc_pci-y := main.o cmdq.o hw.o qp.o cq.o alloc.o eq.o pci_irq.o intf.o
+
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/intf.c b/drivers/net/ethernet/yunsilicon/xsc/pci/intf.c
new file mode 100644
index 000000000..485751b23
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/intf.c
@@ -0,0 +1,279 @@ 
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (C) 2021-2024, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "common/xsc_core.h"
+#include "intf.h"
+
+LIST_HEAD(intf_list);
+LIST_HEAD(xsc_dev_list);
+DEFINE_MUTEX(xsc_intf_mutex); // protect intf_list and xsc_dev_list
+
+static void xsc_add_device(struct xsc_interface *intf, struct xsc_priv *priv)
+{
+	struct xsc_device_context *dev_ctx;
+	struct xsc_core_device *xdev;
+
+	xdev = container_of(priv, struct xsc_core_device, priv);
+	dev_ctx = kzalloc(sizeof(*dev_ctx), GFP_KERNEL);
+	if (!dev_ctx)
+		return;
+
+	dev_ctx->intf = intf;
+
+	dev_ctx->context = intf->add(xdev);
+	if (dev_ctx->context) {
+		set_bit(XSC_INTERFACE_ADDED, &dev_ctx->state);
+		if (intf->attach)
+			set_bit(XSC_INTERFACE_ATTACHED, &dev_ctx->state);
+
+		spin_lock_irq(&priv->ctx_lock);
+		list_add_tail(&dev_ctx->list, &priv->ctx_list);
+		spin_unlock_irq(&priv->ctx_lock);
+	} else {
+		kfree(dev_ctx);
+	}
+}
+
+static struct xsc_device_context *xsc_get_device(struct xsc_interface *intf,
+						 struct xsc_priv *priv)
+{
+	struct xsc_device_context *dev_ctx;
+
+	/* caller of this function has mutex protection */
+	list_for_each_entry(dev_ctx, &priv->ctx_list, list)
+		if (dev_ctx->intf == intf)
+			return dev_ctx;
+
+	return NULL;
+}
+
+static void xsc_remove_device(struct xsc_interface *intf, struct xsc_priv *priv)
+{
+	struct xsc_core_device *xdev = container_of(priv, struct xsc_core_device, priv);
+	struct xsc_device_context *dev_ctx;
+
+	dev_ctx = xsc_get_device(intf, priv);
+	if (!dev_ctx)
+		return;
+
+	spin_lock_irq(&priv->ctx_lock);
+	list_del(&dev_ctx->list);
+	spin_unlock_irq(&priv->ctx_lock);
+
+	if (test_bit(XSC_INTERFACE_ADDED, &dev_ctx->state))
+		intf->remove(xdev, dev_ctx->context);
+
+	kfree(dev_ctx);
+}
+
+int xsc_register_interface(struct xsc_interface *intf)
+{
+	struct xsc_priv *priv;
+
+	if (!intf->add || !intf->remove)
+		return -EINVAL;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_add_tail(&intf->list, &intf_list);
+	list_for_each_entry(priv, &xsc_dev_list, dev_list) {
+		xsc_add_device(intf, priv);
+	}
+	mutex_unlock(&xsc_intf_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(xsc_register_interface);
+
+void xsc_unregister_interface(struct xsc_interface *intf)
+{
+	struct xsc_priv *priv;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_for_each_entry(priv, &xsc_dev_list, dev_list)
+		xsc_remove_device(intf, priv);
+	list_del(&intf->list);
+	mutex_unlock(&xsc_intf_mutex);
+}
+EXPORT_SYMBOL(xsc_unregister_interface);
+
+static void xsc_attach_interface(struct xsc_interface *intf,
+				 struct xsc_priv *priv)
+{
+	struct xsc_core_device *xdev = container_of(priv, struct xsc_core_device, priv);
+	struct xsc_device_context *dev_ctx;
+
+	dev_ctx = xsc_get_device(intf, priv);
+	if (!dev_ctx)
+		return;
+
+	if (intf->attach) {
+		if (test_bit(XSC_INTERFACE_ATTACHED, &dev_ctx->state))
+			return;
+		if (intf->attach(xdev, dev_ctx->context))
+			return;
+		set_bit(XSC_INTERFACE_ATTACHED, &dev_ctx->state);
+	} else {
+		if (test_bit(XSC_INTERFACE_ADDED, &dev_ctx->state))
+			return;
+		dev_ctx->context = intf->add(xdev);
+		if (!dev_ctx->context)
+			return;
+		set_bit(XSC_INTERFACE_ADDED, &dev_ctx->state);
+	}
+}
+
+static void xsc_detach_interface(struct xsc_interface *intf,
+				 struct xsc_priv *priv)
+{
+	struct xsc_core_device *xdev = container_of(priv, struct xsc_core_device, priv);
+	struct xsc_device_context *dev_ctx;
+
+	dev_ctx = xsc_get_device(intf, priv);
+	if (!dev_ctx)
+		return;
+
+	if (intf->detach) {
+		if (!test_bit(XSC_INTERFACE_ATTACHED, &dev_ctx->state))
+			return;
+		intf->detach(xdev, dev_ctx->context);
+		clear_bit(XSC_INTERFACE_ATTACHED, &dev_ctx->state);
+	} else {
+		if (!test_bit(XSC_INTERFACE_ADDED, &dev_ctx->state))
+			return;
+		intf->remove(xdev, dev_ctx->context);
+		clear_bit(XSC_INTERFACE_ADDED, &dev_ctx->state);
+	}
+}
+
+void xsc_attach_device(struct xsc_core_device *xdev)
+{
+	struct xsc_priv *priv = &xdev->priv;
+	struct xsc_interface *intf;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_for_each_entry(intf, &intf_list, list) {
+		xsc_attach_interface(intf, priv);
+	}
+	mutex_unlock(&xsc_intf_mutex);
+}
+
+void xsc_detach_device(struct xsc_core_device *xdev)
+{
+	struct xsc_priv *priv = &xdev->priv;
+	struct xsc_interface *intf;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_for_each_entry(intf, &intf_list, list)
+		xsc_detach_interface(intf, priv);
+	mutex_unlock(&xsc_intf_mutex);
+}
+
+bool xsc_device_registered(struct xsc_core_device *xdev)
+{
+	struct xsc_priv *priv;
+	bool found = false;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_for_each_entry(priv, &xsc_dev_list, dev_list)
+		if (priv == &xdev->priv)
+			found = true;
+	mutex_unlock(&xsc_intf_mutex);
+
+	return found;
+}
+
+int xsc_register_device(struct xsc_core_device *xdev)
+{
+	struct xsc_priv *priv = &xdev->priv;
+	struct xsc_interface *intf;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_add_tail(&priv->dev_list, &xsc_dev_list);
+	list_for_each_entry(intf, &intf_list, list)
+		xsc_add_device(intf, priv);
+	mutex_unlock(&xsc_intf_mutex);
+
+	return 0;
+}
+
+void xsc_unregister_device(struct xsc_core_device *xdev)
+{
+	struct xsc_priv *priv = &xdev->priv;
+	struct xsc_interface *intf;
+
+	mutex_lock(&xsc_intf_mutex);
+	list_for_each_entry_reverse(intf, &intf_list, list)
+		xsc_remove_device(intf, priv);
+	list_del(&priv->dev_list);
+	mutex_unlock(&xsc_intf_mutex);
+}
+
+void xsc_add_dev_by_protocol(struct xsc_core_device *xdev, int protocol)
+{
+	struct xsc_interface *intf;
+
+	list_for_each_entry(intf, &intf_list, list)
+		if (intf->protocol == protocol) {
+			xsc_add_device(intf, &xdev->priv);
+			break;
+		}
+}
+
+void xsc_remove_dev_by_protocol(struct xsc_core_device *xdev, int protocol)
+{
+	struct xsc_interface *intf;
+
+	list_for_each_entry(intf, &intf_list, list)
+		if (intf->protocol == protocol) {
+			xsc_remove_device(intf, &xdev->priv);
+			break;
+		}
+}
+
+void xsc_dev_list_lock(void)
+{
+	mutex_lock(&xsc_intf_mutex);
+}
+
+void xsc_dev_list_unlock(void)
+{
+	mutex_unlock(&xsc_intf_mutex);
+}
+
+int xsc_dev_list_trylock(void)
+{
+	return mutex_trylock(&xsc_intf_mutex);
+}
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/intf.h b/drivers/net/ethernet/yunsilicon/xsc/pci/intf.h
new file mode 100644
index 000000000..acb9f4526
--- /dev/null
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/intf.h
@@ -0,0 +1,22 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2021-2025, Shanghai Yunsilicon Technology Co., Ltd.
+ * All rights reserved.
+ */
+
+#ifndef INTF_H
+#define INTF_H
+
+#include "common/xsc_core.h"
+
+void xsc_attach_device(struct xsc_core_device *xdev);
+void xsc_detach_device(struct xsc_core_device *xdev);
+bool xsc_device_registered(struct xsc_core_device *xdev);
+int xsc_register_device(struct xsc_core_device *xdev);
+void xsc_unregister_device(struct xsc_core_device *xdev);
+void xsc_add_dev_by_protocol(struct xsc_core_device *xdev, int protocol);
+void xsc_remove_dev_by_protocol(struct xsc_core_device *xdev, int protocol);
+void xsc_dev_list_lock(void);
+void xsc_dev_list_unlock(void);
+int xsc_dev_list_trylock(void);
+
+#endif
diff --git a/drivers/net/ethernet/yunsilicon/xsc/pci/main.c b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
index ea9bda0e6..27ce9ee90 100644
--- a/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
+++ b/drivers/net/ethernet/yunsilicon/xsc/pci/main.c
@@ -10,6 +10,7 @@ 
 #include "cq.h"
 #include "eq.h"
 #include "pci_irq.h"
+#include "intf.h"
 
 unsigned int xsc_debug_mask;
 module_param_named(debug_mask, xsc_debug_mask, uint, 0644);
@@ -289,10 +290,22 @@  static int xsc_load(struct xsc_core_device *xdev)
 		goto err_irq_eq_create;
 	}
 
+	if (xsc_device_registered(xdev)) {
+		xsc_attach_device(xdev);
+	} else {
+		err = xsc_register_device(xdev);
+		if (err) {
+			xsc_core_err(xdev, "register device failed %d\n", err);
+			goto err_reg_dev;
+		}
+	}
+
 	set_bit(XSC_INTERFACE_STATE_UP, &xdev->intf_state);
 	mutex_unlock(&xdev->intf_state_mutex);
 
 	return 0;
+err_reg_dev:
+	xsc_irq_eq_destroy(xdev);
 err_irq_eq_create:
 	xsc_hw_cleanup(xdev);
 out:
@@ -302,6 +315,7 @@  static int xsc_load(struct xsc_core_device *xdev)
 
 static int xsc_unload(struct xsc_core_device *xdev)
 {
+	xsc_unregister_device(xdev);
 	mutex_lock(&xdev->intf_state_mutex);
 	if (!test_bit(XSC_INTERFACE_STATE_UP, &xdev->intf_state)) {
 		xsc_core_warn(xdev, "%s: interface is down, NOP\n",
@@ -311,6 +325,8 @@  static int xsc_unload(struct xsc_core_device *xdev)
 	}
 
 	clear_bit(XSC_INTERFACE_STATE_UP, &xdev->intf_state);
+	if (xsc_device_registered(xdev))
+		xsc_detach_device(xdev);
 	xsc_irq_eq_destroy(xdev);
 	xsc_hw_cleanup(xdev);