[RFC net-next 1/7] net/ism: Create net/ism

Alexandra Winter
2025-01-15T19:55:44Z

Create an 'ISM' shim layer that will provide generic functionality and
declarations for ism device drivers and ism clients.

Move the respective pieces from drivers/s390/net/ism_drv.* to net/ism/

When we need to distinguish between generic ism interfaces and
specifically the s390 virtual pci ism device, it will be called 'ISM_vPCI'.

No optimizations are done in this patch, it only moves pieces around.
Following patch will further detangle ism_vpci and smc-d.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
MAINTAINERS | 7 ++
drivers/s390/net/Kconfig | 9 +--
drivers/s390/net/Makefile | 4 +-
drivers/s390/net/ism_drv.c | 129 ++---------------------------
include/linux/ism.h | 8 ++
include/net/smc.h | 3 -
net/Kconfig | 1 +
net/Makefile | 1 +
net/ism/Kconfig | 14 ++++
net/ism/Makefile | 7 ++
net/ism/ism_main.c | 162 +++++++++++++++++++++++++++++++++++++
11 files changed, 213 insertions(+), 132 deletions(-)
create mode 100644 net/ism/Kconfig
create mode 100644 net/ism/Makefile
create mode 100644 net/ism/ism_main.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 4dcb849e6748..780db61f3f16 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12239,6 +12239,13 @@ F: Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml
F: Documentation/hwmon/isl28022.rst
F: drivers/hwmon/isl28022.c

+ISM (INTERNAL SHARED MEMORY)
+M: Alexandra Winter <wintera@linux.ibm.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: include/linux/ism.h
+F: net/ism/
+
ISOFS FILESYSTEM
M: Jan Kara <jack@suse.cz>
L: linux-fsdevel@vger.kernel.org
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index c61e6427384c..2e900d3087d4 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -100,15 +100,14 @@ config CCWGROUP
tristate
default (LCS || CTCM || QETH || SMC)

-config ISM
+config ISM_VPCI
tristate "Support for ISM vPCI Adapter"
- depends on PCI
+ depends on PCI && ISM
imply SMC
- default n
+ default y
help
Select this option if you want to use the Internal Shared Memory
vPCI Adapter. The adapter can be used with the SMC network protocol.

- To compile as a module choose M. The module name is ism.
- If unsure, choose N.
+ To compile as a module choose M. The module name is ism_vpci.
endmenu
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index bc55ec316adb..87461019184e 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -16,5 +16,5 @@ obj-$(CONFIG_QETH_L2) += qeth_l2.o
qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o
obj-$(CONFIG_QETH_L3) += qeth_l3.o

-ism-y := ism_drv.o
-obj-$(CONFIG_ISM) += ism.o
+ism_vpci-y += ism_drv.o
+obj-$(CONFIG_ISM_VPCI) += ism_vpci.o
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index e36e3ea165d3..2eeccf5ef48d 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -4,7 +4,7 @@
*
* Copyright IBM Corp. 2018
*/
-#define KMSG_COMPONENT "ism"
+#define KMSG_COMPONENT "ism-vpci"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/module.h>
@@ -31,100 +31,7 @@ MODULE_DEVICE_TABLE(pci, ism_device_table);

static debug_info_t *ism_debug_info;

-#define NO_CLIENT 0xff /* must be >= MAX_CLIENTS */
-static struct ism_client *clients[MAX_CLIENTS]; /* use an array rather than */
- /* a list for fast mapping */
-static u8 max_client;
-static DEFINE_MUTEX(clients_lock);
static bool ism_v2_capable;
-struct ism_dev_list {
- struct list_head list;
- struct mutex mutex; /* protects ism device list */
-};
-
-static struct ism_dev_list ism_dev_list = {
- .list = LIST_HEAD_INIT(ism_dev_list.list),
- .mutex = __MUTEX_INITIALIZER(ism_dev_list.mutex),
-};
-
-static void ism_setup_forwarding(struct ism_client *client, struct ism_dev *ism)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ism->lock, flags);
- ism->subs[client->id] = client;
- spin_unlock_irqrestore(&ism->lock, flags);
-}
-
-int ism_register_client(struct ism_client *client)
-{
- struct ism_dev *ism;
- int i, rc = -ENOSPC;
-
- mutex_lock(&ism_dev_list.mutex);
- mutex_lock(&clients_lock);
- for (i = 0; i < MAX_CLIENTS; ++i) {
- if (!clients[i]) {
- clients[i] = client;
- client->id = i;
- if (i == max_client)
- max_client++;
- rc = 0;
- break;
- }
- }
- mutex_unlock(&clients_lock);
-
- if (i < MAX_CLIENTS) {
- /* initialize with all devices that we got so far */
- list_for_each_entry(ism, &ism_dev_list.list, list) {
- ism->priv[i] = NULL;
- client->add(ism);
- ism_setup_forwarding(client, ism);
- }
- }
- mutex_unlock(&ism_dev_list.mutex);
-
- return rc;
-}
-EXPORT_SYMBOL_GPL(ism_register_client);
-
-int ism_unregister_client(struct ism_client *client)
-{
- struct ism_dev *ism;
- unsigned long flags;
- int rc = 0;
-
- mutex_lock(&ism_dev_list.mutex);
- list_for_each_entry(ism, &ism_dev_list.list, list) {
- spin_lock_irqsave(&ism->lock, flags);
- /* Stop forwarding IRQs and events */
- ism->subs[client->id] = NULL;
- for (int i = 0; i < ISM_NR_DMBS; ++i) {
- if (ism->sba_client_arr[i] == client->id) {
- WARN(1, "%s: attempt to unregister '%s' with registered dmb(s)\n",
- __func__, client->name);
- rc = -EBUSY;
- goto err_reg_dmb;
- }
- }
- spin_unlock_irqrestore(&ism->lock, flags);
- }
- mutex_unlock(&ism_dev_list.mutex);
-
- mutex_lock(&clients_lock);
- clients[client->id] = NULL;
- if (client->id + 1 == max_client)
- max_client--;
- mutex_unlock(&clients_lock);
- return rc;
-
-err_reg_dmb:
- spin_unlock_irqrestore(&ism->lock, flags);
- mutex_unlock(&ism_dev_list.mutex);
- return rc;
-}
-EXPORT_SYMBOL_GPL(ism_unregister_client);

static int ism_cmd(struct ism_dev *ism, void *cmd)
{
@@ -475,7 +382,7 @@ static void ism_handle_event(struct ism_dev *ism)

entry = &ism->ieq->entry[ism->ieq_idx];
debug_event(ism_debug_info, 2, entry, sizeof(*entry));
- for (i = 0; i < max_client; ++i) {
+ for (i = 0; i < MAX_CLIENTS; ++i) {
clt = ism->subs[i];
if (clt)
clt->handle_event(ism, entry);
@@ -524,7 +431,7 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
static int ism_dev_init(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
- int i, ret;
+ int ret;

ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
if (ret <= 0)
@@ -558,19 +465,7 @@ static int ism_dev_init(struct ism_dev *ism)
else
ism_v2_capable = false;

- mutex_lock(&ism_dev_list.mutex);
- mutex_lock(&clients_lock);
- for (i = 0; i < max_client; ++i) {
- if (clients[i]) {
- clients[i]->add(ism);
- ism_setup_forwarding(clients[i], ism);
- }
- }
- mutex_unlock(&clients_lock);
-
- list_add(&ism->list, &ism_dev_list.list);
- mutex_unlock(&ism_dev_list.mutex);
-
+ ism_dev_register(ism);
query_info(ism);
return 0;

@@ -649,17 +544,11 @@ static void ism_dev_exit(struct ism_dev *ism)
int i;

spin_lock_irqsave(&ism->lock, flags);
- for (i = 0; i < max_client; ++i)
+ for (i = 0; i < MAX_CLIENTS; ++i)
ism->subs[i] = NULL;
spin_unlock_irqrestore(&ism->lock, flags);

- mutex_lock(&ism_dev_list.mutex);
- mutex_lock(&clients_lock);
- for (i = 0; i < max_client; ++i) {
- if (clients[i])
- clients[i]->remove(ism);
- }
- mutex_unlock(&clients_lock);
+ ism_dev_unregister(ism);

if (ism_v2_capable)
ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
@@ -668,8 +557,6 @@ static void ism_dev_exit(struct ism_dev *ism)
free_irq(pci_irq_vector(pdev, 0), ism);
kfree(ism->sba_client_arr);
pci_free_irq_vectors(pdev);
- list_del_init(&ism->list);
- mutex_unlock(&ism_dev_list.mutex);
}

static void ism_remove(struct pci_dev *pdev)
@@ -700,8 +587,6 @@ static int __init ism_init(void)
if (!ism_debug_info)
return -ENODEV;

- memset(clients, 0, sizeof(clients));
- max_client = 0;
debug_register_view(ism_debug_info, &debug_hex_ascii_view);
ret = pci_register_driver(&ism_driver);
if (ret)
@@ -721,7 +606,7 @@ module_exit(ism_exit);

/*************************** SMC-D Implementation *****************************/

-#if IS_ENABLED(CONFIG_SMC)
+#if IS_ENABLED(CONFIG_SMC) // needed to avoid unused functions
static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid,
u32 vid)
{
diff --git a/include/linux/ism.h b/include/linux/ism.h
index 5428edd90982..1462296e8ba7 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -9,6 +9,7 @@
#ifndef _ISM_H
#define _ISM_H

+#include <linux/device.h>
#include <linux/workqueue.h>

struct ism_dmb {
@@ -24,6 +25,7 @@ struct ism_dmb {

/* Unless we gain unexpected popularity, this limit should hold for a while */
#define MAX_CLIENTS 8
+#define NO_CLIENT 0xff /* must be >= MAX_CLIENTS */
#define ISM_NR_DMBS 1920

struct ism_dev {
@@ -76,6 +78,9 @@ static inline void *ism_get_priv(struct ism_dev *dev,
return dev->priv[client->id];
}

+int ism_dev_register(struct ism_dev *ism);
+void ism_dev_unregister(struct ism_dev *ism);
+
static inline void ism_set_priv(struct ism_dev *dev, struct ism_client *client,
void *priv) {
dev->priv[client->id] = priv;
@@ -87,6 +92,9 @@ int ism_unregister_dmb(struct ism_dev *dev, struct ism_dmb *dmb);
int ism_move(struct ism_dev *dev, u64 dmb_tok, unsigned int idx, bool sf,
unsigned int offset, void *data, unsigned int size);

+#define ISM_RESERVED_VLANID 0x1FFF
+#define ISM_ERROR 0xFFFF
+
const struct smcd_ops *ism_get_smcd_ops(void);

#endif /* _ISM_H */
diff --git a/include/net/smc.h b/include/net/smc.h
index db84e4e35080..ab732b286f91 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -42,9 +42,6 @@ struct smcd_dmb {
#define ISM_EVENT_GID 1
#define ISM_EVENT_SWR 2

-#define ISM_RESERVED_VLANID 0x1FFF
-
-#define ISM_ERROR 0xFFFF

struct smcd_dev;

diff --git a/net/Kconfig b/net/Kconfig
index c3fca69a7c83..2dbe9655f7de 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -83,6 +83,7 @@ source "net/tls/Kconfig"
source "net/xfrm/Kconfig"
source "net/iucv/Kconfig"
source "net/smc/Kconfig"
+source "net/ism/Kconfig"
source "net/xdp/Kconfig"

config NET_HANDSHAKE
diff --git a/net/Makefile b/net/Makefile
index 60ed5190eda8..6f06cf00bfbb 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_SMC) += smc/
+obj-$(CONFIG_ISM) += ism/
obj-$(CONFIG_RFKILL) += rfkill/
obj-$(CONFIG_NET_9P) += 9p/
obj-$(CONFIG_CAIF) += caif/
diff --git a/net/ism/Kconfig b/net/ism/Kconfig
new file mode 100644
index 000000000000..4329489cc1e9
--- /dev/null
+++ b/net/ism/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+config ISM
+ tristate "ISM support"
+ default n
+ help
+ Internal Shared Memory (ISM)
+ A communication method that uses common physical memory for
+ synchronous direct access into a remote buffer.
+
+ Select this option to provide the abstraction layer between
+ ISM devices and ISM users like the SMC protocol.
+
+ To compile as a module choose M. The module name is ism.
+ If unsure, choose N.
diff --git a/net/ism/Makefile b/net/ism/Makefile
new file mode 100644
index 000000000000..b752baf72003
--- /dev/null
+++ b/net/ism/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# ISM class module
+#
+
+ism-y += ism_main.o
+obj-$(CONFIG_ISM) += ism.o
diff --git a/net/ism/ism_main.c b/net/ism/ism_main.c
new file mode 100644
index 000000000000..268408dbd691
--- /dev/null
+++ b/net/ism/ism_main.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Internal Shared Memory
+ *
+ * Implementation of the ISM class module
+ *
+ * Copyright IBM Corp. 2024
+ */
+#define KMSG_COMPONENT "ism"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/ism.h>
+
+MODULE_DESCRIPTION("Internal Shared Memory class");
+MODULE_LICENSE("GPL");
+
+static struct ism_client *clients[MAX_CLIENTS]; /* use an array rather than */
+ /* a list for fast mapping */
+static u8 max_client;
+static DEFINE_MUTEX(clients_lock);
+struct ism_dev_list {
+ struct list_head list;
+ struct mutex mutex; /* protects ism device list */
+};
+
+static struct ism_dev_list ism_dev_list = {
+ .list = LIST_HEAD_INIT(ism_dev_list.list),
+ .mutex = __MUTEX_INITIALIZER(ism_dev_list.mutex),
+};
+
+static void ism_setup_forwarding(struct ism_client *client, struct ism_dev *ism)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ism->lock, flags);
+ ism->subs[client->id] = client;
+ spin_unlock_irqrestore(&ism->lock, flags);
+}
+
+int ism_register_client(struct ism_client *client)
+{
+ struct ism_dev *ism;
+ int i, rc = -ENOSPC;
+
+ mutex_lock(&ism_dev_list.mutex);
+ mutex_lock(&clients_lock);
+ for (i = 0; i < MAX_CLIENTS; ++i) {
+ if (!clients[i]) {
+ clients[i] = client;
+ client->id = i;
+ if (i == max_client)
+ max_client++;
+ rc = 0;
+ break;
+ }
+ }
+ mutex_unlock(&clients_lock);
+
+ if (i < MAX_CLIENTS) {
+ /* initialize with all devices that we got so far */
+ list_for_each_entry(ism, &ism_dev_list.list, list) {
+ ism->priv[i] = NULL;
+ client->add(ism);
+ ism_setup_forwarding(client, ism);
+ }
+ }
+ mutex_unlock(&ism_dev_list.mutex);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ism_register_client);
+
+int ism_unregister_client(struct ism_client *client)
+{
+ struct ism_dev *ism;
+ unsigned long flags;
+ int rc = 0;
+
+ mutex_lock(&ism_dev_list.mutex);
+ list_for_each_entry(ism, &ism_dev_list.list, list) {
+ spin_lock_irqsave(&ism->lock, flags);
+ /* Stop forwarding IRQs and events */
+ ism->subs[client->id] = NULL;
+ for (int i = 0; i < ISM_NR_DMBS; ++i) {
+ if (ism->sba_client_arr[i] == client->id) {
+ WARN(1, "%s: attempt to unregister '%s' with registered dmb(s)\n",
+ __func__, client->name);
+ rc = -EBUSY;
+ goto err_reg_dmb;
+ }
+ }
+ spin_unlock_irqrestore(&ism->lock, flags);
+ }
+ mutex_unlock(&ism_dev_list.mutex);
+
+ mutex_lock(&clients_lock);
+ clients[client->id] = NULL;
+ if (client->id + 1 == max_client)
+ max_client--;
+ mutex_unlock(&clients_lock);
+ return rc;
+
+err_reg_dmb:
+ spin_unlock_irqrestore(&ism->lock, flags);
+ mutex_unlock(&ism_dev_list.mutex);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ism_unregister_client);
+
+int ism_dev_register(struct ism_dev *ism)
+{
+ int i;
+
+ mutex_lock(&ism_dev_list.mutex);
+ mutex_lock(&clients_lock);
+ for (i = 0; i < max_client; ++i) {
+ if (clients[i]) {
+ clients[i]->add(ism);
+ ism_setup_forwarding(clients[i], ism);
+ }
+ }
+ mutex_unlock(&clients_lock);
+ list_add(&ism->list, &ism_dev_list.list);
+ mutex_unlock(&ism_dev_list.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ism_dev_register);
+
+void ism_dev_unregister(struct ism_dev *ism)
+{
+ int i;
+
+ mutex_lock(&ism_dev_list.mutex);
+ mutex_lock(&clients_lock);
+ for (i = 0; i < max_client; ++i) {
+ if (clients[i])
+ clients[i]->remove(ism);
+ }
+ mutex_unlock(&clients_lock);
+ list_del_init(&ism->list);
+ mutex_unlock(&ism_dev_list.mutex);
+}
+EXPORT_SYMBOL_GPL(ism_dev_unregister);
+
+static int __init ism_init(void)
+{
+ memset(clients, 0, sizeof(clients));
+ max_client = 0;
+
+ return 0;
+}
+
+static void __exit ism_exit(void)
+{
+}
+
+module_init(ism_init);
+module_exit(ism_exit);
--
2.45.2