* [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing
@ 2025-09-18 11:04 Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 01/14] net/smc: Remove error handling of unregister_dmb() Alexandra Winter
` (14 more replies)
0 siblings, 15 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
This series introduces a generic abstraction of existing components like:
- the s390 specific ISM device (Internal Shared Memory),
- the SMC-D loopback mechanism (Shared Memory Communication - Direct)
- the client interface of the SMC-D module to the transport devices
This generic shim layer can be extended with more devices, more clients and
more features in the future.
This layer is called 'dibs' for Direct Internal Buffer Sharing based on the
common scheme that these mechanisms enable controlled sharing of memory
buffers within some containing entity such as a hypervisor or a Linux
instance.
Benefits:
- Cleaner separation of ISM and SMC-D functionality
- simpler and less module dependencies
- Clear interface definition.
- Extendable for future devices and clients.
An overview was given at the Netdev 0x19 conference, recordings and slides
are available [1].
Background / Status quo:
------------------------
Currently s390 hardware provides virtual PCI ISM devices (Internal Shared
Memory). Their driver is in drivers/s390/net/ism_drv.c. The main user is
SMC-D (net/smc). The ism driver offers a client interface so other
users/protocols can also use them, but it is still heavily intermingled
with the smc code. Namely, the ism module cannot be used without the smc
module, which feels artificial.
There is ongoing work to extend the ISM concept of shared buffers that can
be accessed directly by another instance on the same hardware: [2] proposed
a loopback interface (ism_lo), that can be used on non-s390 architectures
(e.g. between containers or to test SMC-D). A minimal implementation went
upstream with [3]: ism_lo currently is a part of the smc protocol and
rather hidden.
[4] proposed a virtio definition of ism (ism_virtio) that can be used
between kvm guests.
We will shortly send an RFC for an dibs client that uses dibs as transport
for TTY.
Concept:
--------
Create a shim layer in net/dibs that contains common definitions and code
for all dibs devices and all dibs clients. Any device or client module only
needs to depend on this dibs layer module and any device or client code
only needs to include the definitions in include/linux/dibs.h.
The name dibs was chosen to clearly distinguish it from the existing s390
ism devices. And to emphasize that it is not about sharing whole memory
regions with anybody, but dedicating single buffers for another system.
Implementation:
---------------
The end result of this series is: A dibs shim layer with
- One dibs client: smc-d
- Two dibs device drivers: ism and dibs-loopback
- Everything prepared to add more clients and more device drivers.
Patches 1-2 contain some issues that were found along the way. They make
sense on their own, but also enable a better structured dibs series.
There are three components that exist today:
a) smc module (especially SMC-D functionality, which is an ism client today)
b) ism device driver (supports multiple ism clients today)
c) smc-loopback (integrated with smc today)
In order to preserve existing functionality at each step, these are not
moved to dibs layer by component, instead:
- the dibs layer is established in parallel to existing code [patches 3-6]
- then some service functions are moved to the dibs layer [patches 7-12]
- the actual data movement is moved to the dibs layer [patch 13]
- and last event handling is moved to the dibs layer [patch 14]
Future:
-------
Items that are not part of this patchset but can be added later:
- dynamically add or remove dibs_loopback. That will be allow for simple
testing of add_dev()/del_dev()
- handle_irq(): Call clients without interrupt context. e.g using
threaded interrupts. I left this for a follow-on, because it includes
conceptual changes for the smcd receive code.
- Any improvements of locking scopes. I mainly moved some of the the
existing locks to dibs layer. I have the feeling there is room for
improvements.
- The device drivers should not loop through the client array
- dibs_dev_op.*_dmb() functions reveal unnecessary details of the
internal dmb struct to the clients
- Check whether client calls to dibs_dev_ops should be replaced by
interface functions that provide additional value
- Check whether device driver calls to dibs_client_ops should be replaced
by interface functions that provide additional value.
Link: [1] https://netdevconf.info/0x19/sessions/talk/communication-via-internal-shared-memory-ism-time-to-open-up.html
Link: [2] https://lore.kernel.org/netdev/1695568613-125057-1-git-send-email-guwen@linux.alibaba.com/
Link: [3] https://lore.kernel.org/linux-kernel//20240428060738.60843-1-guwen@linux.alibaba.com/
Link: [4] https://groups.oasis-open.org/communities/community-home/digestviewer/viewthread?GroupId=3973&MessageKey=c060ecf9-ea1a-49a2-9827-c92f0e6447b2&CommunityKey=2f26be99-3aa1-48f6-93a5-018dce262226&hlmlt=VT
---
Changes in v3:
- Use kfree() instead of kvfree() for kmalloc()ed dmbs (Paolo Abeni) [13]
Changes in v2:
- More fixes of transient scope of IS_ENABLED(CONFIG_ISM) [7,13] (patchwork)
- Delete obsolete net/smc/smc_loopback.* files [13] (Dust Li)
- Fix transient usage of supports_v2() after rebase on top of
091d019adce0 ("net/smc: remove unused function smc_lo_supports_v2") [7]
- Fix CC according to get_maintainer.pl (patchwork)
- Place dibs level code in drivers/dibs/ instead of net/dibs/ (Dust Li, Julian Ruess)
- Link: https://lore.kernel.org/netdev/20250911194827.844125-1-wintera@linux.ibm.com/
Changes in v1:
- Don't change __init in smc_core_init() (was [1]) (Dust Li)
- Split off log message improvements from this series (was [2,5]) (Dust Li)
- Fix arch/s390/[debug_]defconfig [4,6,7,14]
- Helptext of dibs/Kconfig [3,6]
- include linux/slab.h to avoid Wimplicit-function-declaration of
kzalloc() and kfree() [5,6] (Simon Horman and
'kernel test robot <lkp@intel.com>')
- Fix transient use of undefined 'ism' pointer [7] (Simon Horman)
- Fix transient scope of IS_ENABLED(CONFIG_ISM) [7,13] (Simon Horman)
- Change position of is_attached in struct smc_buf_desc to reduce gaps [1] (Dust Li)
- Fix SW-pnetid handling for s390 ism devices [9]
- use dibs->dev instead of defining dibs_get_dev() [8]
- add const to uuid_t* parameters [12,14] (Julian Ruess)
- no log message for module load/unload [3] (Jakub Kicinski)
- Link: https://lore.kernel.org/netdev/20250905145428.1962105-1-wintera@linux.ibm.com/
RFC:
- Link: https://lore.kernel.org/netdev/20250806154122.3413330-1-wintera@linux.ibm.com/
Alexandra Winter (11):
net/smc: Remove error handling of unregister_dmb()
net/smc: Decouple sf and attached send_buf in smc_loopback
dibs: Create drivers/dibs
dibs: Register smc as dibs_client
dibs: Register ism as dibs device
dibs: Define dibs loopback
dibs: Define dibs_client_ops and dibs_dev_ops
dibs: Local gid for dibs devices
dibs: Move vlan support to dibs_dev_ops
dibs: Move query_remote_gid() to dibs_dev_ops
dibs: Move data path to dibs layer
Julian Ruess (3):
dibs: Move struct device to dibs_dev
dibs: Create class dibs
dibs: Move event handling to dibs layer
MAINTAINERS | 9 +-
arch/s390/configs/debug_defconfig | 4 +-
arch/s390/configs/defconfig | 4 +-
drivers/Makefile | 1 +
drivers/dibs/Kconfig | 23 ++
drivers/dibs/Makefile | 8 +
drivers/dibs/dibs_loopback.c | 356 +++++++++++++++++++
drivers/dibs/dibs_loopback.h | 57 +++
drivers/dibs/dibs_main.c | 278 +++++++++++++++
drivers/s390/net/Kconfig | 3 +-
drivers/s390/net/ism.h | 53 ++-
drivers/s390/net/ism_drv.c | 573 +++++++++++-------------------
include/linux/dibs.h | 464 ++++++++++++++++++++++++
include/linux/ism.h | 28 +-
include/net/smc.h | 51 +--
net/Kconfig | 1 +
net/smc/Kconfig | 16 +-
net/smc/Makefile | 1 -
net/smc/af_smc.c | 12 +-
net/smc/smc_clc.c | 6 +-
net/smc/smc_core.c | 6 +-
net/smc/smc_core.h | 5 +
net/smc/smc_diag.c | 2 +-
net/smc/smc_ism.c | 224 ++++++------
net/smc/smc_ism.h | 36 +-
net/smc/smc_loopback.c | 421 ----------------------
net/smc/smc_loopback.h | 60 ----
net/smc/smc_pnet.c | 25 +-
net/smc/smc_tx.c | 3 +
29 files changed, 1645 insertions(+), 1085 deletions(-)
create mode 100644 drivers/dibs/Kconfig
create mode 100644 drivers/dibs/Makefile
create mode 100644 drivers/dibs/dibs_loopback.c
create mode 100644 drivers/dibs/dibs_loopback.h
create mode 100644 drivers/dibs/dibs_main.c
create mode 100644 include/linux/dibs.h
delete mode 100644 net/smc/smc_loopback.c
delete mode 100644 net/smc/smc_loopback.h
--
2.48.1
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH net-next v3 01/14] net/smc: Remove error handling of unregister_dmb()
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 02/14] net/smc: Decouple sf and attached send_buf in smc_loopback Alexandra Winter
` (13 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
smcd_buf_free() calls smc_ism_unregister_dmb(lgr->smcd, buf_desc) and
then unconditionally frees buf_desc.
Remove the cleaning up of fields of buf_desc in
smc_ism_unregister_dmb(), because it is not helpful.
This removes the only usage of ISM_ERROR from the smc module. So move it
to drivers/s390/net/ism.h.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
---
drivers/s390/net/ism.h | 1 +
include/net/smc.h | 2 --
net/smc/smc_ism.c | 14 +++++---------
net/smc/smc_ism.h | 3 ++-
4 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index 047fa6101555..b5b03db52fce 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -10,6 +10,7 @@
#include <asm/pci_insn.h>
#define UTIL_STR_LEN 16
+#define ISM_ERROR 0xFFFF
/*
* Do not use the first word of the DMB bits to ensure 8 byte aligned access.
diff --git a/include/net/smc.h b/include/net/smc.h
index db84e4e35080..a9c023dd1380 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -44,8 +44,6 @@ struct smcd_dmb {
#define ISM_RESERVED_VLANID 0x1FFF
-#define ISM_ERROR 0xFFFF
-
struct smcd_dev;
struct smcd_gid {
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index a58ffb7a0610..fca01b95b65a 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -205,13 +205,13 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
return rc;
}
-int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc)
+void smc_ism_unregister_dmb(struct smcd_dev *smcd,
+ struct smc_buf_desc *dmb_desc)
{
struct smcd_dmb dmb;
- int rc = 0;
if (!dmb_desc->dma_addr)
- return rc;
+ return;
memset(&dmb, 0, sizeof(dmb));
dmb.dmb_tok = dmb_desc->token;
@@ -219,13 +219,9 @@ int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc)
dmb.cpu_addr = dmb_desc->cpu_addr;
dmb.dma_addr = dmb_desc->dma_addr;
dmb.dmb_len = dmb_desc->len;
- rc = smcd->ops->unregister_dmb(smcd, &dmb);
- if (!rc || rc == ISM_ERROR) {
- dmb_desc->cpu_addr = NULL;
- dmb_desc->dma_addr = 0;
- }
+ smcd->ops->unregister_dmb(smcd, &dmb);
- return rc;
+ return;
}
int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 6763133dd8d0..765aa8fae6fa 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -47,7 +47,8 @@ int smc_ism_get_vlan(struct smcd_dev *dev, unsigned short vlan_id);
int smc_ism_put_vlan(struct smcd_dev *dev, unsigned short vlan_id);
int smc_ism_register_dmb(struct smc_link_group *lgr, int buf_size,
struct smc_buf_desc *dmb_desc);
-int smc_ism_unregister_dmb(struct smcd_dev *dev, struct smc_buf_desc *dmb_desc);
+void smc_ism_unregister_dmb(struct smcd_dev *dev,
+ struct smc_buf_desc *dmb_desc);
bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd);
int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
struct smc_buf_desc *dmb_desc);
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 02/14] net/smc: Decouple sf and attached send_buf in smc_loopback
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 01/14] net/smc: Remove error handling of unregister_dmb() Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 03/14] dibs: Create drivers/dibs Alexandra Winter
` (12 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Before this patch there was the following assumption in
smc_loopback.c>smc_lo_move_data():
sf (signalling flag) == 0 : data is already in an attached target dmb
sf == 1 : data is not yet in the target dmb
This is true for the 2 callers in smc client
smcd_cdc_msg_send() : sf=1
smcd_tx_rdma_writes() : sf=0
but should not be a general assumption.
Add a bool to struct smc_buf_desc to indicate whether an SMC-D sndbuf_desc
is an attached buffer. Don't call move_data() for attached send_buffers,
because it is not necessary.
Move the data in smc_lo_move_data() if len != 0 and signal when requested.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
Reviewed-by: Dust Li <dust.li@linux.alibaba.com>
---
net/smc/smc_core.h | 5 +++++
net/smc/smc_ism.c | 1 +
net/smc/smc_loopback.c | 9 +++------
net/smc/smc_tx.c | 3 +++
4 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/net/smc/smc_core.h b/net/smc/smc_core.h
index 48a1b1dcb576..a5a78cbff341 100644
--- a/net/smc/smc_core.h
+++ b/net/smc/smc_core.h
@@ -13,6 +13,7 @@
#define _SMC_CORE_H
#include <linux/atomic.h>
+#include <linux/types.h>
#include <linux/smc.h>
#include <linux/pci.h>
#include <rdma/ib_verbs.h>
@@ -221,6 +222,10 @@ struct smc_buf_desc {
/* virtually contiguous */
};
struct { /* SMC-D */
+ /* SMC-D tx buffer */
+ bool is_attached;
+ /* no need for explicit writes */
+ /* SMC-D rx buffer: */
unsigned short sba_idx;
/* SBA index number */
u64 token;
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index fca01b95b65a..503a9f93b392 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -274,6 +274,7 @@ int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
dmb_desc->cpu_addr = dmb.cpu_addr;
dmb_desc->dma_addr = dmb.dma_addr;
dmb_desc->len = dmb.dmb_len;
+ dmb_desc->is_attached = true;
}
return rc;
}
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 0eb00bbefd17..1853c26fbbbb 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -224,12 +224,6 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
struct smc_lo_dev *ldev = smcd->priv;
struct smc_connection *conn;
- if (!sf)
- /* since sndbuf is merged with peer DMB, there is
- * no need to copy data from sndbuf to peer DMB.
- */
- return 0;
-
read_lock_bh(&ldev->dmb_ht_lock);
hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
if (tmp_node->token == dmb_tok) {
@@ -244,6 +238,9 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
memcpy((char *)rmb_node->cpu_addr + offset, data, size);
read_unlock_bh(&ldev->dmb_ht_lock);
+ if (!sf)
+ return 0;
+
conn = smcd->conn[rmb_node->sba_idx];
if (!conn || conn->killed)
return -EPIPE;
diff --git a/net/smc/smc_tx.c b/net/smc/smc_tx.c
index 214ac3cbcf9a..3144b4b1fe29 100644
--- a/net/smc/smc_tx.c
+++ b/net/smc/smc_tx.c
@@ -426,6 +426,9 @@ static int smcd_tx_rdma_writes(struct smc_connection *conn, size_t len,
int srcchunk, dstchunk;
int rc;
+ if (conn->sndbuf_desc->is_attached)
+ return 0;
+
for (dstchunk = 0; dstchunk < 2; dstchunk++) {
for (srcchunk = 0; srcchunk < 2; srcchunk++) {
void *data = conn->sndbuf_desc->cpu_addr + src_off;
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 03/14] dibs: Create drivers/dibs
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 01/14] net/smc: Remove error handling of unregister_dmb() Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 02/14] net/smc: Decouple sf and attached send_buf in smc_loopback Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 04/14] dibs: Register smc as dibs_client Alexandra Winter
` (11 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Create the file structure for a 'DIBS - Direct Internal Buffer Sharing'
shim layer that will provide generic functionality and declarations for
dibs device drivers and dibs clients.
Following patches will add functionality.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
MAINTAINERS | 7 +++++++
drivers/Makefile | 1 +
drivers/dibs/Kconfig | 12 ++++++++++++
drivers/dibs/Makefile | 7 +++++++
drivers/dibs/dibs_main.c | 37 +++++++++++++++++++++++++++++++++++
include/linux/dibs.h | 42 ++++++++++++++++++++++++++++++++++++++++
net/Kconfig | 1 +
7 files changed, 107 insertions(+)
create mode 100644 drivers/dibs/Kconfig
create mode 100644 drivers/dibs/Makefile
create mode 100644 drivers/dibs/dibs_main.c
create mode 100644 include/linux/dibs.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 47bc35743f22..10d3ccebaa73 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7132,6 +7132,13 @@ L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-gpio-mm.c
+DIBS (DIRECT INTERNAL BUFFER SHARING)
+M: Alexandra Winter <wintera@linux.ibm.com>
+L: netdev@vger.kernel.org
+S: Supported
+F: drivers/dibs/
+F: include/linux/dibs.h
+
DIGITEQ AUTOMOTIVE MGB4 V4L2 DRIVER
M: Martin Tuma <martin.tuma@digiteqautomotive.com>
L: linux-media@vger.kernel.org
diff --git a/drivers/Makefile b/drivers/Makefile
index b5749cf67044..a104163b1353 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -195,4 +195,5 @@ obj-$(CONFIG_DRM_ACCEL) += accel/
obj-$(CONFIG_CDX_BUS) += cdx/
obj-$(CONFIG_DPLL) += dpll/
+obj-$(CONFIG_DIBS) += dibs/
obj-$(CONFIG_S390) += s390/
diff --git a/drivers/dibs/Kconfig b/drivers/dibs/Kconfig
new file mode 100644
index 000000000000..09c12f6838ad
--- /dev/null
+++ b/drivers/dibs/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+config DIBS
+ tristate "DIBS support"
+ default n
+ help
+ Direct Internal Buffer Sharing (DIBS)
+ A communication method that uses common physical (internal) memory
+ for synchronous direct access into a remote buffer.
+
+ Select this option to provide the abstraction layer between
+ dibs devices and dibs clients like the SMC protocol.
+ The module name is dibs.
diff --git a/drivers/dibs/Makefile b/drivers/dibs/Makefile
new file mode 100644
index 000000000000..825dec431bfc
--- /dev/null
+++ b/drivers/dibs/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# DIBS class module
+#
+
+dibs-y += dibs_main.o
+obj-$(CONFIG_DIBS) += dibs.o
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
new file mode 100644
index 000000000000..68e189932fcf
--- /dev/null
+++ b/drivers/dibs/dibs_main.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DIBS - Direct Internal Buffer Sharing
+ *
+ * Implementation of the DIBS class module
+ *
+ * Copyright IBM Corp. 2025
+ */
+#define KMSG_COMPONENT "dibs"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/dibs.h>
+
+MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
+MODULE_LICENSE("GPL");
+
+/* use an array rather a list for fast mapping: */
+static struct dibs_client *clients[MAX_DIBS_CLIENTS];
+static u8 max_client;
+
+static int __init dibs_init(void)
+{
+ memset(clients, 0, sizeof(clients));
+ max_client = 0;
+
+ return 0;
+}
+
+static void __exit dibs_exit(void)
+{
+}
+
+module_init(dibs_init);
+module_exit(dibs_exit);
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
new file mode 100644
index 000000000000..3f4175aaa732
--- /dev/null
+++ b/include/linux/dibs.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Direct Internal Buffer Sharing
+ *
+ * Definitions for the DIBS module
+ *
+ * Copyright IBM Corp. 2025
+ */
+#ifndef _DIBS_H
+#define _DIBS_H
+
+/* DIBS - Direct Internal Buffer Sharing - concept
+ * -----------------------------------------------
+ * In the case of multiple system sharing the same hardware, dibs fabrics can
+ * provide dibs devices to these systems. The systems use dibs devices of the
+ * same fabric to communicate via dmbs (Direct Memory Buffers). Each dmb has
+ * exactly one owning local dibs device and one remote using dibs device, that
+ * is authorized to write into this dmb. This access control is provided by the
+ * dibs fabric.
+ *
+ * Because the access to the dmb is based on access to physical memory, it is
+ * lossless and synchronous. The remote devices can directly access any offset
+ * of the dmb.
+ *
+ * Dibs fabrics, dibs devices and dmbs are identified by tokens and ids.
+ * Dibs fabric id is unique within the same hardware (with the exception of the
+ * dibs loopback fabric), dmb token is unique within the same fabric, dibs
+ * device gids are guaranteed to be unique within the same fabric and
+ * statistically likely to be globally unique. The exchange of these tokens and
+ * ids between the systems is not part of the dibs concept.
+ *
+ * The dibs layer provides an abstraction between dibs device drivers and dibs
+ * clients.
+ */
+
+#define MAX_DIBS_CLIENTS 8
+
+struct dibs_client {
+ const char *name;
+};
+
+#endif /* _DIBS_H */
diff --git a/net/Kconfig b/net/Kconfig
index d5865cf19799..f370f8f196f6 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -87,6 +87,7 @@ source "net/tls/Kconfig"
source "net/xfrm/Kconfig"
source "net/iucv/Kconfig"
source "net/smc/Kconfig"
+source "drivers/dibs/Kconfig"
source "net/xdp/Kconfig"
config NET_HANDSHAKE
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 04/14] dibs: Register smc as dibs_client
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (2 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 03/14] dibs: Create drivers/dibs Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 05/14] dibs: Register ism as dibs device Alexandra Winter
` (10 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Formally register smc as dibs client. Functionality will be moved by
follow-on patches from ism_client to dibs_client until eventually
ism_client can be removed.
As DIBS is only a shim layer without any dependencies, we can depend SMC
on DIBS without adding indirect dependencies. A follow-on patch will
remove dependency of SMC on ISM.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
---
arch/s390/configs/debug_defconfig | 1 +
arch/s390/configs/defconfig | 1 +
drivers/dibs/dibs_main.c | 35 +++++++++++++++++++++++++++++++
include/linux/dibs.h | 23 ++++++++++++++++++++
net/smc/Kconfig | 2 +-
net/smc/smc_ism.c | 6 ++++++
6 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 5e616bc988ac..7bc54f053a3b 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -120,6 +120,7 @@ CONFIG_UNIX=y
CONFIG_UNIX_DIAG=m
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
+CONFIG_DIBS=y
CONFIG_SMC_DIAG=m
CONFIG_SMC_LO=y
CONFIG_INET=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 094599cdaf4d..4bf6f3311f7d 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -111,6 +111,7 @@ CONFIG_UNIX=y
CONFIG_UNIX_DIAG=m
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
+CONFIG_DIBS=y
CONFIG_SMC_DIAG=m
CONFIG_SMC_LO=y
CONFIG_INET=y
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index 68e189932fcf..a5d2be9c3246 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -20,6 +20,41 @@ MODULE_LICENSE("GPL");
/* use an array rather a list for fast mapping: */
static struct dibs_client *clients[MAX_DIBS_CLIENTS];
static u8 max_client;
+static DEFINE_MUTEX(clients_lock);
+
+int dibs_register_client(struct dibs_client *client)
+{
+ int i, rc = -ENOSPC;
+
+ mutex_lock(&clients_lock);
+ for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
+ if (!clients[i]) {
+ clients[i] = client;
+ client->id = i;
+ if (i == max_client)
+ max_client++;
+ rc = 0;
+ break;
+ }
+ }
+ mutex_unlock(&clients_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(dibs_register_client);
+
+int dibs_unregister_client(struct dibs_client *client)
+{
+ int rc = 0;
+
+ mutex_lock(&clients_lock);
+ clients[client->id] = NULL;
+ if (client->id + 1 == max_client)
+ max_client--;
+ mutex_unlock(&clients_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(dibs_unregister_client);
static int __init dibs_init(void)
{
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 3f4175aaa732..7bedeaf52c1b 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -33,10 +33,33 @@
* clients.
*/
+/* DIBS client
+ * -----------
+ */
#define MAX_DIBS_CLIENTS 8
struct dibs_client {
+ /* client name for logging and debugging purposes */
const char *name;
+ /* client index - provided and used by dibs layer */
+ u8 id;
};
+/* Functions to be called by dibs clients:
+ */
+/**
+ * dibs_register_client() - register a client with dibs layer
+ * @client: this client
+ *
+ * Return: zero on success.
+ */
+int dibs_register_client(struct dibs_client *client);
+/**
+ * dibs_unregister_client() - unregister a client with dibs layer
+ * @client: this client
+ *
+ * Return: zero on success.
+ */
+int dibs_unregister_client(struct dibs_client *client);
+
#endif /* _DIBS_H */
diff --git a/net/smc/Kconfig b/net/smc/Kconfig
index ba5e6a2dd2fd..40dd60c1d23f 100644
--- a/net/smc/Kconfig
+++ b/net/smc/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config SMC
tristate "SMC socket protocol family"
- depends on INET && INFINIBAND
+ depends on INET && INFINIBAND && DIBS
depends on m || ISM != m
help
SMC-R provides a "sockets over RDMA" solution making use of
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 503a9f93b392..a7a965e3c0ce 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -18,6 +18,7 @@
#include "smc_pnet.h"
#include "smc_netlink.h"
#include "linux/ism.h"
+#include "linux/dibs.h"
struct smcd_dev_list smcd_dev_list = {
.list = LIST_HEAD_INIT(smcd_dev_list.list),
@@ -42,6 +43,9 @@ static struct ism_client smc_ism_client = {
.handle_irq = smcd_handle_irq,
};
#endif
+static struct dibs_client smc_dibs_client = {
+ .name = "SMC-D",
+};
static void smc_ism_create_system_eid(void)
{
@@ -623,11 +627,13 @@ int smc_ism_init(void)
#if IS_ENABLED(CONFIG_ISM)
rc = ism_register_client(&smc_ism_client);
#endif
+ rc = dibs_register_client(&smc_dibs_client);
return rc;
}
void smc_ism_exit(void)
{
+ dibs_unregister_client(&smc_dibs_client);
#if IS_ENABLED(CONFIG_ISM)
ism_unregister_client(&smc_ism_client);
#endif
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 05/14] dibs: Register ism as dibs device
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (3 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 04/14] dibs: Register smc as dibs_client Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 06/14] dibs: Define dibs loopback Alexandra Winter
` (9 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Register ism devices with the dibs layer. Follow-on patches will move
functionality to the dibs layer.
As DIBS is only a shim layer without any dependencies, we can depend ISM
on DIBS without adding indirect dependencies. A follow-on patch will
remove implication of SMC by ISM.
Define struct dibs_dev. Follow-on patches will move more content into
dibs_dev. The goal of follow-on patches is that ism_dev will only
contain fields that are special for this device driver. The same concept
will apply to other dibs device drivers.
Define dibs_dev_alloc(), dibs_dev_add() and dibs_dev_del() to be called
by dibs device drivers and call them from ism_drv.c
Use ism_dev.dibs for a pointer to dibs_dev.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
drivers/dibs/dibs_main.c | 38 +++++++++++++++++
drivers/s390/net/Kconfig | 2 +-
drivers/s390/net/ism.h | 1 +
drivers/s390/net/ism_drv.c | 83 ++++++++++++++++++++++++--------------
include/linux/dibs.h | 38 +++++++++++++++++
include/linux/ism.h | 1 +
6 files changed, 131 insertions(+), 32 deletions(-)
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index a5d2be9c3246..2f420e077417 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/slab.h>
#include <linux/err.h>
#include <linux/dibs.h>
@@ -21,6 +22,15 @@ MODULE_LICENSE("GPL");
static struct dibs_client *clients[MAX_DIBS_CLIENTS];
static u8 max_client;
static DEFINE_MUTEX(clients_lock);
+struct dibs_dev_list {
+ struct list_head list;
+ struct mutex mutex; /* protects dibs device list */
+};
+
+static struct dibs_dev_list dibs_dev_list = {
+ .list = LIST_HEAD_INIT(dibs_dev_list.list),
+ .mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
+};
int dibs_register_client(struct dibs_client *client)
{
@@ -56,6 +66,34 @@ int dibs_unregister_client(struct dibs_client *client)
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);
+struct dibs_dev *dibs_dev_alloc(void)
+{
+ struct dibs_dev *dibs;
+
+ dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
+
+ return dibs;
+}
+EXPORT_SYMBOL_GPL(dibs_dev_alloc);
+
+int dibs_dev_add(struct dibs_dev *dibs)
+{
+ mutex_lock(&dibs_dev_list.mutex);
+ list_add(&dibs->list, &dibs_dev_list.list);
+ mutex_unlock(&dibs_dev_list.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dibs_dev_add);
+
+void dibs_dev_del(struct dibs_dev *dibs)
+{
+ mutex_lock(&dibs_dev_list.mutex);
+ list_del_init(&dibs->list);
+ mutex_unlock(&dibs_dev_list.mutex);
+}
+EXPORT_SYMBOL_GPL(dibs_dev_del);
+
static int __init dibs_init(void)
{
memset(clients, 0, sizeof(clients));
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 2b43f6f28362..92985f595d59 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -81,7 +81,7 @@ config CCWGROUP
config ISM
tristate "Support for ISM vPCI Adapter"
- depends on PCI
+ depends on PCI && DIBS
imply SMC
default n
help
diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index b5b03db52fce..3078779fa71e 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -5,6 +5,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/dibs.h>
#include <linux/ism.h>
#include <net/smc.h>
#include <asm/pci_insn.h>
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 6cd60b174315..8ecd0cccc7e8 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -599,8 +599,39 @@ static void ism_dev_release(struct device *dev)
kfree(ism);
}
+static void ism_dev_exit(struct ism_dev *ism)
+{
+ struct pci_dev *pdev = ism->pdev;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ism->lock, flags);
+ for (i = 0; i < max_client; ++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);
+
+ if (ism_v2_capable)
+ ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
+ unregister_ieq(ism);
+ unregister_sba(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 int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct dibs_dev *dibs;
struct ism_dev *ism;
int ret;
@@ -636,12 +667,28 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dma_set_max_seg_size(&pdev->dev, SZ_1M);
pci_set_master(pdev);
+ dibs = dibs_dev_alloc();
+ if (!dibs) {
+ ret = -ENOMEM;
+ goto err_resource;
+ }
+ ism->dibs = dibs;
+
ret = ism_dev_init(ism);
if (ret)
- goto err_resource;
+ goto err_dibs;
+
+ ret = dibs_dev_add(dibs);
+ if (ret)
+ goto err_ism;
return 0;
+err_ism:
+ ism_dev_exit(ism);
+err_dibs:
+ /* pairs with dibs_dev_alloc() */
+ kfree(dibs);
err_resource:
pci_release_mem_regions(pdev);
err_disable:
@@ -655,41 +702,15 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
}
-static void ism_dev_exit(struct ism_dev *ism)
-{
- struct pci_dev *pdev = ism->pdev;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ism->lock, flags);
- for (i = 0; i < max_client; ++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);
-
- if (ism_v2_capable)
- ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
- unregister_ieq(ism);
- unregister_sba(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)
{
struct ism_dev *ism = dev_get_drvdata(&pdev->dev);
+ struct dibs_dev *dibs = ism->dibs;
+ dibs_dev_del(dibs);
ism_dev_exit(ism);
+ /* pairs with dibs_dev_alloc() */
+ kfree(dibs);
pci_release_mem_regions(pdev);
pci_disable_device(pdev);
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 7bedeaf52c1b..c12db19c98c0 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -9,6 +9,7 @@
#ifndef _DIBS_H
#define _DIBS_H
+#include <linux/device.h>
/* DIBS - Direct Internal Buffer Sharing - concept
* -----------------------------------------------
* In the case of multiple system sharing the same hardware, dibs fabrics can
@@ -62,4 +63,41 @@ int dibs_register_client(struct dibs_client *client);
*/
int dibs_unregister_client(struct dibs_client *client);
+/* DIBS devices
+ * ------------
+ */
+struct dibs_dev {
+ struct list_head list;
+};
+
+/* ------- End of client-only functions ----------- */
+
+/*
+ * Functions to be called by dibs device drivers:
+ */
+/**
+ * dibs_dev_alloc() - allocate and reference device structure
+ *
+ * The following fields will be valid upon successful return: dev
+ * NOTE: Use put_device(dibs_get_dev(@dibs)) to give up your reference instead
+ * of freeing @dibs @dev directly once you have successfully called this
+ * function.
+ * Return: Pointer to dibs device structure
+ */
+struct dibs_dev *dibs_dev_alloc(void);
+/**
+ * dibs_dev_add() - register with dibs layer and all clients
+ * @dibs: dibs device
+ *
+ * The following fields must be valid upon entry: dev, ops, drv_priv
+ * All fields will be valid upon successful return.
+ * Return: zero on success
+ */
+int dibs_dev_add(struct dibs_dev *dibs);
+/**
+ * dibs_dev_del() - unregister from dibs layer and all clients
+ * @dibs: dibs device
+ */
+void dibs_dev_del(struct dibs_dev *dibs);
+
#endif /* _DIBS_H */
diff --git a/include/linux/ism.h b/include/linux/ism.h
index 8358b4cd7ba6..9a53d3c48c16 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -30,6 +30,7 @@ struct ism_dev {
spinlock_t lock; /* protects the ism device */
spinlock_t cmd_lock; /* serializes cmds */
struct list_head list;
+ struct dibs_dev *dibs;
struct pci_dev *pdev;
struct ism_sba *sba;
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 06/14] dibs: Define dibs loopback
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (4 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 05/14] dibs: Register ism as dibs device Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 07/14] dibs: Define dibs_client_ops and dibs_dev_ops Alexandra Winter
` (8 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
The first stage of loopback-ism was implemented as part of the
SMC module [1]. Now that we have the dibs layer, provide access to a
dibs_loopback device to all dibs clients.
This is the first step of moving loopback-ism from net/smc/smc_loopback.*
to drivers/dibs/dibs_loopback.*. One global structure lo_dev is allocated
and added to the dibs devices. Follow-on patches will move functionality.
Same as smc_loopback, dibs_loopback is provided by a config option.
Note that there is no way to dynamically add or remove the loopback
device. That could be a future improvement.
When moving code to drivers/dibs, replace ism_ prefix with dibs_ prefix.
As this is mostly a move of existing code, copyright and authors are
unchanged.
Link: https://lore.kernel.org/lkml/20240428060738.60843-1-guwen@linux.alibaba.com/ [1]
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
arch/s390/configs/debug_defconfig | 1 +
arch/s390/configs/defconfig | 1 +
drivers/dibs/Kconfig | 11 +++++
drivers/dibs/Makefile | 1 +
drivers/dibs/dibs_loopback.c | 78 +++++++++++++++++++++++++++++++
drivers/dibs/dibs_loopback.h | 38 +++++++++++++++
drivers/dibs/dibs_main.c | 11 ++++-
7 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 drivers/dibs/dibs_loopback.c
create mode 100644 drivers/dibs/dibs_loopback.h
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 7bc54f053a3b..5a2ed07b6198 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -121,6 +121,7 @@ CONFIG_UNIX_DIAG=m
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
CONFIG_DIBS=y
+CONFIG_DIBS_LO=y
CONFIG_SMC_DIAG=m
CONFIG_SMC_LO=y
CONFIG_INET=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 4bf6f3311f7d..4cbdd7e2ff9f 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -112,6 +112,7 @@ CONFIG_UNIX_DIAG=m
CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
CONFIG_DIBS=y
+CONFIG_DIBS_LO=y
CONFIG_SMC_DIAG=m
CONFIG_SMC_LO=y
CONFIG_INET=y
diff --git a/drivers/dibs/Kconfig b/drivers/dibs/Kconfig
index 09c12f6838ad..5dc347b9b235 100644
--- a/drivers/dibs/Kconfig
+++ b/drivers/dibs/Kconfig
@@ -10,3 +10,14 @@ config DIBS
Select this option to provide the abstraction layer between
dibs devices and dibs clients like the SMC protocol.
The module name is dibs.
+
+config DIBS_LO
+ bool "intra-OS shortcut with dibs loopback"
+ depends on DIBS
+ default n
+ help
+ DIBS_LO enables the creation of an software-emulated dibs device
+ named lo which can be used for transferring data when communication
+ occurs within the same OS. This helps in convenient testing of
+ dibs clients, since dibs loopback is independent of architecture or
+ hardware.
diff --git a/drivers/dibs/Makefile b/drivers/dibs/Makefile
index 825dec431bfc..85805490c77f 100644
--- a/drivers/dibs/Makefile
+++ b/drivers/dibs/Makefile
@@ -5,3 +5,4 @@
dibs-y += dibs_main.o
obj-$(CONFIG_DIBS) += dibs.o
+dibs-$(CONFIG_DIBS_LO) += dibs_loopback.o
\ No newline at end of file
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
new file mode 100644
index 000000000000..225514a452a8
--- /dev/null
+++ b/drivers/dibs/dibs_loopback.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions for dibs loopback/loopback-ism device.
+ *
+ * Copyright (c) 2024, Alibaba Inc.
+ *
+ * Author: Wen Gu <guwen@linux.alibaba.com>
+ * Tony Lu <tonylu@linux.alibaba.com>
+ *
+ */
+
+#include <linux/dibs.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "dibs_loopback.h"
+
+/* global loopback device */
+static struct dibs_lo_dev *lo_dev;
+
+static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
+{
+ dibs_dev_del(ldev->dibs);
+}
+
+static int dibs_lo_dev_probe(void)
+{
+ struct dibs_lo_dev *ldev;
+ struct dibs_dev *dibs;
+ int ret;
+
+ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return -ENOMEM;
+
+ dibs = dibs_dev_alloc();
+ if (!dibs) {
+ kfree(ldev);
+ return -ENOMEM;
+ }
+
+ ldev->dibs = dibs;
+
+ ret = dibs_dev_add(dibs);
+ if (ret)
+ goto err_reg;
+ lo_dev = ldev;
+ return 0;
+
+err_reg:
+ /* pairs with dibs_dev_alloc() */
+ kfree(dibs);
+ kfree(ldev);
+
+ return ret;
+}
+
+static void dibs_lo_dev_remove(void)
+{
+ if (!lo_dev)
+ return;
+
+ dibs_lo_dev_exit(lo_dev);
+ /* pairs with dibs_dev_alloc() */
+ kfree(lo_dev->dibs);
+ kfree(lo_dev);
+ lo_dev = NULL;
+}
+
+int dibs_loopback_init(void)
+{
+ return dibs_lo_dev_probe();
+}
+
+void dibs_loopback_exit(void)
+{
+ dibs_lo_dev_remove();
+}
diff --git a/drivers/dibs/dibs_loopback.h b/drivers/dibs/dibs_loopback.h
new file mode 100644
index 000000000000..fd03b6333a24
--- /dev/null
+++ b/drivers/dibs/dibs_loopback.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * dibs loopback (aka loopback-ism) device structure definitions.
+ *
+ * Copyright (c) 2024, Alibaba Inc.
+ *
+ * Author: Wen Gu <guwen@linux.alibaba.com>
+ * Tony Lu <tonylu@linux.alibaba.com>
+ *
+ */
+
+#ifndef _DIBS_LOOPBACK_H
+#define _DIBS_LOOPBACK_H
+
+#include <linux/dibs.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#if IS_ENABLED(CONFIG_DIBS_LO)
+
+struct dibs_lo_dev {
+ struct dibs_dev *dibs;
+};
+
+int dibs_loopback_init(void);
+void dibs_loopback_exit(void);
+#else
+static inline int dibs_loopback_init(void)
+{
+ return 0;
+}
+
+static inline void dibs_loopback_exit(void)
+{
+}
+#endif
+
+#endif /* _DIBS_LOOPBACK_H */
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index 2f420e077417..a7e33be36158 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -15,6 +15,8 @@
#include <linux/err.h>
#include <linux/dibs.h>
+#include "dibs_loopback.h"
+
MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
MODULE_LICENSE("GPL");
@@ -96,14 +98,21 @@ EXPORT_SYMBOL_GPL(dibs_dev_del);
static int __init dibs_init(void)
{
+ int rc;
+
memset(clients, 0, sizeof(clients));
max_client = 0;
- return 0;
+ rc = dibs_loopback_init();
+ if (rc)
+ pr_err("%s fails with %d\n", __func__, rc);
+
+ return rc;
}
static void __exit dibs_exit(void)
{
+ dibs_loopback_exit();
}
module_init(dibs_init);
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 07/14] dibs: Define dibs_client_ops and dibs_dev_ops
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (5 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 06/14] dibs: Define dibs loopback Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 08/14] dibs: Move struct device to dibs_dev Alexandra Winter
` (7 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Move the device add() and remove() functions from ism_client to
dibs_client_ops and call add_dev()/del_dev() for ism devices and
dibs_loopback devices. dibs_client_ops->add_dev() = smcd_register_dev() for
the smc_dibs_client. This is the first step to handle ism and loopback
devices alike (as dibs devices) in the smc dibs client.
Define dibs_dev->ops and move smcd_ops->get_chid to
dibs_dev_ops->get_fabric_id() for ism and loopback devices. See below for
why this needs to be in the same patch as dibs_client_ops->add_dev().
The following changes contain intermediate steps, that will be obsoleted by
follow-on patches, once more functionality has been moved to dibs:
Use different smcd_ops and max_dmbs for ism and loopback. Follow-on patches
will change SMC-D to directly use dibs_ops instead of smcd_ops.
In smcd_register_dev() it is now necessary to identify a dibs_loopback
device before smcd_dev and smcd_ops->get_chid() are available. So provide
dibs_dev_ops->get_fabric_id() in this patch and evaluate it in
smc_ism_is_loopback().
Call smc_loopback_init() in smcd_register_dev() and call
smc_loopback_exit() in smcd_unregister_dev() to handle the functionality
that is still in smc_loopback. Follow-on patches will move all smc_loopback
code to dibs_loopback.
In smcd_[un]register_dev() use only ism device name, this will be replaced
by dibs device name by a follow-on patch.
End of changes with intermediate parts.
Allocate an smcd event workqueue for all dibs devices, although
dibs_loopback does not generate events.
Use kernel memory instead of devres memory for smcd_dev and smcd->conn.
Since commit a72178cfe855 ("net/smc: Fix dependency of SMC on ISM") an ism
device and its driver can have a longer lifetime than the smc module, so
smc should not rely on devres to free its resources [1]. It is now the
responsibility of the smc client to free smcd and smcd->conn for all dibs
devices, ism devices as well as loopback. Call client->ops->del_dev() for
all existing dibs devices in dibs_unregister_client(), so all device
related structures can be freed in the client.
When dibs_unregister_client() is called in the context of smc_exit() or
smc_core_reboot_event(), these functions have already called
smc_lgrs_shutdown() which calls smc_smcd_terminate_all(smcd) and sets
going_away. This is done a second time in smcd_unregister_dev(). This is
analogous to how smcr is handled in these functions, by calling first
smc_lgrs_shutdown() and then smc_ib_unregister_client() >
smc_ib_remove_dev(), so leave it that way. It may be worth investigating,
whether smc_lgrs_shutdown() is still required or useful.
Remove CONFIG_SMC_LO. CONFIG_DIBS_LO now controls whether a dibs loopback
device exists or not.
Link: https://www.kernel.org/doc/Documentation/driver-model/devres.txt [1]
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
---
arch/s390/configs/debug_defconfig | 1 -
arch/s390/configs/defconfig | 1 -
drivers/dibs/dibs_loopback.c | 11 +++
drivers/dibs/dibs_main.c | 36 ++++++++
drivers/s390/net/ism_drv.c | 43 +++++-----
include/linux/dibs.h | 89 +++++++++++++++++++-
include/linux/ism.h | 2 -
include/net/smc.h | 3 +-
net/smc/Kconfig | 13 ---
net/smc/Makefile | 2 +-
net/smc/af_smc.c | 12 +--
net/smc/smc_ism.c | 132 +++++++++++++++++++++---------
net/smc/smc_ism.h | 7 +-
net/smc/smc_loopback.c | 94 ++++-----------------
net/smc/smc_loopback.h | 17 +---
15 files changed, 270 insertions(+), 193 deletions(-)
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 5a2ed07b6198..a97c8d19f643 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -123,7 +123,6 @@ CONFIG_NET_KEY=m
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
CONFIG_SMC_DIAG=m
-CONFIG_SMC_LO=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 4cbdd7e2ff9f..7f7b52d9a33c 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -114,7 +114,6 @@ CONFIG_NET_KEY=m
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
CONFIG_SMC_DIAG=m
-CONFIG_SMC_LO=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 225514a452a8..215986ae54a4 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -18,6 +18,15 @@
/* global loopback device */
static struct dibs_lo_dev *lo_dev;
+static u16 dibs_lo_get_fabric_id(struct dibs_dev *dibs)
+{
+ return DIBS_LOOPBACK_FABRIC;
+}
+
+static const struct dibs_dev_ops dibs_lo_ops = {
+ .get_fabric_id = dibs_lo_get_fabric_id,
+};
+
static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
{
dibs_dev_del(ldev->dibs);
@@ -40,6 +49,8 @@ static int dibs_lo_dev_probe(void)
}
ldev->dibs = dibs;
+ dibs->drv_priv = ldev;
+ dibs->ops = &dibs_lo_ops;
ret = dibs_dev_add(dibs);
if (ret)
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index a7e33be36158..f1cfa5849277 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -36,8 +36,10 @@ static struct dibs_dev_list dibs_dev_list = {
int dibs_register_client(struct dibs_client *client)
{
+ struct dibs_dev *dibs;
int i, rc = -ENOSPC;
+ mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
if (!clients[i]) {
@@ -51,19 +53,37 @@ int dibs_register_client(struct dibs_client *client)
}
mutex_unlock(&clients_lock);
+ if (i < MAX_DIBS_CLIENTS) {
+ /* initialize with all devices that we got so far */
+ list_for_each_entry(dibs, &dibs_dev_list.list, list) {
+ dibs->priv[i] = NULL;
+ client->ops->add_dev(dibs);
+ }
+ }
+ mutex_unlock(&dibs_dev_list.mutex);
+
return rc;
}
EXPORT_SYMBOL_GPL(dibs_register_client);
int dibs_unregister_client(struct dibs_client *client)
{
+ struct dibs_dev *dibs;
int rc = 0;
+ mutex_lock(&dibs_dev_list.mutex);
+ list_for_each_entry(dibs, &dibs_dev_list.list, list) {
+ clients[client->id]->ops->del_dev(dibs);
+ dibs->priv[client->id] = NULL;
+ }
+
mutex_lock(&clients_lock);
clients[client->id] = NULL;
if (client->id + 1 == max_client)
max_client--;
mutex_unlock(&clients_lock);
+
+ mutex_unlock(&dibs_dev_list.mutex);
return rc;
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);
@@ -80,7 +100,15 @@ EXPORT_SYMBOL_GPL(dibs_dev_alloc);
int dibs_dev_add(struct dibs_dev *dibs)
{
+ int i;
+
mutex_lock(&dibs_dev_list.mutex);
+ mutex_lock(&clients_lock);
+ for (i = 0; i < max_client; ++i) {
+ if (clients[i])
+ clients[i]->ops->add_dev(dibs);
+ }
+ mutex_unlock(&clients_lock);
list_add(&dibs->list, &dibs_dev_list.list);
mutex_unlock(&dibs_dev_list.mutex);
@@ -90,7 +118,15 @@ EXPORT_SYMBOL_GPL(dibs_dev_add);
void dibs_dev_del(struct dibs_dev *dibs)
{
+ int i;
+
mutex_lock(&dibs_dev_list.mutex);
+ mutex_lock(&clients_lock);
+ for (i = 0; i < max_client; ++i) {
+ if (clients[i])
+ clients[i]->ops->del_dev(dibs);
+ }
+ mutex_unlock(&clients_lock);
list_del_init(&dibs->list);
mutex_unlock(&dibs_dev_list.mutex);
}
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 8ecd0cccc7e8..2bd8f64ebb56 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -79,7 +79,6 @@ int ism_register_client(struct ism_client *client)
/* 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);
}
}
@@ -465,6 +464,16 @@ int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
}
EXPORT_SYMBOL_GPL(ism_move);
+static u16 ism_get_chid(struct dibs_dev *dibs)
+{
+ struct ism_dev *ism = dibs->drv_priv;
+
+ if (!ism || !ism->pdev)
+ return 0;
+
+ return to_zpci(ism->pdev)->pchid;
+}
+
static void ism_handle_event(struct ism_dev *ism)
{
struct ism_event *entry;
@@ -523,6 +532,10 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static const struct dibs_dev_ops ism_ops = {
+ .get_fabric_id = ism_get_chid,
+};
+
static int ism_dev_init(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
@@ -564,7 +577,6 @@ static int ism_dev_init(struct ism_dev *ism)
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
if (clients[i]) {
- clients[i]->add(ism);
ism_setup_forwarding(clients[i], ism);
}
}
@@ -611,12 +623,6 @@ static void ism_dev_exit(struct ism_dev *ism)
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);
if (ism_v2_capable)
ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
@@ -672,7 +678,10 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOMEM;
goto err_resource;
}
+ /* set this up before we enable interrupts */
ism->dibs = dibs;
+ dibs->drv_priv = ism;
+ dibs->ops = &ism_ops;
ret = ism_dev_init(ism);
if (ret)
@@ -857,19 +866,6 @@ static void smcd_get_local_gid(struct smcd_dev *smcd,
smcd_gid->gid_ext = 0;
}
-static u16 ism_get_chid(struct ism_dev *ism)
-{
- if (!ism || !ism->pdev)
- return 0;
-
- return to_zpci(ism->pdev)->pchid;
-}
-
-static u16 smcd_get_chid(struct smcd_dev *smcd)
-{
- return ism_get_chid(smcd->priv);
-}
-
static inline struct device *smcd_get_dev(struct smcd_dev *dev)
{
struct ism_dev *ism = dev->priv;
@@ -877,7 +873,7 @@ static inline struct device *smcd_get_dev(struct smcd_dev *dev)
return &ism->dev;
}
-static const struct smcd_ops ism_ops = {
+static const struct smcd_ops ism_smcd_ops = {
.query_remote_gid = smcd_query_rgid,
.register_dmb = smcd_register_dmb,
.unregister_dmb = smcd_unregister_dmb,
@@ -889,13 +885,12 @@ static const struct smcd_ops ism_ops = {
.move_data = smcd_move,
.supports_v2 = smcd_supports_v2,
.get_local_gid = smcd_get_local_gid,
- .get_chid = smcd_get_chid,
.get_dev = smcd_get_dev,
};
const struct smcd_ops *ism_get_smcd_ops(void)
{
- return &ism_ops;
+ return &ism_smcd_ops;
}
EXPORT_SYMBOL_GPL(ism_get_smcd_ops);
#endif
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index c12db19c98c0..805ab33271b5 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -34,14 +34,45 @@
* clients.
*/
+struct dibs_dev;
+
/* DIBS client
* -----------
*/
#define MAX_DIBS_CLIENTS 8
+/* All dibs clients have access to all dibs devices.
+ * A dibs client provides the following functions to be called by dibs layer or
+ * dibs device drivers:
+ */
+struct dibs_client_ops {
+ /**
+ * add_dev() - add a dibs device
+ * @dev: device that was added
+ *
+ * Will be called during dibs_register_client() for all existing
+ * dibs devices and whenever a new dibs device is registered.
+ * dev is usable until dibs_client.remove() is called.
+ * *dev is protected by device refcounting.
+ */
+ void (*add_dev)(struct dibs_dev *dev);
+ /**
+ * del_dev() - remove a dibs device
+ * @dev: device to be removed
+ *
+ * Will be called whenever a dibs device is removed.
+ * Will be called during dibs_unregister_client() for all existing
+ * dibs devices and whenever a dibs device is unregistered.
+ * The device has already stopped initiative for this client:
+ * No new handlers will be started.
+ * The device is no longer usable by this client after this call.
+ */
+ void (*del_dev)(struct dibs_dev *dev);
+};
struct dibs_client {
/* client name for logging and debugging purposes */
const char *name;
+ const struct dibs_client_ops *ops;
/* client index - provided and used by dibs layer */
u8 id;
};
@@ -52,6 +83,7 @@ struct dibs_client {
* dibs_register_client() - register a client with dibs layer
* @client: this client
*
+ * Will call client->ops->add_dev() for all existing dibs devices.
* Return: zero on success.
*/
int dibs_register_client(struct dibs_client *client);
@@ -59,21 +91,74 @@ int dibs_register_client(struct dibs_client *client);
* dibs_unregister_client() - unregister a client with dibs layer
* @client: this client
*
+ * Will call client->ops->del_dev() for all existing dibs devices.
* Return: zero on success.
*/
int dibs_unregister_client(struct dibs_client *client);
+/* dibs clients can call dibs device ops. */
+
/* DIBS devices
* ------------
*/
+
+/* Defined fabric id / CHID for all loopback devices:
+ * All dibs loopback devices report this fabric id. In this case devices with
+ * the same fabric id can NOT communicate via dibs. Only loopback devices with
+ * the same dibs device gid can communicate (=same device with itself).
+ */
+#define DIBS_LOOPBACK_FABRIC 0xFFFF
+
+/* A dibs device provides the following functions to be called by dibs clients.
+ * They are mandatory, unless marked 'optional'.
+ */
+struct dibs_dev_ops {
+ /**
+ * get_fabric_id()
+ * @dev: local dibs device
+ *
+ * Only devices on the same dibs fabric can communicate. Fabric_id is
+ * unique inside the same HW system. Use fabric_id for fast negative
+ * checks, but only query_remote_gid() can give a reliable positive
+ * answer:
+ * Different fabric_id: dibs is not possible
+ * Same fabric_id: dibs may be possible or not
+ * (e.g. different HW systems)
+ * EXCEPTION: DIBS_LOOPBACK_FABRIC denotes an ism_loopback device
+ * that can only communicate with itself. Use dibs_dev.gid
+ * or query_remote_gid()to determine whether sender and
+ * receiver use the same ism_loopback device.
+ * Return: 2 byte dibs fabric id
+ */
+ u16 (*get_fabric_id)(struct dibs_dev *dev);
+};
+
struct dibs_dev {
struct list_head list;
+ /* To be filled by device driver, before calling dibs_dev_add(): */
+ const struct dibs_dev_ops *ops;
+ /* priv pointer for device driver */
+ void *drv_priv;
+
+ /* priv pointer per client; for client usage only */
+ void *priv[MAX_DIBS_CLIENTS];
};
+static inline void dibs_set_priv(struct dibs_dev *dev,
+ struct dibs_client *client, void *priv)
+{
+ dev->priv[client->id] = priv;
+}
+
+static inline void *dibs_get_priv(struct dibs_dev *dev,
+ struct dibs_client *client)
+{
+ return dev->priv[client->id];
+}
+
/* ------- End of client-only functions ----------- */
-/*
- * Functions to be called by dibs device drivers:
+/* Functions to be called by dibs device drivers:
*/
/**
* dibs_dev_alloc() - allocate and reference device structure
diff --git a/include/linux/ism.h b/include/linux/ism.h
index 9a53d3c48c16..c818a25996db 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -59,8 +59,6 @@ struct ism_event {
struct ism_client {
const char *name;
- void (*add)(struct ism_dev *dev);
- void (*remove)(struct ism_dev *dev);
void (*handle_event)(struct ism_dev *dev, struct ism_event *event);
/* Parameter dmbemask contains a bit vector with updated DMBEs, if sent
* via ism_move_data(). Callback function must handle all active bits
diff --git a/include/net/smc.h b/include/net/smc.h
index a9c023dd1380..e271891b85e6 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
+#include <linux/dibs.h>
#include "linux/ism.h"
struct sock;
@@ -62,7 +63,6 @@ struct smcd_ops {
unsigned int size);
int (*supports_v2)(void);
void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
- u16 (*get_chid)(struct smcd_dev *dev);
struct device* (*get_dev)(struct smcd_dev *dev);
/* optional operations */
@@ -81,6 +81,7 @@ struct smcd_dev {
const struct smcd_ops *ops;
void *priv;
void *client;
+ struct dibs_dev *dibs;
struct list_head list;
spinlock_t lock;
struct smc_connection **conn;
diff --git a/net/smc/Kconfig b/net/smc/Kconfig
index 40dd60c1d23f..9535d88c2acb 100644
--- a/net/smc/Kconfig
+++ b/net/smc/Kconfig
@@ -20,16 +20,3 @@ config SMC_DIAG
smcss.
if unsure, say Y.
-
-config SMC_LO
- bool "SMC intra-OS shortcut with loopback-ism"
- depends on SMC
- default n
- help
- SMC_LO enables the creation of an Emulated-ISM device named
- loopback-ism in SMC and makes use of it for transferring data
- when communication occurs within the same OS. This helps in
- convenient testing of SMC-D since loopback-ism is independent
- of architecture or hardware.
-
- if unsure, say N.
diff --git a/net/smc/Makefile b/net/smc/Makefile
index 60f1c87d5212..96ccfdf246df 100644
--- a/net/smc/Makefile
+++ b/net/smc/Makefile
@@ -6,4 +6,4 @@ smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o
smc-y += smc_tracepoint.o smc_inet.o
smc-$(CONFIG_SYSCTL) += smc_sysctl.o
-smc-$(CONFIG_SMC_LO) += smc_loopback.o
+smc-y += smc_loopback.o
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index a7187e5873ec..1ea54c09b3ac 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -57,7 +57,6 @@
#include "smc_stats.h"
#include "smc_tracepoint.h"
#include "smc_sysctl.h"
-#include "smc_loopback.h"
#include "smc_inet.h"
static DEFINE_MUTEX(smc_server_lgr_pending); /* serialize link group
@@ -3591,16 +3590,10 @@ static int __init smc_init(void)
goto out_sock;
}
- rc = smc_loopback_init();
- if (rc) {
- pr_err("%s: smc_loopback_init fails with %d\n", __func__, rc);
- goto out_ib;
- }
-
rc = tcp_register_ulp(&smc_ulp_ops);
if (rc) {
pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc);
- goto out_lo;
+ goto out_ib;
}
rc = smc_inet_init();
if (rc) {
@@ -3611,8 +3604,6 @@ static int __init smc_init(void)
return 0;
out_ulp:
tcp_unregister_ulp(&smc_ulp_ops);
-out_lo:
- smc_loopback_exit();
out_ib:
smc_ib_unregister_client();
out_sock:
@@ -3651,7 +3642,6 @@ static void __exit smc_exit(void)
tcp_unregister_ulp(&smc_ulp_ops);
sock_unregister(PF_SMC);
smc_core_exit();
- smc_loopback_exit();
smc_ib_unregister_client();
smc_ism_exit();
destroy_workqueue(smc_close_wq);
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index a7a965e3c0ce..415f03910c91 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -15,6 +15,7 @@
#include "smc.h"
#include "smc_core.h"
#include "smc_ism.h"
+#include "smc_loopback.h"
#include "smc_pnet.h"
#include "smc_netlink.h"
#include "linux/ism.h"
@@ -28,23 +29,27 @@ struct smcd_dev_list smcd_dev_list = {
static bool smc_ism_v2_capable;
static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN];
+static void smcd_register_dev(struct dibs_dev *dibs);
+static void smcd_unregister_dev(struct dibs_dev *dibs);
#if IS_ENABLED(CONFIG_ISM)
-static void smcd_register_dev(struct ism_dev *ism);
-static void smcd_unregister_dev(struct ism_dev *ism);
static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event);
static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
u16 dmbemask);
static struct ism_client smc_ism_client = {
.name = "SMC-D",
- .add = smcd_register_dev,
- .remove = smcd_unregister_dev,
.handle_event = smcd_handle_event,
.handle_irq = smcd_handle_irq,
};
#endif
+static struct dibs_client_ops smc_client_ops = {
+ .add_dev = smcd_register_dev,
+ .del_dev = smcd_unregister_dev,
+};
+
static struct dibs_client smc_dibs_client = {
.name = "SMC-D",
+ .ops = &smc_client_ops,
};
static void smc_ism_create_system_eid(void)
@@ -86,7 +91,7 @@ void smc_ism_get_system_eid(u8 **eid)
u16 smc_ism_get_chid(struct smcd_dev *smcd)
{
- return smcd->ops->get_chid(smcd);
+ return smcd->dibs->ops->get_fabric_id(smcd->dibs);
}
/* HW supports ISM V2 and thus System EID is defined */
@@ -318,7 +323,7 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0))
goto errattr;
memset(&smc_pci_dev, 0, sizeof(smc_pci_dev));
- smc_set_pci_values(to_pci_dev(ism->dev.parent), &smc_pci_dev);
+ smc_set_pci_values(ism->pdev, &smc_pci_dev);
if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid))
goto errattr;
if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid))
@@ -368,7 +373,7 @@ static void smc_nl_prep_smcd_dev(struct smcd_dev_list *dev_list,
list_for_each_entry(smcd, &dev_list->list, list) {
if (num < snum)
goto next;
- if (smc_ism_is_loopback(smcd))
+ if (smc_ism_is_loopback(smcd->dibs))
goto next;
if (smc_nl_handle_smcd_dev(smcd, skb, cb))
goto errout;
@@ -453,24 +458,26 @@ static void smc_ism_event_work(struct work_struct *work)
}
kfree(wrk);
}
+#endif
-static struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
- const struct smcd_ops *ops, int max_dmbs)
+static struct smcd_dev *smcd_alloc_dev(const char *name,
+ const struct smcd_ops *ops,
+ int max_dmbs)
{
struct smcd_dev *smcd;
- smcd = devm_kzalloc(parent, sizeof(*smcd), GFP_KERNEL);
+ smcd = kzalloc(sizeof(*smcd), GFP_KERNEL);
if (!smcd)
return NULL;
- smcd->conn = devm_kcalloc(parent, max_dmbs,
- sizeof(struct smc_connection *), GFP_KERNEL);
+ smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *),
+ GFP_KERNEL);
if (!smcd->conn)
- return NULL;
+ goto free_smcd;
smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)",
WQ_MEM_RECLAIM, name);
if (!smcd->event_wq)
- return NULL;
+ goto free_conn;
smcd->ops = ops;
@@ -480,27 +487,58 @@ static struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
INIT_LIST_HEAD(&smcd->lgr_list);
init_waitqueue_head(&smcd->lgrs_deleted);
return smcd;
+
+free_conn:
+ kfree(smcd->conn);
+free_smcd:
+ kfree(smcd);
+ return NULL;
}
-static void smcd_register_dev(struct ism_dev *ism)
+static void smcd_register_dev(struct dibs_dev *dibs)
{
- const struct smcd_ops *ops = ism_get_smcd_ops();
struct smcd_dev *smcd, *fentry;
+ const struct smcd_ops *ops;
+ struct smc_lo_dev *smc_lo;
+ struct ism_dev *ism;
- if (!ops)
- return;
+ if (smc_ism_is_loopback(dibs)) {
+ if (smc_loopback_init(&smc_lo))
+ return;
+ }
- smcd = smcd_alloc_dev(&ism->pdev->dev, dev_name(&ism->pdev->dev), ops,
- ISM_NR_DMBS);
+ if (smc_ism_is_loopback(dibs)) {
+ ops = smc_lo_get_smcd_ops();
+ smcd = smcd_alloc_dev(dev_name(&smc_lo->dev), ops,
+ SMC_LO_MAX_DMBS);
+ } else {
+ ism = dibs->drv_priv;
+#if IS_ENABLED(CONFIG_ISM)
+ ops = ism_get_smcd_ops();
+#endif
+ smcd = smcd_alloc_dev(dev_name(&ism->pdev->dev), ops,
+ ISM_NR_DMBS);
+ }
if (!smcd)
return;
- smcd->priv = ism;
- smcd->client = &smc_ism_client;
- ism_set_priv(ism, &smc_ism_client, smcd);
- if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid))
- smc_pnetid_by_table_smcd(smcd);
- if (smcd->ops->supports_v2())
+ smcd->dibs = dibs;
+ dibs_set_priv(dibs, &smc_dibs_client, smcd);
+
+ if (smc_ism_is_loopback(dibs)) {
+ smcd->priv = smc_lo;
+ smc_lo->smcd = smcd;
+ } else {
+ smcd->priv = ism;
+#if IS_ENABLED(CONFIG_ISM)
+ ism_set_priv(ism, &smc_ism_client, smcd);
+ smcd->client = &smc_ism_client;
+#endif
+ if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid))
+ smc_pnetid_by_table_smcd(smcd);
+ }
+
+ if (smc_ism_is_loopback(dibs) || smcd->ops->supports_v2())
smc_ism_set_v2_capable();
mutex_lock(&smcd_dev_list.mutex);
/* sort list:
@@ -510,7 +548,7 @@ static void smcd_register_dev(struct ism_dev *ism)
if (!smcd->pnetid[0]) {
fentry = list_first_entry_or_null(&smcd_dev_list.list,
struct smcd_dev, list);
- if (fentry && smc_ism_is_loopback(fentry))
+ if (fentry && smc_ism_is_loopback(fentry->dibs))
list_add(&smcd->list, &fentry->list);
else
list_add(&smcd->list, &smcd_dev_list.list);
@@ -519,32 +557,46 @@ static void smcd_register_dev(struct ism_dev *ism)
}
mutex_unlock(&smcd_dev_list.mutex);
- if (smc_pnet_is_pnetid_set(smcd->pnetid))
- pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
- dev_name(&ism->dev), smcd->pnetid,
- smcd->pnetid_by_user ?
- " (user defined)" :
- "");
- else
- pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n",
- dev_name(&ism->dev));
+ if (smc_ism_is_loopback(dibs)) {
+ pr_warn_ratelimited("smc: adding smcd loopback device\n");
+ } else {
+ if (smc_pnet_is_pnetid_set(smcd->pnetid))
+ pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
+ dev_name(&ism->dev), smcd->pnetid,
+ smcd->pnetid_by_user ?
+ " (user defined)" :
+ "");
+ else
+ pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n",
+ dev_name(&ism->dev));
+ }
return;
}
-static void smcd_unregister_dev(struct ism_dev *ism)
+static void smcd_unregister_dev(struct dibs_dev *dibs)
{
- struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
+ struct smcd_dev *smcd = dibs_get_priv(dibs, &smc_dibs_client);
+ struct ism_dev *ism = dibs->drv_priv;
- pr_warn_ratelimited("smc: removing smcd device %s\n",
- dev_name(&ism->dev));
+ if (smc_ism_is_loopback(dibs)) {
+ pr_warn_ratelimited("smc: removing smcd loopback device\n");
+ } else {
+ pr_warn_ratelimited("smc: removing smcd device %s\n",
+ dev_name(&ism->dev));
+ }
smcd->going_away = 1;
smc_smcd_terminate_all(smcd);
mutex_lock(&smcd_dev_list.mutex);
list_del_init(&smcd->list);
mutex_unlock(&smcd_dev_list.mutex);
destroy_workqueue(smcd->event_wq);
+ if (smc_ism_is_loopback(dibs))
+ smc_loopback_exit();
+ kfree(smcd->conn);
+ kfree(smcd);
}
+#if IS_ENABLED(CONFIG_ISM)
/* SMCD Device event handler. Called from ISM device interrupt handler.
* Parameters are ism device pointer,
* - event->type (0 --> DMB, 1 --> GID),
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 765aa8fae6fa..04699951d03f 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -12,6 +12,7 @@
#include <linux/uio.h>
#include <linux/types.h>
#include <linux/mutex.h>
+#include <linux/dibs.h>
#include "smc.h"
@@ -85,14 +86,14 @@ static inline bool __smc_ism_is_emulated(u16 chid)
static inline bool smc_ism_is_emulated(struct smcd_dev *smcd)
{
- u16 chid = smcd->ops->get_chid(smcd);
+ u16 chid = smcd->dibs->ops->get_fabric_id(smcd->dibs);
return __smc_ism_is_emulated(chid);
}
-static inline bool smc_ism_is_loopback(struct smcd_dev *smcd)
+static inline bool smc_ism_is_loopback(struct dibs_dev *dibs)
{
- return (smcd->ops->get_chid(smcd) == 0xFFFF);
+ return (dibs->ops->get_fabric_id(dibs) == DIBS_LOOPBACK_FABRIC);
}
#endif
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 1853c26fbbbb..37d8366419f7 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -35,8 +35,6 @@ static void smc_lo_generate_ids(struct smc_lo_dev *ldev)
memcpy(&lgid->gid, &uuid, sizeof(lgid->gid));
memcpy(&lgid->gid_ext, (u8 *)&uuid + sizeof(lgid->gid),
sizeof(lgid->gid_ext));
-
- ldev->chid = SMC_LO_RESERVED_CHID;
}
static int smc_lo_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
@@ -257,11 +255,6 @@ static void smc_lo_get_local_gid(struct smcd_dev *smcd,
smcd_gid->gid_ext = ldev->local_gid.gid_ext;
}
-static u16 smc_lo_get_chid(struct smcd_dev *smcd)
-{
- return ((struct smc_lo_dev *)smcd->priv)->chid;
-}
-
static struct device *smc_lo_get_dev(struct smcd_dev *smcd)
{
return &((struct smc_lo_dev *)smcd->priv)->dev;
@@ -281,72 +274,15 @@ static const struct smcd_ops lo_ops = {
.signal_event = NULL,
.move_data = smc_lo_move_data,
.get_local_gid = smc_lo_get_local_gid,
- .get_chid = smc_lo_get_chid,
.get_dev = smc_lo_get_dev,
};
-static struct smcd_dev *smcd_lo_alloc_dev(const struct smcd_ops *ops,
- int max_dmbs)
-{
- struct smcd_dev *smcd;
-
- smcd = kzalloc(sizeof(*smcd), GFP_KERNEL);
- if (!smcd)
- return NULL;
-
- smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *),
- GFP_KERNEL);
- if (!smcd->conn)
- goto out_smcd;
-
- smcd->ops = ops;
-
- spin_lock_init(&smcd->lock);
- spin_lock_init(&smcd->lgr_lock);
- INIT_LIST_HEAD(&smcd->vlan);
- INIT_LIST_HEAD(&smcd->lgr_list);
- init_waitqueue_head(&smcd->lgrs_deleted);
- return smcd;
-
-out_smcd:
- kfree(smcd);
- return NULL;
-}
-
-static int smcd_lo_register_dev(struct smc_lo_dev *ldev)
-{
- struct smcd_dev *smcd;
-
- smcd = smcd_lo_alloc_dev(&lo_ops, SMC_LO_MAX_DMBS);
- if (!smcd)
- return -ENOMEM;
- ldev->smcd = smcd;
- smcd->priv = ldev;
- smc_ism_set_v2_capable();
- mutex_lock(&smcd_dev_list.mutex);
- list_add(&smcd->list, &smcd_dev_list.list);
- mutex_unlock(&smcd_dev_list.mutex);
- pr_warn_ratelimited("smc: adding smcd device %s\n",
- dev_name(&ldev->dev));
- return 0;
-}
-
-static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev)
+const struct smcd_ops *smc_lo_get_smcd_ops(void)
{
- struct smcd_dev *smcd = ldev->smcd;
-
- pr_warn_ratelimited("smc: removing smcd device %s\n",
- dev_name(&ldev->dev));
- smcd->going_away = 1;
- smc_smcd_terminate_all(smcd);
- mutex_lock(&smcd_dev_list.mutex);
- list_del_init(&smcd->list);
- mutex_unlock(&smcd_dev_list.mutex);
- kfree(smcd->conn);
- kfree(smcd);
+ return &lo_ops;
}
-static int smc_lo_dev_init(struct smc_lo_dev *ldev)
+static void smc_lo_dev_init(struct smc_lo_dev *ldev)
{
smc_lo_generate_ids(ldev);
rwlock_init(&ldev->dmb_ht_lock);
@@ -354,12 +290,11 @@ static int smc_lo_dev_init(struct smc_lo_dev *ldev)
atomic_set(&ldev->dmb_cnt, 0);
init_waitqueue_head(&ldev->ldev_release);
- return smcd_lo_register_dev(ldev);
+ return;
}
static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
{
- smcd_lo_unregister_dev(ldev);
if (atomic_read(&ldev->dmb_cnt))
wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
}
@@ -375,7 +310,6 @@ static void smc_lo_dev_release(struct device *dev)
static int smc_lo_dev_probe(void)
{
struct smc_lo_dev *ldev;
- int ret;
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev)
@@ -385,17 +319,11 @@ static int smc_lo_dev_probe(void)
ldev->dev.release = smc_lo_dev_release;
device_initialize(&ldev->dev);
dev_set_name(&ldev->dev, smc_lo_dev_name);
-
- ret = smc_lo_dev_init(ldev);
- if (ret)
- goto free_dev;
+ smc_lo_dev_init(ldev);
lo_dev = ldev; /* global loopback device */
- return 0;
-free_dev:
- put_device(&ldev->dev);
- return ret;
+ return 0;
}
static void smc_lo_dev_remove(void)
@@ -405,11 +333,17 @@ static void smc_lo_dev_remove(void)
smc_lo_dev_exit(lo_dev);
put_device(&lo_dev->dev); /* device_initialize in smc_lo_dev_probe */
+ lo_dev = NULL;
}
-int smc_loopback_init(void)
+int smc_loopback_init(struct smc_lo_dev **smc_lb)
{
- return smc_lo_dev_probe();
+ int ret;
+
+ ret = smc_lo_dev_probe();
+ if (!ret)
+ *smc_lb = lo_dev;
+ return ret;
}
void smc_loopback_exit(void)
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
index 04dc6808d2e1..76c62526e2e5 100644
--- a/net/smc/smc_loopback.h
+++ b/net/smc/smc_loopback.h
@@ -17,10 +17,8 @@
#include <linux/device.h>
#include <net/smc.h>
-#if IS_ENABLED(CONFIG_SMC_LO)
#define SMC_LO_MAX_DMBS 5000
#define SMC_LO_DMBS_HASH_BITS 12
-#define SMC_LO_RESERVED_CHID 0xFFFF
struct smc_lo_dmb_node {
struct hlist_node list;
@@ -35,7 +33,6 @@ struct smc_lo_dmb_node {
struct smc_lo_dev {
struct smcd_dev *smcd;
struct device dev;
- u16 chid;
struct smcd_gid local_gid;
atomic_t dmb_cnt;
rwlock_t dmb_ht_lock;
@@ -44,17 +41,9 @@ struct smc_lo_dev {
wait_queue_head_t ldev_release;
};
-int smc_loopback_init(void);
+const struct smcd_ops *smc_lo_get_smcd_ops(void);
+
+int smc_loopback_init(struct smc_lo_dev **smc_lb);
void smc_loopback_exit(void);
-#else
-static inline int smc_loopback_init(void)
-{
- return 0;
-}
-
-static inline void smc_loopback_exit(void)
-{
-}
-#endif
#endif /* _SMC_LOOPBACK_H */
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 08/14] dibs: Move struct device to dibs_dev
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (6 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 07/14] dibs: Define dibs_client_ops and dibs_dev_ops Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 09/14] dibs: Create class dibs Alexandra Winter
` (6 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
From: Julian Ruess <julianr@linux.ibm.com>
Move struct device from ism_dev and smc_lo_dev to dibs_dev, and define a
corresponding release function. Free ism_dev in ism_remove() and smc_lo_dev
in smc_lo_dev_remove().
Replace smcd->ops->get_dev(smcd) by using dibs->dev directly.
An alternative design would be to embed dibs_dev as a field in ism_dev and
do the same for other dibs device driver specific structs. However that
would have the disadvantage that each dibs device driver needs to allocate
dibs_dev and each dibs device driver needs a different device release
function. The advantage would be that ism_dev and other device driver
specific structs would be covered by device reference counts.
Signed-off-by: Julian Ruess <julianr@linux.ibm.com>
Co-developed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
---
drivers/dibs/dibs_loopback.c | 15 ++++++------
drivers/dibs/dibs_main.c | 21 +++++++++++++++-
drivers/s390/net/ism_drv.c | 40 +++++++------------------------
include/linux/dibs.h | 1 +
include/linux/ism.h | 1 -
include/net/smc.h | 1 -
net/smc/smc_core.c | 4 ++--
net/smc/smc_ism.c | 46 +++++++++++++++---------------------
net/smc/smc_loopback.c | 21 +---------------
net/smc/smc_loopback.h | 1 -
net/smc/smc_pnet.c | 13 ++++------
11 files changed, 63 insertions(+), 101 deletions(-)
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 215986ae54a4..76e479d5724b 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -15,6 +15,7 @@
#include "dibs_loopback.h"
+static const char dibs_lo_dev_name[] = "lo";
/* global loopback device */
static struct dibs_lo_dev *lo_dev;
@@ -27,11 +28,6 @@ static const struct dibs_dev_ops dibs_lo_ops = {
.get_fabric_id = dibs_lo_get_fabric_id,
};
-static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
-{
- dibs_dev_del(ldev->dibs);
-}
-
static int dibs_lo_dev_probe(void)
{
struct dibs_lo_dev *ldev;
@@ -52,6 +48,9 @@ static int dibs_lo_dev_probe(void)
dibs->drv_priv = ldev;
dibs->ops = &dibs_lo_ops;
+ dibs->dev.parent = NULL;
+ dev_set_name(&dibs->dev, "%s", dibs_lo_dev_name);
+
ret = dibs_dev_add(dibs);
if (ret)
goto err_reg;
@@ -60,7 +59,7 @@ static int dibs_lo_dev_probe(void)
err_reg:
/* pairs with dibs_dev_alloc() */
- kfree(dibs);
+ put_device(&dibs->dev);
kfree(ldev);
return ret;
@@ -71,9 +70,9 @@ static void dibs_lo_dev_remove(void)
if (!lo_dev)
return;
- dibs_lo_dev_exit(lo_dev);
+ dibs_dev_del(lo_dev->dibs);
/* pairs with dibs_dev_alloc() */
- kfree(lo_dev->dibs);
+ put_device(&lo_dev->dibs->dev);
kfree(lo_dev);
lo_dev = NULL;
}
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index f1cfa5849277..610b6c452211 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -88,11 +88,24 @@ int dibs_unregister_client(struct dibs_client *client)
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);
+static void dibs_dev_release(struct device *dev)
+{
+ struct dibs_dev *dibs;
+
+ dibs = container_of(dev, struct dibs_dev, dev);
+
+ kfree(dibs);
+}
+
struct dibs_dev *dibs_dev_alloc(void)
{
struct dibs_dev *dibs;
dibs = kzalloc(sizeof(*dibs), GFP_KERNEL);
+ if (!dibs)
+ return dibs;
+ dibs->dev.release = dibs_dev_release;
+ device_initialize(&dibs->dev);
return dibs;
}
@@ -100,7 +113,11 @@ EXPORT_SYMBOL_GPL(dibs_dev_alloc);
int dibs_dev_add(struct dibs_dev *dibs)
{
- int i;
+ int i, ret;
+
+ ret = device_add(&dibs->dev);
+ if (ret)
+ return ret;
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
@@ -129,6 +146,8 @@ void dibs_dev_del(struct dibs_dev *dibs)
mutex_unlock(&clients_lock);
list_del_init(&dibs->list);
mutex_unlock(&dibs_dev_list.mutex);
+
+ device_del(&dibs->dev);
}
EXPORT_SYMBOL_GPL(dibs_dev_del);
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 2bd8f64ebb56..4096ea9faa7e 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -602,15 +602,6 @@ static int ism_dev_init(struct ism_dev *ism)
return ret;
}
-static void ism_dev_release(struct device *dev)
-{
- struct ism_dev *ism;
-
- ism = container_of(dev, struct ism_dev, dev);
-
- kfree(ism);
-}
-
static void ism_dev_exit(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
@@ -649,17 +640,10 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ism->cmd_lock);
dev_set_drvdata(&pdev->dev, ism);
ism->pdev = pdev;
- ism->dev.parent = &pdev->dev;
- ism->dev.release = ism_dev_release;
- device_initialize(&ism->dev);
- dev_set_name(&ism->dev, "%s", dev_name(&pdev->dev));
- ret = device_add(&ism->dev);
- if (ret)
- goto err_dev;
ret = pci_enable_device_mem(pdev);
if (ret)
- goto err;
+ goto err_dev;
ret = pci_request_mem_regions(pdev, DRV_NAME);
if (ret)
@@ -687,6 +671,9 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_dibs;
+ dibs->dev.parent = &pdev->dev;
+ dev_set_name(&dibs->dev, "%s", dev_name(&pdev->dev));
+
ret = dibs_dev_add(dibs);
if (ret)
goto err_ism;
@@ -697,16 +684,14 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ism_dev_exit(ism);
err_dibs:
/* pairs with dibs_dev_alloc() */
- kfree(dibs);
+ put_device(&dibs->dev);
err_resource:
pci_release_mem_regions(pdev);
err_disable:
pci_disable_device(pdev);
-err:
- device_del(&ism->dev);
err_dev:
dev_set_drvdata(&pdev->dev, NULL);
- put_device(&ism->dev);
+ kfree(ism);
return ret;
}
@@ -719,13 +704,12 @@ static void ism_remove(struct pci_dev *pdev)
dibs_dev_del(dibs);
ism_dev_exit(ism);
/* pairs with dibs_dev_alloc() */
- kfree(dibs);
+ put_device(&dibs->dev);
pci_release_mem_regions(pdev);
pci_disable_device(pdev);
- device_del(&ism->dev);
dev_set_drvdata(&pdev->dev, NULL);
- put_device(&ism->dev);
+ kfree(ism);
}
static struct pci_driver ism_driver = {
@@ -866,13 +850,6 @@ static void smcd_get_local_gid(struct smcd_dev *smcd,
smcd_gid->gid_ext = 0;
}
-static inline struct device *smcd_get_dev(struct smcd_dev *dev)
-{
- struct ism_dev *ism = dev->priv;
-
- return &ism->dev;
-}
-
static const struct smcd_ops ism_smcd_ops = {
.query_remote_gid = smcd_query_rgid,
.register_dmb = smcd_register_dmb,
@@ -885,7 +862,6 @@ static const struct smcd_ops ism_smcd_ops = {
.move_data = smcd_move,
.supports_v2 = smcd_supports_v2,
.get_local_gid = smcd_get_local_gid,
- .get_dev = smcd_get_dev,
};
const struct smcd_ops *ism_get_smcd_ops(void)
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 805ab33271b5..793c6e1ece0f 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -135,6 +135,7 @@ struct dibs_dev_ops {
struct dibs_dev {
struct list_head list;
+ struct device dev;
/* To be filled by device driver, before calling dibs_dev_add(): */
const struct dibs_dev_ops *ops;
/* priv pointer for device driver */
diff --git a/include/linux/ism.h b/include/linux/ism.h
index c818a25996db..84f1afb3dded 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -42,7 +42,6 @@ struct ism_dev {
struct ism_eq *ieq;
dma_addr_t ieq_dma_addr;
- struct device dev;
u64 local_gid;
int ieq_idx;
diff --git a/include/net/smc.h b/include/net/smc.h
index e271891b85e6..05faac83371e 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -63,7 +63,6 @@ struct smcd_ops {
unsigned int size);
int (*supports_v2)(void);
void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
- struct device* (*get_dev)(struct smcd_dev *dev);
/* optional operations */
int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 2a559a98541c..585e86890ff7 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -924,7 +924,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
if (ini->is_smcd) {
/* SMC-D specific settings */
smcd = ini->ism_dev[ini->ism_selected];
- get_device(smcd->ops->get_dev(smcd));
+ get_device(&smcd->dibs->dev);
lgr->peer_gid.gid =
ini->ism_peer_gid[ini->ism_selected].gid;
lgr->peer_gid.gid_ext =
@@ -1474,7 +1474,7 @@ static void smc_lgr_free(struct smc_link_group *lgr)
destroy_workqueue(lgr->tx_wq);
if (lgr->is_smcd) {
smc_ism_put_vlan(lgr->smcd, lgr->vlan_id);
- put_device(lgr->smcd->ops->get_dev(lgr->smcd));
+ put_device(&lgr->smcd->dibs->dev);
}
smc_lgr_put(lgr); /* theoretically last lgr_put */
}
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 415f03910c91..6a6e7c9641e8 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -303,12 +303,12 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
char smc_pnet[SMC_MAX_PNETID_LEN + 1];
struct smc_pci_dev smc_pci_dev;
struct nlattr *port_attrs;
+ struct dibs_dev *dibs;
struct nlattr *attrs;
- struct ism_dev *ism;
int use_cnt = 0;
void *nlh;
- ism = smcd->priv;
+ dibs = smcd->dibs;
nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
&smc_gen_nl_family, NLM_F_MULTI,
SMC_NETLINK_GET_DEV_SMCD);
@@ -323,7 +323,7 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0))
goto errattr;
memset(&smc_pci_dev, 0, sizeof(smc_pci_dev));
- smc_set_pci_values(ism->pdev, &smc_pci_dev);
+ smc_set_pci_values(to_pci_dev(dibs->dev.parent), &smc_pci_dev);
if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid))
goto errattr;
if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid))
@@ -509,14 +509,14 @@ static void smcd_register_dev(struct dibs_dev *dibs)
if (smc_ism_is_loopback(dibs)) {
ops = smc_lo_get_smcd_ops();
- smcd = smcd_alloc_dev(dev_name(&smc_lo->dev), ops,
+ smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops,
SMC_LO_MAX_DMBS);
} else {
ism = dibs->drv_priv;
#if IS_ENABLED(CONFIG_ISM)
ops = ism_get_smcd_ops();
#endif
- smcd = smcd_alloc_dev(dev_name(&ism->pdev->dev), ops,
+ smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops,
ISM_NR_DMBS);
}
if (!smcd)
@@ -534,10 +534,11 @@ static void smcd_register_dev(struct dibs_dev *dibs)
ism_set_priv(ism, &smc_ism_client, smcd);
smcd->client = &smc_ism_client;
#endif
- if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid))
- smc_pnetid_by_table_smcd(smcd);
}
+ if (smc_pnetid_by_dev_port(dibs->dev.parent, 0, smcd->pnetid))
+ smc_pnetid_by_table_smcd(smcd);
+
if (smc_ism_is_loopback(dibs) || smcd->ops->supports_v2())
smc_ism_set_v2_capable();
mutex_lock(&smcd_dev_list.mutex);
@@ -557,33 +558,24 @@ static void smcd_register_dev(struct dibs_dev *dibs)
}
mutex_unlock(&smcd_dev_list.mutex);
- if (smc_ism_is_loopback(dibs)) {
- pr_warn_ratelimited("smc: adding smcd loopback device\n");
- } else {
- if (smc_pnet_is_pnetid_set(smcd->pnetid))
- pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
- dev_name(&ism->dev), smcd->pnetid,
- smcd->pnetid_by_user ?
- " (user defined)" :
- "");
- else
- pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n",
- dev_name(&ism->dev));
- }
+ if (smc_pnet_is_pnetid_set(smcd->pnetid))
+ pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
+ dev_name(&dibs->dev), smcd->pnetid,
+ smcd->pnetid_by_user ?
+ " (user defined)" :
+ "");
+ else
+ pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n",
+ dev_name(&dibs->dev));
return;
}
static void smcd_unregister_dev(struct dibs_dev *dibs)
{
struct smcd_dev *smcd = dibs_get_priv(dibs, &smc_dibs_client);
- struct ism_dev *ism = dibs->drv_priv;
- if (smc_ism_is_loopback(dibs)) {
- pr_warn_ratelimited("smc: removing smcd loopback device\n");
- } else {
- pr_warn_ratelimited("smc: removing smcd device %s\n",
- dev_name(&ism->dev));
- }
+ pr_warn_ratelimited("smc: removing smcd device %s\n",
+ dev_name(&dibs->dev));
smcd->going_away = 1;
smc_smcd_terminate_all(smcd);
mutex_lock(&smcd_dev_list.mutex);
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 37d8366419f7..262d0d0df4d0 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -23,7 +23,6 @@
#define SMC_LO_SUPPORT_NOCOPY 0x1
#define SMC_DMA_ADDR_INVALID (~(dma_addr_t)0)
-static const char smc_lo_dev_name[] = "loopback-ism";
static struct smc_lo_dev *lo_dev;
static void smc_lo_generate_ids(struct smc_lo_dev *ldev)
@@ -255,11 +254,6 @@ static void smc_lo_get_local_gid(struct smcd_dev *smcd,
smcd_gid->gid_ext = ldev->local_gid.gid_ext;
}
-static struct device *smc_lo_get_dev(struct smcd_dev *smcd)
-{
- return &((struct smc_lo_dev *)smcd->priv)->dev;
-}
-
static const struct smcd_ops lo_ops = {
.query_remote_gid = smc_lo_query_rgid,
.register_dmb = smc_lo_register_dmb,
@@ -274,7 +268,6 @@ static const struct smcd_ops lo_ops = {
.signal_event = NULL,
.move_data = smc_lo_move_data,
.get_local_gid = smc_lo_get_local_gid,
- .get_dev = smc_lo_get_dev,
};
const struct smcd_ops *smc_lo_get_smcd_ops(void)
@@ -299,14 +292,6 @@ static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
}
-static void smc_lo_dev_release(struct device *dev)
-{
- struct smc_lo_dev *ldev =
- container_of(dev, struct smc_lo_dev, dev);
-
- kfree(ldev);
-}
-
static int smc_lo_dev_probe(void)
{
struct smc_lo_dev *ldev;
@@ -315,10 +300,6 @@ static int smc_lo_dev_probe(void)
if (!ldev)
return -ENOMEM;
- ldev->dev.parent = NULL;
- ldev->dev.release = smc_lo_dev_release;
- device_initialize(&ldev->dev);
- dev_set_name(&ldev->dev, smc_lo_dev_name);
smc_lo_dev_init(ldev);
lo_dev = ldev; /* global loopback device */
@@ -332,7 +313,7 @@ static void smc_lo_dev_remove(void)
return;
smc_lo_dev_exit(lo_dev);
- put_device(&lo_dev->dev); /* device_initialize in smc_lo_dev_probe */
+ kfree(lo_dev);
lo_dev = NULL;
}
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
index 76c62526e2e5..a033bf10890a 100644
--- a/net/smc/smc_loopback.h
+++ b/net/smc/smc_loopback.h
@@ -32,7 +32,6 @@ struct smc_lo_dmb_node {
struct smc_lo_dev {
struct smcd_dev *smcd;
- struct device dev;
struct smcd_gid local_gid;
atomic_t dmb_cnt;
rwlock_t dmb_ht_lock;
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 7225b5fa17a6..d0df7f2b03aa 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -169,7 +169,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
pr_warn_ratelimited("smc: smcd device %s "
"erased user defined pnetid "
"%.16s\n",
- dev_name(smcd->ops->get_dev(smcd)),
+ dev_name(&smcd->dibs->dev),
smcd->pnetid);
memset(smcd->pnetid, 0, SMC_MAX_PNETID_LEN);
smcd->pnetid_by_user = false;
@@ -332,7 +332,7 @@ static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
mutex_lock(&smcd_dev_list.mutex);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
- if (!strncmp(dev_name(smcd_dev->ops->get_dev(smcd_dev)),
+ if (!strncmp(dev_name(&smcd_dev->dibs->dev),
smcd_name, IB_DEVICE_NAME_MAX - 1))
goto out;
}
@@ -413,7 +413,6 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
bool smcddev_applied = true;
bool ibdev_applied = true;
struct smcd_dev *smcd;
- struct device *dev;
bool new_ibdev;
/* try to apply the pnetid to active devices */
@@ -431,10 +430,8 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
if (smcd) {
smcddev_applied = smc_pnet_apply_smcd(smcd, pnet_name);
if (smcddev_applied) {
- dev = smcd->ops->get_dev(smcd);
- pr_warn_ratelimited("smc: smcd device %s "
- "applied user defined pnetid "
- "%.16s\n", dev_name(dev),
+ pr_warn_ratelimited("smc: smcd device %s applied user defined pnetid %.16s\n",
+ dev_name(&smcd->dibs->dev),
smcd->pnetid);
}
}
@@ -1193,7 +1190,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
*/
int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
{
- const char *ib_name = dev_name(smcddev->ops->get_dev(smcddev));
+ const char *ib_name = dev_name(&smcddev->dibs->dev);
struct smc_pnettable *pnettable;
struct smc_pnetentry *tmp_pe;
struct smc_net *sn;
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 09/14] dibs: Create class dibs
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (7 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 08/14] dibs: Move struct device to dibs_dev Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 10/14] dibs: Local gid for dibs devices Alexandra Winter
` (5 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
From: Julian Ruess <julianr@linux.ibm.com>
Create '/sys/class/dibs' to represent multiple kinds of dibs devices in
sysfs. Show s390/ism devices as well as dibs_loopback devices.
Show attribute fabric_id using dibs_ops.get_fabric_id(). This can help
users understand which dibs devices are connected to the same fabric in
different systems and which dibs devices are loopback devices
(fabric_id 0xffff)
Instead of using the same name as the pci device, give the ism devices
their own readable names based on uid or fid from the HW definition.
smc_loopback was never visible in sysfs. dibs_loopback is now represented
as a virtual device.
For the SMC feature "software defined pnet-id" either the ib device name or
the PCI-ID (actually the parent device name) can be used for SMC-R entries.
Mimic this behaviour for SMC-D, and check the parent device name as well.
So device name or PCI-ID can be used for ism and device name can be used
for dibs-loopback. Note that this:
IB_DEVICE_NAME_MAX - 1 == smc_pnet_policy.[SMC_PNETID_IBNAME].len
is the length of smcd_name. Future SW-pnetid cleanup patches to could use a
meaningful define, but that would touch too much unrelated code here.
Examples:
---------
ism before:
> ls /sys/bus/pci/devices/0000:00:00.0/0000:00:00.0
uevent
ism now:
> ls /sys/bus/pci/devices/0000:00:00.0/dibs/ism30
device -> ../../../0000:00:00.0/
fabric_id
subsystem -> ../../../../../class/dibs/
uevent
dibs loopback:
> ls /sys/devices/virtual/dibs/lo/
fabric_id
subsystem -> ../../../../class/dibs/
uevent
dibs class:
> ls -l /sys/class/dibs/
ism30 -> ../../devices/pci0000:00/0000:00:00.0/dibs/ism30/
lo -> ../../devices/virtual/dibs/lo/
For comparison:
> ls -l /sys/class/net/
enc8410 -> ../../devices/qeth/0.0.8410/net/enc8410/
ens1693 -> ../../devices/pci0001:00/0001:00:00.0/net/ens1693/
lo -> ../../devices/virtual/net/lo/
Signed-off-by: Julian Ruess <julianr@linux.ibm.com>
Co-developed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
drivers/dibs/dibs_main.c | 40 ++++++++++++++++++++++++++++++++++++++
drivers/s390/net/ism_drv.c | 5 ++++-
net/smc/smc_pnet.c | 16 +++++++++++----
3 files changed, 56 insertions(+), 5 deletions(-)
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index 610b6c452211..b3f21805aa59 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -20,6 +20,8 @@
MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
MODULE_LICENSE("GPL");
+static struct class *dibs_class;
+
/* use an array rather a list for fast mapping: */
static struct dibs_client *clients[MAX_DIBS_CLIENTS];
static u8 max_client;
@@ -105,12 +107,35 @@ struct dibs_dev *dibs_dev_alloc(void)
if (!dibs)
return dibs;
dibs->dev.release = dibs_dev_release;
+ dibs->dev.class = dibs_class;
device_initialize(&dibs->dev);
return dibs;
}
EXPORT_SYMBOL_GPL(dibs_dev_alloc);
+static ssize_t fabric_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dibs_dev *dibs;
+ u16 fabric_id;
+
+ dibs = container_of(dev, struct dibs_dev, dev);
+ fabric_id = dibs->ops->get_fabric_id(dibs);
+
+ return sysfs_emit(buf, "0x%04x\n", fabric_id);
+}
+static DEVICE_ATTR_RO(fabric_id);
+
+static struct attribute *dibs_dev_attrs[] = {
+ &dev_attr_fabric_id.attr,
+ NULL,
+};
+
+static const struct attribute_group dibs_dev_attr_group = {
+ .attrs = dibs_dev_attrs,
+};
+
int dibs_dev_add(struct dibs_dev *dibs)
{
int i, ret;
@@ -119,6 +144,11 @@ int dibs_dev_add(struct dibs_dev *dibs)
if (ret)
return ret;
+ ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
+ if (ret) {
+ dev_err(&dibs->dev, "sysfs_create_group failed for dibs_dev\n");
+ goto err_device_del;
+ }
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
@@ -130,6 +160,11 @@ int dibs_dev_add(struct dibs_dev *dibs)
mutex_unlock(&dibs_dev_list.mutex);
return 0;
+
+err_device_del:
+ device_del(&dibs->dev);
+ return ret;
+
}
EXPORT_SYMBOL_GPL(dibs_dev_add);
@@ -158,6 +193,10 @@ static int __init dibs_init(void)
memset(clients, 0, sizeof(clients));
max_client = 0;
+ dibs_class = class_create("dibs");
+ if (IS_ERR(&dibs_class))
+ return PTR_ERR(&dibs_class);
+
rc = dibs_loopback_init();
if (rc)
pr_err("%s fails with %d\n", __func__, rc);
@@ -168,6 +207,7 @@ static int __init dibs_init(void)
static void __exit dibs_exit(void)
{
dibs_loopback_exit();
+ class_destroy(dibs_class);
}
module_init(dibs_init);
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 4096ea9faa7e..ab1d61eb3e3b 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -629,6 +629,7 @@ static void ism_dev_exit(struct ism_dev *ism)
static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct dibs_dev *dibs;
+ struct zpci_dev *zdev;
struct ism_dev *ism;
int ret;
@@ -672,7 +673,9 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_dibs;
dibs->dev.parent = &pdev->dev;
- dev_set_name(&dibs->dev, "%s", dev_name(&pdev->dev));
+
+ zdev = to_zpci(pdev);
+ dev_set_name(&dibs->dev, "ism%x", zdev->uid ? zdev->uid : zdev->fid);
ret = dibs_dev_add(dibs);
if (ret)
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index d0df7f2b03aa..a3a1e1fde8eb 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -332,8 +332,11 @@ static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
mutex_lock(&smcd_dev_list.mutex);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
- if (!strncmp(dev_name(&smcd_dev->dibs->dev),
- smcd_name, IB_DEVICE_NAME_MAX - 1))
+ if (!strncmp(dev_name(&smcd_dev->dibs->dev), smcd_name,
+ IB_DEVICE_NAME_MAX - 1) ||
+ (smcd_dev->dibs->dev.parent &&
+ !strncmp(dev_name(smcd_dev->dibs->dev.parent), smcd_name,
+ IB_DEVICE_NAME_MAX - 1)))
goto out;
}
smcd_dev = NULL;
@@ -1190,7 +1193,6 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
*/
int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
{
- const char *ib_name = dev_name(&smcddev->dibs->dev);
struct smc_pnettable *pnettable;
struct smc_pnetentry *tmp_pe;
struct smc_net *sn;
@@ -1203,7 +1205,13 @@ int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
mutex_lock(&pnettable->lock);
list_for_each_entry(tmp_pe, &pnettable->pnetlist, list) {
if (tmp_pe->type == SMC_PNET_IB &&
- !strncmp(tmp_pe->ib_name, ib_name, IB_DEVICE_NAME_MAX)) {
+ (!strncmp(tmp_pe->ib_name,
+ dev_name(&smcddev->dibs->dev),
+ sizeof(tmp_pe->ib_name)) ||
+ (smcddev->dibs->dev.parent &&
+ !strncmp(tmp_pe->ib_name,
+ dev_name(smcddev->dibs->dev.parent),
+ sizeof(tmp_pe->ib_name))))) {
smc_pnet_apply_smcd(smcddev, tmp_pe->pnet_name);
rc = 0;
break;
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 10/14] dibs: Local gid for dibs devices
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (8 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 09/14] dibs: Create class dibs Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 11/14] dibs: Move vlan support to dibs_dev_ops Alexandra Winter
` (4 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Define a uuid_t GID attribute to identify a dibs device.
SMC uses 64 Bit and 128 Bit Global Identifiers (GIDs) per device, that
need to be sent via the SMC protocol. Because the smc code uses integers,
network endianness and host endianness need to be considered. Avoid this
in the dibs layer by using uuid_t byte arrays. Future patches could change
SMC to use uuid_t. For now conversion helper functions are introduced.
ISM devices provide 64 Bit GIDs. Map them to dibs uuid_t GIDs like this:
_________________________________________
| 64 Bit ISM-vPCI GID | 00000000_00000000 |
-----------------------------------------
If interpreted as UUID [1], this would be interpreted as the UIID variant,
that is reserved for NCS backward compatibility. So it will not collide
with UUIDs that were generated according to the standard.
smc_loopback already uses version 4 UUIDs as 128 Bit GIDs, move that to
dibs loopback. A temporary change to smc_lo_query_rgid() is required,
that will be moved to dibs_loopback with a follow-on patch.
Provide gid of a dibs device as sysfs read-only attribute.
Link: https://datatracker.ietf.org/doc/html/rfc4122 [1]
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
---
drivers/dibs/dibs_loopback.c | 1 +
drivers/dibs/dibs_main.c | 12 ++++++++++++
drivers/s390/net/ism.h | 9 +++++++++
drivers/s390/net/ism_drv.c | 30 +++++++++---------------------
include/linux/dibs.h | 3 +++
include/linux/ism.h | 1 -
include/net/smc.h | 1 -
net/smc/smc_clc.c | 6 +++---
net/smc/smc_core.c | 2 +-
net/smc/smc_diag.c | 2 +-
net/smc/smc_ism.h | 22 ++++++++++++++++++++++
net/smc/smc_loopback.c | 29 ++++-------------------------
net/smc/smc_loopback.h | 1 -
13 files changed, 65 insertions(+), 54 deletions(-)
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 76e479d5724b..d7e6fa5e90f3 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -46,6 +46,7 @@ static int dibs_lo_dev_probe(void)
ldev->dibs = dibs;
dibs->drv_priv = ldev;
+ uuid_gen(&dibs->gid);
dibs->ops = &dibs_lo_ops;
dibs->dev.parent = NULL;
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index b3f21805aa59..f20ed0594a51 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -114,6 +114,17 @@ struct dibs_dev *dibs_dev_alloc(void)
}
EXPORT_SYMBOL_GPL(dibs_dev_alloc);
+static ssize_t gid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dibs_dev *dibs;
+
+ dibs = container_of(dev, struct dibs_dev, dev);
+
+ return sysfs_emit(buf, "%pUb\n", &dibs->gid);
+}
+static DEVICE_ATTR_RO(gid);
+
static ssize_t fabric_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -128,6 +139,7 @@ static ssize_t fabric_id_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(fabric_id);
static struct attribute *dibs_dev_attrs[] = {
+ &dev_attr_gid.attr,
&dev_attr_fabric_id.attr,
NULL,
};
diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index 3078779fa71e..1b9fa14da20c 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -67,6 +67,15 @@ union ism_reg_ieq {
} response;
} __aligned(16);
+/* ISM-vPCI devices provide 64 Bit GIDs
+ * Map them to ISM UUID GIDs like this:
+ * _________________________________________
+ * | 64 Bit ISM-vPCI GID | 00000000_00000000 |
+ * -----------------------------------------
+ * This will be interpreted as a UIID variant, that is reserved
+ * for NCS backward compatibility. So it will not collide with
+ * proper UUIDs.
+ */
union ism_read_gid {
struct {
struct ism_req_hdr hdr;
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index ab1d61eb3e3b..e58c55fb03c2 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -272,8 +272,9 @@ static int unregister_ieq(struct ism_dev *ism)
return 0;
}
-static int ism_read_local_gid(struct ism_dev *ism)
+static int ism_read_local_gid(struct dibs_dev *dibs)
{
+ struct ism_dev *ism = dibs->drv_priv;
union ism_read_gid cmd;
int ret;
@@ -285,7 +286,8 @@ static int ism_read_local_gid(struct ism_dev *ism)
if (ret)
goto out;
- ism->local_gid = cmd.response.gid;
+ memset(&dibs->gid, 0, sizeof(dibs->gid));
+ memcpy(&dibs->gid, &cmd.response.gid, sizeof(cmd.response.gid));
out:
return ret;
}
@@ -563,10 +565,6 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret)
goto unreg_sba;
- ret = ism_read_local_gid(ism);
- if (ret)
- goto unreg_ieq;
-
if (!ism_add_vlan_id(ism, ISM_RESERVED_VLANID))
/* hardware is V2 capable */
ism_v2_capable = true;
@@ -588,8 +586,6 @@ static int ism_dev_init(struct ism_dev *ism)
query_info(ism);
return 0;
-unreg_ieq:
- unregister_ieq(ism);
unreg_sba:
unregister_sba(ism);
free_irq:
@@ -672,6 +668,11 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret)
goto err_dibs;
+ /* after ism_dev_init() we can call ism function to set gid */
+ ret = ism_read_local_gid(dibs);
+ if (ret)
+ goto err_ism;
+
dibs->dev.parent = &pdev->dev;
zdev = to_zpci(pdev);
@@ -841,18 +842,6 @@ static int smcd_supports_v2(void)
return ism_v2_capable;
}
-static u64 ism_get_local_gid(struct ism_dev *ism)
-{
- return ism->local_gid;
-}
-
-static void smcd_get_local_gid(struct smcd_dev *smcd,
- struct smcd_gid *smcd_gid)
-{
- smcd_gid->gid = ism_get_local_gid(smcd->priv);
- smcd_gid->gid_ext = 0;
-}
-
static const struct smcd_ops ism_smcd_ops = {
.query_remote_gid = smcd_query_rgid,
.register_dmb = smcd_register_dmb,
@@ -864,7 +853,6 @@ static const struct smcd_ops ism_smcd_ops = {
.signal_event = smcd_signal_ieq,
.move_data = smcd_move,
.supports_v2 = smcd_supports_v2,
- .get_local_gid = smcd_get_local_gid,
};
const struct smcd_ops *ism_get_smcd_ops(void)
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 793c6e1ece0f..904f37505c27 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -10,6 +10,8 @@
#define _DIBS_H
#include <linux/device.h>
+#include <linux/uuid.h>
+
/* DIBS - Direct Internal Buffer Sharing - concept
* -----------------------------------------------
* In the case of multiple system sharing the same hardware, dibs fabrics can
@@ -138,6 +140,7 @@ struct dibs_dev {
struct device dev;
/* To be filled by device driver, before calling dibs_dev_add(): */
const struct dibs_dev_ops *ops;
+ uuid_t gid;
/* priv pointer for device driver */
void *drv_priv;
diff --git a/include/linux/ism.h b/include/linux/ism.h
index 84f1afb3dded..a926dd61b5a1 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -42,7 +42,6 @@ struct ism_dev {
struct ism_eq *ieq;
dma_addr_t ieq_dma_addr;
- u64 local_gid;
int ieq_idx;
struct ism_client *subs[MAX_CLIENTS];
diff --git a/include/net/smc.h b/include/net/smc.h
index 05faac83371e..9cb8385bbc6e 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -62,7 +62,6 @@ struct smcd_ops {
bool sf, unsigned int offset, void *data,
unsigned int size);
int (*supports_v2)(void);
- void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid);
/* optional operations */
int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
diff --git a/net/smc/smc_clc.c b/net/smc/smc_clc.c
index 09745baa1017..157aace169d4 100644
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -916,7 +916,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
/* add SMC-D specifics */
if (ini->ism_dev[0]) {
smcd = ini->ism_dev[0];
- smcd->ops->get_local_gid(smcd, &smcd_gid);
+ copy_to_smcdgid(&smcd_gid, &smcd->dibs->gid);
pclc_smcd->ism.gid = htonll(smcd_gid.gid);
pclc_smcd->ism.chid =
htons(smc_ism_get_chid(ini->ism_dev[0]));
@@ -966,7 +966,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
if (ini->ism_offered_cnt) {
for (i = 1; i <= ini->ism_offered_cnt; i++) {
smcd = ini->ism_dev[i];
- smcd->ops->get_local_gid(smcd, &smcd_gid);
+ copy_to_smcdgid(&smcd_gid, &smcd->dibs->gid);
gidchids[entry].chid =
htons(smc_ism_get_chid(ini->ism_dev[i]));
gidchids[entry].gid = htonll(smcd_gid.gid);
@@ -1059,7 +1059,7 @@ smcd_clc_prep_confirm_accept(struct smc_connection *conn,
/* SMC-D specific settings */
memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
sizeof(SMCD_EYECATCHER));
- smcd->ops->get_local_gid(smcd, &smcd_gid);
+ copy_to_smcdgid(&smcd_gid, &smcd->dibs->gid);
clc->hdr.typev1 = SMC_TYPE_D;
clc->d0.gid = htonll(smcd_gid.gid);
clc->d0.token = htonll(conn->rmb_desc->token);
diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
index 585e86890ff7..48d434470517 100644
--- a/net/smc/smc_core.c
+++ b/net/smc/smc_core.c
@@ -555,7 +555,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
goto errattr;
- smcd->ops->get_local_gid(smcd, &smcd_gid);
+ copy_to_smcdgid(&smcd_gid, &smcd->dibs->gid);
if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
smcd_gid.gid, SMC_NLA_LGR_D_PAD))
goto errattr;
diff --git a/net/smc/smc_diag.c b/net/smc/smc_diag.c
index 8ed2f6689b01..bf0beaa23bdb 100644
--- a/net/smc/smc_diag.c
+++ b/net/smc/smc_diag.c
@@ -175,7 +175,7 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
dinfo.linkid = *((u32 *)conn->lgr->id);
dinfo.peer_gid = conn->lgr->peer_gid.gid;
dinfo.peer_gid_ext = conn->lgr->peer_gid.gid_ext;
- smcd->ops->get_local_gid(smcd, &smcd_gid);
+ copy_to_smcdgid(&smcd_gid, &smcd->dibs->gid);
dinfo.my_gid = smcd_gid.gid;
dinfo.my_gid_ext = smcd_gid.gid_ext;
dinfo.token = conn->rmb_desc->token;
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 04699951d03f..139e99da2c9f 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -96,4 +96,26 @@ static inline bool smc_ism_is_loopback(struct dibs_dev *dibs)
return (dibs->ops->get_fabric_id(dibs) == DIBS_LOOPBACK_FABRIC);
}
+static inline void copy_to_smcdgid(struct smcd_gid *sgid, uuid_t *dibs_gid)
+{
+ __be64 temp;
+
+ memcpy(&temp, dibs_gid, sizeof(sgid->gid));
+ sgid->gid = ntohll(temp);
+ memcpy(&temp, (uint8_t *)dibs_gid + sizeof(sgid->gid),
+ sizeof(sgid->gid_ext));
+ sgid->gid_ext = ntohll(temp);
+}
+
+static inline void copy_to_dibsgid(uuid_t *dibs_gid, struct smcd_gid *sgid)
+{
+ __be64 temp;
+
+ temp = htonll(sgid->gid);
+ memcpy(dibs_gid, &temp, sizeof(sgid->gid));
+ temp = htonll(sgid->gid_ext);
+ memcpy((uint8_t *)dibs_gid + sizeof(sgid->gid), &temp,
+ sizeof(sgid->gid_ext));
+}
+
#endif
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 262d0d0df4d0..454d9d6a6e8f 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/types.h>
+#include <linux/dibs.h>
#include <net/smc.h>
#include "smc_cdc.h"
@@ -25,25 +26,14 @@
static struct smc_lo_dev *lo_dev;
-static void smc_lo_generate_ids(struct smc_lo_dev *ldev)
-{
- struct smcd_gid *lgid = &ldev->local_gid;
- uuid_t uuid;
-
- uuid_gen(&uuid);
- memcpy(&lgid->gid, &uuid, sizeof(lgid->gid));
- memcpy(&lgid->gid_ext, (u8 *)&uuid + sizeof(lgid->gid),
- sizeof(lgid->gid_ext));
-}
-
static int smc_lo_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
u32 vid_valid, u32 vid)
{
- struct smc_lo_dev *ldev = smcd->priv;
+ uuid_t temp;
+ copy_to_dibsgid(&temp, rgid);
/* rgid should be the same as lgid */
- if (!ldev || rgid->gid != ldev->local_gid.gid ||
- rgid->gid_ext != ldev->local_gid.gid_ext)
+ if (!uuid_equal(&temp, &smcd->dibs->gid))
return -ENETUNREACH;
return 0;
}
@@ -245,15 +235,6 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
return 0;
}
-static void smc_lo_get_local_gid(struct smcd_dev *smcd,
- struct smcd_gid *smcd_gid)
-{
- struct smc_lo_dev *ldev = smcd->priv;
-
- smcd_gid->gid = ldev->local_gid.gid;
- smcd_gid->gid_ext = ldev->local_gid.gid_ext;
-}
-
static const struct smcd_ops lo_ops = {
.query_remote_gid = smc_lo_query_rgid,
.register_dmb = smc_lo_register_dmb,
@@ -267,7 +248,6 @@ static const struct smcd_ops lo_ops = {
.reset_vlan_required = NULL,
.signal_event = NULL,
.move_data = smc_lo_move_data,
- .get_local_gid = smc_lo_get_local_gid,
};
const struct smcd_ops *smc_lo_get_smcd_ops(void)
@@ -277,7 +257,6 @@ const struct smcd_ops *smc_lo_get_smcd_ops(void)
static void smc_lo_dev_init(struct smc_lo_dev *ldev)
{
- smc_lo_generate_ids(ldev);
rwlock_init(&ldev->dmb_ht_lock);
hash_init(ldev->dmb_ht);
atomic_set(&ldev->dmb_cnt, 0);
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
index a033bf10890a..33bb96ec8b77 100644
--- a/net/smc/smc_loopback.h
+++ b/net/smc/smc_loopback.h
@@ -32,7 +32,6 @@ struct smc_lo_dmb_node {
struct smc_lo_dev {
struct smcd_dev *smcd;
- struct smcd_gid local_gid;
atomic_t dmb_cnt;
rwlock_t dmb_ht_lock;
DECLARE_BITMAP(sba_idx_mask, SMC_LO_MAX_DMBS);
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 11/14] dibs: Move vlan support to dibs_dev_ops
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (9 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 10/14] dibs: Local gid for dibs devices Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 12/14] dibs: Move query_remote_gid() " Alexandra Winter
` (3 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
It can be debated how much benefit definition of vlan ids for dibs devices
brings, as the dmbs are accessible only by a single peer anyhow. But ism
provides vlan support and smcd exploits it, so move it to dibs layer as an
optional feature.
smcd_loopback simply ignores all vlan settings, do the same in
dibs_loopback.
SMC-D and ISM have a method to use the invalid VLAN ID 1FFF
(ISM_RESERVED_VLANID), to indicate that both communication peers support
routable SMC-Dv2. Tolerate it in dibs, but move it to SMC only.
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
drivers/s390/net/ism_drv.c | 47 +++++---------------------------------
include/linux/dibs.h | 19 +++++++++++++++
include/net/smc.h | 5 ----
net/smc/smc_ism.c | 14 ++++++++----
net/smc/smc_loopback.c | 5 ----
5 files changed, 34 insertions(+), 56 deletions(-)
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index e58c55fb03c2..ed4c28ca355b 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -36,7 +36,6 @@ 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 */
@@ -409,8 +408,9 @@ int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
}
EXPORT_SYMBOL_GPL(ism_unregister_dmb);
-static int ism_add_vlan_id(struct ism_dev *ism, u64 vlan_id)
+static int ism_add_vlan_id(struct dibs_dev *dibs, u64 vlan_id)
{
+ struct ism_dev *ism = dibs->drv_priv;
union ism_set_vlan_id cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -422,8 +422,9 @@ static int ism_add_vlan_id(struct ism_dev *ism, u64 vlan_id)
return ism_cmd(ism, &cmd);
}
-static int ism_del_vlan_id(struct ism_dev *ism, u64 vlan_id)
+static int ism_del_vlan_id(struct dibs_dev *dibs, u64 vlan_id)
{
+ struct ism_dev *ism = dibs->drv_priv;
union ism_set_vlan_id cmd;
memset(&cmd, 0, sizeof(cmd));
@@ -536,6 +537,8 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
static const struct dibs_dev_ops ism_ops = {
.get_fabric_id = ism_get_chid,
+ .add_vlan_id = ism_add_vlan_id,
+ .del_vlan_id = ism_del_vlan_id,
};
static int ism_dev_init(struct ism_dev *ism)
@@ -565,12 +568,6 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret)
goto unreg_sba;
- if (!ism_add_vlan_id(ism, ISM_RESERVED_VLANID))
- /* hardware is V2 capable */
- ism_v2_capable = true;
- else
- ism_v2_capable = false;
-
mutex_lock(&ism_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
@@ -611,8 +608,6 @@ static void ism_dev_exit(struct ism_dev *ism)
mutex_lock(&ism_dev_list.mutex);
- if (ism_v2_capable)
- ism_del_vlan_id(ism, ISM_RESERVED_VLANID);
unregister_ieq(ism);
unregister_sba(ism);
free_irq(pci_irq_vector(pdev, 0), ism);
@@ -786,26 +781,6 @@ static int smcd_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
return ism_unregister_dmb(smcd->priv, (struct ism_dmb *)dmb);
}
-static int smcd_add_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
-{
- return ism_add_vlan_id(smcd->priv, vlan_id);
-}
-
-static int smcd_del_vlan_id(struct smcd_dev *smcd, u64 vlan_id)
-{
- return ism_del_vlan_id(smcd->priv, vlan_id);
-}
-
-static int smcd_set_vlan_required(struct smcd_dev *smcd)
-{
- return ism_cmd_simple(smcd->priv, ISM_SET_VLAN);
-}
-
-static int smcd_reset_vlan_required(struct smcd_dev *smcd)
-{
- return ism_cmd_simple(smcd->priv, ISM_RESET_VLAN);
-}
-
static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
u32 event_code, u64 info)
{
@@ -837,22 +812,12 @@ static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
return ism_move(smcd->priv, dmb_tok, idx, sf, offset, data, size);
}
-static int smcd_supports_v2(void)
-{
- return ism_v2_capable;
-}
-
static const struct smcd_ops ism_smcd_ops = {
.query_remote_gid = smcd_query_rgid,
.register_dmb = smcd_register_dmb,
.unregister_dmb = smcd_unregister_dmb,
- .add_vlan_id = smcd_add_vlan_id,
- .del_vlan_id = smcd_del_vlan_id,
- .set_vlan_required = smcd_set_vlan_required,
- .reset_vlan_required = smcd_reset_vlan_required,
.signal_event = smcd_signal_ieq,
.move_data = smcd_move,
- .supports_v2 = smcd_supports_v2,
};
const struct smcd_ops *ism_get_smcd_ops(void)
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 904f37505c27..166148fb8d76 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -133,6 +133,25 @@ struct dibs_dev_ops {
* Return: 2 byte dibs fabric id
*/
u16 (*get_fabric_id)(struct dibs_dev *dev);
+ /**
+ * add_vlan_id() - add dibs device to vlan (optional, deprecated)
+ * @dev: dibs device
+ * @vlan_id: vlan id
+ *
+ * In order to write into a vlan-tagged dmb, the remote device needs
+ * to belong to the this vlan. A device can belong to more than 1 vlan.
+ * Any device can access an untagged dmb.
+ * Deprecated, only supported for backwards compatibility.
+ * Return: zero on success
+ */
+ int (*add_vlan_id)(struct dibs_dev *dev, u64 vlan_id);
+ /**
+ * del_vlan_id() - remove dibs device from vlan (optional, deprecated)
+ * @dev: dibs device
+ * @vlan_id: vlan id
+ * Return: zero on success
+ */
+ int (*del_vlan_id)(struct dibs_dev *dev, u64 vlan_id);
};
struct dibs_dev {
diff --git a/include/net/smc.h b/include/net/smc.h
index 9cb8385bbc6e..51b4aefc106a 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -61,13 +61,8 @@ struct smcd_ops {
int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
bool sf, unsigned int offset, void *data,
unsigned int size);
- int (*supports_v2)(void);
/* optional operations */
- int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
- int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
- int (*set_vlan_required)(struct smcd_dev *dev);
- int (*reset_vlan_required)(struct smcd_dev *dev);
int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
u32 trigger_irq, u32 event_code, u64 info);
int (*support_dmb_nocopy)(struct smcd_dev *dev);
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 6a6e7c9641e8..5118441bed18 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -140,7 +140,7 @@ int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid)
if (!vlanid) /* No valid vlan id */
return -EINVAL;
- if (!smcd->ops->add_vlan_id)
+ if (!smcd->dibs->ops->add_vlan_id)
return -EOPNOTSUPP;
/* create new vlan entry, in case we need it */
@@ -163,7 +163,7 @@ int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid)
/* no existing entry found.
* add new entry to device; might fail, e.g., if HW limit reached
*/
- if (smcd->ops->add_vlan_id(smcd, vlanid)) {
+ if (smcd->dibs->ops->add_vlan_id(smcd->dibs, vlanid)) {
kfree(new_vlan);
rc = -EIO;
goto out;
@@ -187,7 +187,7 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
if (!vlanid) /* No valid vlan id */
return -EINVAL;
- if (!smcd->ops->del_vlan_id)
+ if (!smcd->dibs->ops->del_vlan_id)
return -EOPNOTSUPP;
spin_lock_irqsave(&smcd->lock, flags);
@@ -205,7 +205,7 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
}
/* Found and the last reference just gone */
- if (smcd->ops->del_vlan_id(smcd, vlanid))
+ if (smcd->dibs->ops->del_vlan_id(smcd->dibs, vlanid))
rc = -EIO;
list_del(&vlan->list);
kfree(vlan);
@@ -539,8 +539,12 @@ static void smcd_register_dev(struct dibs_dev *dibs)
if (smc_pnetid_by_dev_port(dibs->dev.parent, 0, smcd->pnetid))
smc_pnetid_by_table_smcd(smcd);
- if (smc_ism_is_loopback(dibs) || smcd->ops->supports_v2())
+ if (smc_ism_is_loopback(dibs) ||
+ (dibs->ops->add_vlan_id &&
+ !dibs->ops->add_vlan_id(dibs, ISM_RESERVED_VLANID))) {
smc_ism_set_v2_capable();
+ }
+
mutex_lock(&smcd_dev_list.mutex);
/* sort list:
* - devices without pnetid before devices with pnetid;
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 454d9d6a6e8f..982a19430313 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -20,7 +20,6 @@
#include "smc_ism.h"
#include "smc_loopback.h"
-#define SMC_LO_V2_CAPABLE 0x1 /* loopback-ism acts as ISMv2 */
#define SMC_LO_SUPPORT_NOCOPY 0x1
#define SMC_DMA_ADDR_INVALID (~(dma_addr_t)0)
@@ -242,10 +241,6 @@ static const struct smcd_ops lo_ops = {
.support_dmb_nocopy = smc_lo_support_dmb_nocopy,
.attach_dmb = smc_lo_attach_dmb,
.detach_dmb = smc_lo_detach_dmb,
- .add_vlan_id = NULL,
- .del_vlan_id = NULL,
- .set_vlan_required = NULL,
- .reset_vlan_required = NULL,
.signal_event = NULL,
.move_data = smc_lo_move_data,
};
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 12/14] dibs: Move query_remote_gid() to dibs_dev_ops
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (10 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 11/14] dibs: Move vlan support to dibs_dev_ops Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer Alexandra Winter
` (2 subsequent siblings)
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Provide the dibs_dev_ops->query_remote_gid() in ism and dibs_loopback
dibs_devices. And call it in smc dibs_client.
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
drivers/dibs/dibs_loopback.c | 10 +++++++++
drivers/s390/net/ism_drv.c | 41 ++++++++++++++++--------------------
include/linux/dibs.h | 14 ++++++++++++
include/net/smc.h | 2 --
net/smc/smc_ism.c | 8 +++++--
net/smc/smc_loopback.c | 13 ------------
6 files changed, 48 insertions(+), 40 deletions(-)
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index d7e6fa5e90f3..6b53e626a6d1 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -24,8 +24,18 @@ static u16 dibs_lo_get_fabric_id(struct dibs_dev *dibs)
return DIBS_LOOPBACK_FABRIC;
}
+static int dibs_lo_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
+ u32 vid_valid, u32 vid)
+{
+ /* rgid should be the same as lgid */
+ if (!uuid_equal(rgid, &dibs->gid))
+ return -ENETUNREACH;
+ return 0;
+}
+
static const struct dibs_dev_ops dibs_lo_ops = {
.get_fabric_id = dibs_lo_get_fabric_id,
+ .query_remote_gid = dibs_lo_query_rgid,
};
static int dibs_lo_dev_probe(void)
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index ed4c28ca355b..121b3a2be760 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -291,6 +291,23 @@ static int ism_read_local_gid(struct dibs_dev *dibs)
return ret;
}
+static int ism_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
+ u32 vid_valid, u32 vid)
+{
+ struct ism_dev *ism = dibs->drv_priv;
+ union ism_query_rgid cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.request.hdr.cmd = ISM_QUERY_RGID;
+ cmd.request.hdr.len = sizeof(cmd.request);
+
+ memcpy(&cmd.request.rgid, rgid, sizeof(cmd.request.rgid));
+ cmd.request.vlan_valid = vid_valid;
+ cmd.request.vlan_id = vid;
+
+ return ism_cmd(ism, &cmd);
+}
+
static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
{
clear_bit(dmb->sba_idx, ism->sba_bitmap);
@@ -537,6 +554,7 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
static const struct dibs_dev_ops ism_ops = {
.get_fabric_id = ism_get_chid,
+ .query_remote_gid = ism_query_rgid,
.add_vlan_id = ism_add_vlan_id,
.del_vlan_id = ism_del_vlan_id,
};
@@ -748,28 +766,6 @@ module_exit(ism_exit);
/*************************** SMC-D Implementation *****************************/
#if IS_ENABLED(CONFIG_SMC)
-static int ism_query_rgid(struct ism_dev *ism, u64 rgid, u32 vid_valid,
- u32 vid)
-{
- union ism_query_rgid cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.request.hdr.cmd = ISM_QUERY_RGID;
- cmd.request.hdr.len = sizeof(cmd.request);
-
- cmd.request.rgid = rgid;
- cmd.request.vlan_valid = vid_valid;
- cmd.request.vlan_id = vid;
-
- return ism_cmd(ism, &cmd);
-}
-
-static int smcd_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
- u32 vid_valid, u32 vid)
-{
- return ism_query_rgid(smcd->priv, rgid->gid, vid_valid, vid);
-}
-
static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
void *client)
{
@@ -813,7 +809,6 @@ static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
}
static const struct smcd_ops ism_smcd_ops = {
- .query_remote_gid = smcd_query_rgid,
.register_dmb = smcd_register_dmb,
.unregister_dmb = smcd_unregister_dmb,
.signal_event = smcd_signal_ieq,
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 166148fb8d76..c75a40fe3039 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -133,6 +133,20 @@ struct dibs_dev_ops {
* Return: 2 byte dibs fabric id
*/
u16 (*get_fabric_id)(struct dibs_dev *dev);
+ /**
+ * query_remote_gid()
+ * @dev: local dibs device
+ * @rgid: gid of remote dibs device
+ * @vid_valid: if zero, vid will be ignored;
+ * deprecated, ignored if device does not support vlan
+ * @vid: VLAN id; deprecated, ignored if device does not support vlan
+ *
+ * Query whether a remote dibs device is reachable via this local device
+ * and this vlan id.
+ * Return: 0 if remote gid is reachable.
+ */
+ int (*query_remote_gid)(struct dibs_dev *dev, const uuid_t *rgid,
+ u32 vid_valid, u32 vid);
/**
* add_vlan_id() - add dibs device to vlan (optional, deprecated)
* @dev: dibs device
diff --git a/include/net/smc.h b/include/net/smc.h
index 51b4aefc106a..5bd135fb4d49 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -53,8 +53,6 @@ struct smcd_gid {
};
struct smcd_ops {
- int (*query_remote_gid)(struct smcd_dev *dev, struct smcd_gid *rgid,
- u32 vid_valid, u32 vid);
int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
void *client);
int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 5118441bed18..d20d00b46825 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -77,8 +77,12 @@ static void smc_ism_create_system_eid(void)
int smc_ism_cantalk(struct smcd_gid *peer_gid, unsigned short vlan_id,
struct smcd_dev *smcd)
{
- return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0,
- vlan_id);
+ struct dibs_dev *dibs = smcd->dibs;
+ uuid_t ism_rgid;
+
+ copy_to_dibsgid(&ism_rgid, peer_gid);
+ return dibs->ops->query_remote_gid(dibs, &ism_rgid, vlan_id ? 1 : 0,
+ vlan_id);
}
void smc_ism_get_system_eid(u8 **eid)
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
index 982a19430313..52cba01cb209 100644
--- a/net/smc/smc_loopback.c
+++ b/net/smc/smc_loopback.c
@@ -25,18 +25,6 @@
static struct smc_lo_dev *lo_dev;
-static int smc_lo_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid,
- u32 vid_valid, u32 vid)
-{
- uuid_t temp;
-
- copy_to_dibsgid(&temp, rgid);
- /* rgid should be the same as lgid */
- if (!uuid_equal(&temp, &smcd->dibs->gid))
- return -ENETUNREACH;
- return 0;
-}
-
static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
void *client_priv)
{
@@ -235,7 +223,6 @@ static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
}
static const struct smcd_ops lo_ops = {
- .query_remote_gid = smc_lo_query_rgid,
.register_dmb = smc_lo_register_dmb,
.unregister_dmb = smc_lo_unregister_dmb,
.support_dmb_nocopy = smc_lo_support_dmb_nocopy,
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 13/14] dibs: Move data path to dibs layer
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (11 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 12/14] dibs: Move query_remote_gid() " Alexandra Winter
@ 2025-09-18 11:04 ` Alexandra Winter
2025-09-24 9:07 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge Matthieu Baerts
2025-09-18 11:05 ` [PATCH net-next v3 14/14] dibs: Move event handling to dibs layer Alexandra Winter
2025-09-23 9:20 ` [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing patchwork-bot+netdevbpf
14 siblings, 1 reply; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:04 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
Use struct dibs_dmb instead of struct smc_dmb and move the corresponding
client tables to dibs_dev. Leave driver specific implementation details
like sba in the device drivers.
Register and unregister dmbs via dibs_dev_ops. A dmb is dedicated to a
single client, but a dibs device can have dmbs for more than one client.
Trigger dibs clients via dibs_client_ops->handle_irq(), when data is
received into a dmb. For dibs_loopback replace scheduling an smcd receive
tasklet with calling dibs_client_ops->handle_irq().
For loopback devices attach_dmb(), detach_dmb() and move_data() need to
access the dmb tables, so move those to dibs_dev_ops in this patch as well.
Remove remaining definitions of smc_loopback as they are no longer
required, now that everything is in dibs_loopback.
Note that struct ism_client and struct ism_dev are still required in smc
until a follow-on patch moves event handling to dibs. (Loopback does not
use events).
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
drivers/dibs/dibs_loopback.c | 257 ++++++++++++++++++++++++++++++
drivers/dibs/dibs_loopback.h | 19 +++
drivers/dibs/dibs_main.c | 56 ++++++-
drivers/s390/net/ism_drv.c | 121 ++++++--------
include/linux/dibs.h | 177 +++++++++++++++++++++
include/linux/ism.h | 23 ---
include/net/smc.h | 22 ---
net/smc/Makefile | 1 -
net/smc/smc_ism.c | 70 ++++-----
net/smc/smc_ism.h | 4 +-
net/smc/smc_loopback.c | 294 -----------------------------------
net/smc/smc_loopback.h | 47 ------
12 files changed, 591 insertions(+), 500 deletions(-)
delete mode 100644 net/smc/smc_loopback.c
delete mode 100644 net/smc/smc_loopback.h
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index 6b53e626a6d1..b3fd0f8100d4 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -9,12 +9,18 @@
*
*/
+#include <linux/bitops.h>
+#include <linux/device.h>
#include <linux/dibs.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
#include "dibs_loopback.h"
+#define DIBS_LO_SUPPORT_NOCOPY 0x1
+#define DIBS_DMA_ADDR_INVALID (~(dma_addr_t)0)
+
static const char dibs_lo_dev_name[] = "lo";
/* global loopback device */
static struct dibs_lo_dev *lo_dev;
@@ -33,11 +39,259 @@ static int dibs_lo_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
return 0;
}
+static int dibs_lo_max_dmbs(void)
+{
+ return DIBS_LO_MAX_DMBS;
+}
+
+static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
+ struct dibs_client *client)
+{
+ struct dibs_lo_dmb_node *dmb_node, *tmp_node;
+ struct dibs_lo_dev *ldev;
+ unsigned long flags;
+ int sba_idx, rc;
+
+ ldev = dibs->drv_priv;
+ sba_idx = dmb->idx;
+ /* check space for new dmb */
+ for_each_clear_bit(sba_idx, ldev->sba_idx_mask, DIBS_LO_MAX_DMBS) {
+ if (!test_and_set_bit(sba_idx, ldev->sba_idx_mask))
+ break;
+ }
+ if (sba_idx == DIBS_LO_MAX_DMBS)
+ return -ENOSPC;
+
+ dmb_node = kzalloc(sizeof(*dmb_node), GFP_KERNEL);
+ if (!dmb_node) {
+ rc = -ENOMEM;
+ goto err_bit;
+ }
+
+ dmb_node->sba_idx = sba_idx;
+ dmb_node->len = dmb->dmb_len;
+ dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL |
+ __GFP_NOWARN | __GFP_NORETRY |
+ __GFP_NOMEMALLOC);
+ if (!dmb_node->cpu_addr) {
+ rc = -ENOMEM;
+ goto err_node;
+ }
+ dmb_node->dma_addr = DIBS_DMA_ADDR_INVALID;
+ refcount_set(&dmb_node->refcnt, 1);
+
+again:
+ /* add new dmb into hash table */
+ get_random_bytes(&dmb_node->token, sizeof(dmb_node->token));
+ write_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_node->token) {
+ if (tmp_node->token == dmb_node->token) {
+ write_unlock_bh(&ldev->dmb_ht_lock);
+ goto again;
+ }
+ }
+ hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+ atomic_inc(&ldev->dmb_cnt);
+
+ dmb->idx = dmb_node->sba_idx;
+ dmb->dmb_tok = dmb_node->token;
+ dmb->cpu_addr = dmb_node->cpu_addr;
+ dmb->dma_addr = dmb_node->dma_addr;
+ dmb->dmb_len = dmb_node->len;
+
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[sba_idx] = client->id;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+
+ return 0;
+
+err_node:
+ kfree(dmb_node);
+err_bit:
+ clear_bit(sba_idx, ldev->sba_idx_mask);
+ return rc;
+}
+
+static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
+ struct dibs_lo_dmb_node *dmb_node)
+{
+ /* remove dmb from hash table */
+ write_lock_bh(&ldev->dmb_ht_lock);
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+
+ clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
+ kfree(dmb_node->cpu_addr);
+ kfree(dmb_node);
+
+ if (atomic_dec_and_test(&ldev->dmb_cnt))
+ wake_up(&ldev->ldev_release);
+}
+
+static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
+{
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+ unsigned long flags;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb from hash table */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
+ if (tmp_node->token == dmb->dmb_tok) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ if (!dmb_node)
+ return -EINVAL;
+
+ if (refcount_dec_and_test(&dmb_node->refcnt)) {
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+
+ __dibs_lo_unregister_dmb(ldev, dmb_node);
+ }
+ return 0;
+}
+
+static int dibs_lo_support_dmb_nocopy(struct dibs_dev *dibs)
+{
+ return DIBS_LO_SUPPORT_NOCOPY;
+}
+
+static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
+{
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb_node according to dmb->dmb_tok */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
+ if (tmp_node->token == dmb->dmb_tok) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!dmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (!refcount_inc_not_zero(&dmb_node->refcnt))
+ /* the dmb is being unregistered, but has
+ * not been removed from the hash table.
+ */
+ return -EINVAL;
+
+ /* provide dmb information */
+ dmb->idx = dmb_node->sba_idx;
+ dmb->dmb_tok = dmb_node->token;
+ dmb->cpu_addr = dmb_node->cpu_addr;
+ dmb->dma_addr = dmb_node->dma_addr;
+ dmb->dmb_len = dmb_node->len;
+ return 0;
+}
+
+static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
+{
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb_node according to dmb->dmb_tok */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
+ if (tmp_node->token == token) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!dmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (refcount_dec_and_test(&dmb_node->refcnt))
+ __dibs_lo_unregister_dmb(ldev, dmb_node);
+ return 0;
+}
+
+static int dibs_lo_move_data(struct dibs_dev *dibs, u64 dmb_tok,
+ unsigned int idx, bool sf, unsigned int offset,
+ void *data, unsigned int size)
+{
+ struct dibs_lo_dmb_node *rmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+ u16 s_mask;
+ u8 client_id;
+ u32 sba_idx;
+
+ ldev = dibs->drv_priv;
+
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
+ if (tmp_node->token == dmb_tok) {
+ rmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!rmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ memcpy((char *)rmb_node->cpu_addr + offset, data, size);
+ sba_idx = rmb_node->sba_idx;
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (!sf)
+ return 0;
+
+ spin_lock(&dibs->lock);
+ client_id = dibs->dmb_clientid_arr[sba_idx];
+ s_mask = ror16(0x1000, idx);
+ if (likely(client_id != NO_DIBS_CLIENT && dibs->subs[client_id]))
+ dibs->subs[client_id]->ops->handle_irq(dibs, sba_idx, s_mask);
+ spin_unlock(&dibs->lock);
+
+ return 0;
+}
+
static const struct dibs_dev_ops dibs_lo_ops = {
.get_fabric_id = dibs_lo_get_fabric_id,
.query_remote_gid = dibs_lo_query_rgid,
+ .max_dmbs = dibs_lo_max_dmbs,
+ .register_dmb = dibs_lo_register_dmb,
+ .unregister_dmb = dibs_lo_unregister_dmb,
+ .move_data = dibs_lo_move_data,
+ .support_mmapped_rdmb = dibs_lo_support_dmb_nocopy,
+ .attach_dmb = dibs_lo_attach_dmb,
+ .detach_dmb = dibs_lo_detach_dmb,
};
+static void dibs_lo_dev_init(struct dibs_lo_dev *ldev)
+{
+ rwlock_init(&ldev->dmb_ht_lock);
+ hash_init(ldev->dmb_ht);
+ atomic_set(&ldev->dmb_cnt, 0);
+ init_waitqueue_head(&ldev->ldev_release);
+}
+
+static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
+{
+ if (atomic_read(&ldev->dmb_cnt))
+ wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
+}
+
static int dibs_lo_dev_probe(void)
{
struct dibs_lo_dev *ldev;
@@ -56,6 +310,7 @@ static int dibs_lo_dev_probe(void)
ldev->dibs = dibs;
dibs->drv_priv = ldev;
+ dibs_lo_dev_init(ldev);
uuid_gen(&dibs->gid);
dibs->ops = &dibs_lo_ops;
@@ -69,6 +324,7 @@ static int dibs_lo_dev_probe(void)
return 0;
err_reg:
+ kfree(dibs->dmb_clientid_arr);
/* pairs with dibs_dev_alloc() */
put_device(&dibs->dev);
kfree(ldev);
@@ -82,6 +338,7 @@ static void dibs_lo_dev_remove(void)
return;
dibs_dev_del(lo_dev->dibs);
+ dibs_lo_dev_exit(lo_dev);
/* pairs with dibs_dev_alloc() */
put_device(&lo_dev->dibs->dev);
kfree(lo_dev);
diff --git a/drivers/dibs/dibs_loopback.h b/drivers/dibs/dibs_loopback.h
index fd03b6333a24..0664f6a8e662 100644
--- a/drivers/dibs/dibs_loopback.h
+++ b/drivers/dibs/dibs_loopback.h
@@ -13,13 +13,32 @@
#define _DIBS_LOOPBACK_H
#include <linux/dibs.h>
+#include <linux/hashtable.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
#if IS_ENABLED(CONFIG_DIBS_LO)
+#define DIBS_LO_DMBS_HASH_BITS 12
+#define DIBS_LO_MAX_DMBS 5000
+
+struct dibs_lo_dmb_node {
+ struct hlist_node list;
+ u64 token;
+ u32 len;
+ u32 sba_idx;
+ void *cpu_addr;
+ dma_addr_t dma_addr;
+ refcount_t refcnt;
+};
struct dibs_lo_dev {
struct dibs_dev *dibs;
+ atomic_t dmb_cnt;
+ rwlock_t dmb_ht_lock;
+ DECLARE_BITMAP(sba_idx_mask, DIBS_LO_MAX_DMBS);
+ DECLARE_HASHTABLE(dmb_ht, DIBS_LO_DMBS_HASH_BITS);
+ wait_queue_head_t ldev_release;
};
int dibs_loopback_init(void);
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index f20ed0594a51..aacb3ea7825a 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -36,6 +36,16 @@ static struct dibs_dev_list dibs_dev_list = {
.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
};
+static void dibs_setup_forwarding(struct dibs_client *client,
+ struct dibs_dev *dibs)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->subs[client->id] = client;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+}
+
int dibs_register_client(struct dibs_client *client)
{
struct dibs_dev *dibs;
@@ -60,6 +70,7 @@ int dibs_register_client(struct dibs_client *client)
list_for_each_entry(dibs, &dibs_dev_list.list, list) {
dibs->priv[i] = NULL;
client->ops->add_dev(dibs);
+ dibs_setup_forwarding(client, dibs);
}
}
mutex_unlock(&dibs_dev_list.mutex);
@@ -71,10 +82,25 @@ EXPORT_SYMBOL_GPL(dibs_register_client);
int dibs_unregister_client(struct dibs_client *client)
{
struct dibs_dev *dibs;
+ unsigned long flags;
+ int max_dmbs;
int rc = 0;
mutex_lock(&dibs_dev_list.mutex);
list_for_each_entry(dibs, &dibs_dev_list.list, list) {
+ spin_lock_irqsave(&dibs->lock, flags);
+ max_dmbs = dibs->ops->max_dmbs();
+ for (int i = 0; i < max_dmbs; ++i) {
+ if (dibs->dmb_clientid_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;
+ }
+ }
+ /* Stop forwarding IRQs */
+ dibs->subs[client->id] = NULL;
+ spin_unlock_irqrestore(&dibs->lock, flags);
clients[client->id]->ops->del_dev(dibs);
dibs->priv[client->id] = NULL;
}
@@ -87,6 +113,11 @@ int dibs_unregister_client(struct dibs_client *client)
mutex_unlock(&dibs_dev_list.mutex);
return rc;
+
+err_reg_dmb:
+ spin_unlock_irqrestore(&dibs->lock, flags);
+ mutex_unlock(&dibs_dev_list.mutex);
+ return rc;
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);
@@ -150,11 +181,19 @@ static const struct attribute_group dibs_dev_attr_group = {
int dibs_dev_add(struct dibs_dev *dibs)
{
+ int max_dmbs;
int i, ret;
+ max_dmbs = dibs->ops->max_dmbs();
+ spin_lock_init(&dibs->lock);
+ dibs->dmb_clientid_arr = kzalloc(max_dmbs, GFP_KERNEL);
+ if (!dibs->dmb_clientid_arr)
+ return -ENOMEM;
+ memset(dibs->dmb_clientid_arr, NO_DIBS_CLIENT, max_dmbs);
+
ret = device_add(&dibs->dev);
if (ret)
- return ret;
+ goto free_client_arr;
ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
if (ret) {
@@ -164,8 +203,10 @@ int dibs_dev_add(struct dibs_dev *dibs)
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
- if (clients[i])
+ if (clients[i]) {
clients[i]->ops->add_dev(dibs);
+ dibs_setup_forwarding(clients[i], dibs);
+ }
}
mutex_unlock(&clients_lock);
list_add(&dibs->list, &dibs_dev_list.list);
@@ -175,6 +216,8 @@ int dibs_dev_add(struct dibs_dev *dibs)
err_device_del:
device_del(&dibs->dev);
+free_client_arr:
+ kfree(dibs->dmb_clientid_arr);
return ret;
}
@@ -182,8 +225,16 @@ EXPORT_SYMBOL_GPL(dibs_dev_add);
void dibs_dev_del(struct dibs_dev *dibs)
{
+ unsigned long flags;
int i;
+ sysfs_remove_group(&dibs->dev.kobj, &dibs_dev_attr_group);
+
+ spin_lock_irqsave(&dibs->lock, flags);
+ for (i = 0; i < MAX_DIBS_CLIENTS; ++i)
+ dibs->subs[i] = NULL;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+
mutex_lock(&dibs_dev_list.mutex);
mutex_lock(&clients_lock);
for (i = 0; i < max_client; ++i) {
@@ -195,6 +246,7 @@ void dibs_dev_del(struct dibs_dev *dibs)
mutex_unlock(&dibs_dev_list.mutex);
device_del(&dibs->dev);
+ kfree(dibs->dmb_clientid_arr);
}
EXPORT_SYMBOL_GPL(dibs_dev_del);
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 121b3a2be760..346d1ea8650b 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -98,14 +98,6 @@ int ism_unregister_client(struct ism_client *client)
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);
@@ -116,11 +108,6 @@ int ism_unregister_client(struct ism_client *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);
@@ -308,15 +295,20 @@ static int ism_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
return ism_cmd(ism, &cmd);
}
-static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
+static int ism_max_dmbs(void)
+{
+ return ISM_NR_DMBS;
+}
+
+static void ism_free_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
{
- clear_bit(dmb->sba_idx, ism->sba_bitmap);
+ clear_bit(dmb->idx, ism->sba_bitmap);
dma_unmap_page(&ism->pdev->dev, dmb->dma_addr, dmb->dmb_len,
DMA_FROM_DEVICE);
folio_put(virt_to_folio(dmb->cpu_addr));
}
-static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
+static int ism_alloc_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
{
struct folio *folio;
unsigned long bit;
@@ -325,16 +317,16 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
if (PAGE_ALIGN(dmb->dmb_len) > dma_get_max_seg_size(&ism->pdev->dev))
return -EINVAL;
- if (!dmb->sba_idx) {
+ if (!dmb->idx) {
bit = find_next_zero_bit(ism->sba_bitmap, ISM_NR_DMBS,
ISM_DMB_BIT_OFFSET);
if (bit == ISM_NR_DMBS)
return -ENOSPC;
- dmb->sba_idx = bit;
+ dmb->idx = bit;
}
- if (dmb->sba_idx < ISM_DMB_BIT_OFFSET ||
- test_and_set_bit(dmb->sba_idx, ism->sba_bitmap))
+ if (dmb->idx < ISM_DMB_BIT_OFFSET ||
+ test_and_set_bit(dmb->idx, ism->sba_bitmap))
return -EINVAL;
folio = folio_alloc(GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC |
@@ -359,13 +351,14 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
out_free:
kfree(dmb->cpu_addr);
out_bit:
- clear_bit(dmb->sba_idx, ism->sba_bitmap);
+ clear_bit(dmb->idx, ism->sba_bitmap);
return rc;
}
-int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
- struct ism_client *client)
+static int ism_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
+ struct dibs_client *client)
{
+ struct ism_dev *ism = dibs->drv_priv;
union ism_reg_dmb cmd;
unsigned long flags;
int ret;
@@ -380,10 +373,10 @@ int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
cmd.request.dmb = dmb->dma_addr;
cmd.request.dmb_len = dmb->dmb_len;
- cmd.request.sba_idx = dmb->sba_idx;
+ cmd.request.sba_idx = dmb->idx;
cmd.request.vlan_valid = dmb->vlan_valid;
cmd.request.vlan_id = dmb->vlan_id;
- cmd.request.rgid = dmb->rgid;
+ memcpy(&cmd.request.rgid, &dmb->rgid, sizeof(u64));
ret = ism_cmd(ism, &cmd);
if (ret) {
@@ -391,16 +384,16 @@ int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
goto out;
}
dmb->dmb_tok = cmd.response.dmb_tok;
- spin_lock_irqsave(&ism->lock, flags);
- ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = client->id;
- spin_unlock_irqrestore(&ism->lock, flags);
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[dmb->idx - ISM_DMB_BIT_OFFSET] = client->id;
+ spin_unlock_irqrestore(&dibs->lock, flags);
out:
return ret;
}
-EXPORT_SYMBOL_GPL(ism_register_dmb);
-int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
+static int ism_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
+ struct ism_dev *ism = dibs->drv_priv;
union ism_unreg_dmb cmd;
unsigned long flags;
int ret;
@@ -411,9 +404,9 @@ int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
cmd.request.dmb_tok = dmb->dmb_tok;
- spin_lock_irqsave(&ism->lock, flags);
- ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = NO_CLIENT;
- spin_unlock_irqrestore(&ism->lock, flags);
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[dmb->idx - ISM_DMB_BIT_OFFSET] = NO_DIBS_CLIENT;
+ spin_unlock_irqrestore(&dibs->lock, flags);
ret = ism_cmd(ism, &cmd);
if (ret && ret != ISM_ERROR)
@@ -423,7 +416,6 @@ int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
out:
return ret;
}
-EXPORT_SYMBOL_GPL(ism_unregister_dmb);
static int ism_add_vlan_id(struct dibs_dev *dibs, u64 vlan_id)
{
@@ -459,9 +451,11 @@ static unsigned int max_bytes(unsigned int start, unsigned int len,
return min(boundary - (start & (boundary - 1)), len);
}
-int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
- unsigned int offset, void *data, unsigned int size)
+static int ism_move(struct dibs_dev *dibs, u64 dmb_tok, unsigned int idx,
+ bool sf, unsigned int offset, void *data,
+ unsigned int size)
{
+ struct ism_dev *ism = dibs->drv_priv;
unsigned int bytes;
u64 dmb_req;
int ret;
@@ -482,7 +476,6 @@ int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
return 0;
}
-EXPORT_SYMBOL_GPL(ism_move);
static u16 ism_get_chid(struct dibs_dev *dibs)
{
@@ -518,14 +511,17 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
{
struct ism_dev *ism = data;
unsigned long bit, end;
+ struct dibs_dev *dibs;
unsigned long *bv;
u16 dmbemask;
u8 client_id;
+ dibs = ism->dibs;
+
bv = (void *) &ism->sba->dmb_bits[ISM_DMB_WORD_OFFSET];
end = sizeof(ism->sba->dmb_bits) * BITS_PER_BYTE - ISM_DMB_BIT_OFFSET;
- spin_lock(&ism->lock);
+ spin_lock(&dibs->lock);
ism->sba->s = 0;
barrier();
for (bit = 0;;) {
@@ -537,10 +533,13 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
dmbemask = ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET];
ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0;
barrier();
- client_id = ism->sba_client_arr[bit];
- if (unlikely(client_id == NO_CLIENT || !ism->subs[client_id]))
+ client_id = dibs->dmb_clientid_arr[bit];
+ if (unlikely(client_id == NO_DIBS_CLIENT ||
+ !dibs->subs[client_id]))
continue;
- ism->subs[client_id]->handle_irq(ism, bit + ISM_DMB_BIT_OFFSET, dmbemask);
+ dibs->subs[client_id]->ops->handle_irq(dibs,
+ bit + ISM_DMB_BIT_OFFSET,
+ dmbemask);
}
if (ism->sba->e) {
@@ -548,13 +547,17 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
barrier();
ism_handle_event(ism);
}
- spin_unlock(&ism->lock);
+ spin_unlock(&dibs->lock);
return IRQ_HANDLED;
}
static const struct dibs_dev_ops ism_ops = {
.get_fabric_id = ism_get_chid,
.query_remote_gid = ism_query_rgid,
+ .max_dmbs = ism_max_dmbs,
+ .register_dmb = ism_register_dmb,
+ .unregister_dmb = ism_unregister_dmb,
+ .move_data = ism_move,
.add_vlan_id = ism_add_vlan_id,
.del_vlan_id = ism_del_vlan_id,
};
@@ -568,15 +571,10 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret <= 0)
goto out;
- ism->sba_client_arr = kzalloc(ISM_NR_DMBS, GFP_KERNEL);
- if (!ism->sba_client_arr)
- goto free_vectors;
- memset(ism->sba_client_arr, NO_CLIENT, ISM_NR_DMBS);
-
ret = request_irq(pci_irq_vector(pdev, 0), ism_handle_irq, 0,
pci_name(pdev), ism);
if (ret)
- goto free_client_arr;
+ goto free_vectors;
ret = register_sba(ism);
if (ret)
@@ -605,8 +603,6 @@ static int ism_dev_init(struct ism_dev *ism)
unregister_sba(ism);
free_irq:
free_irq(pci_irq_vector(pdev, 0), ism);
-free_client_arr:
- kfree(ism->sba_client_arr);
free_vectors:
pci_free_irq_vectors(pdev);
out:
@@ -629,7 +625,6 @@ static void ism_dev_exit(struct ism_dev *ism)
unregister_ieq(ism);
unregister_sba(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);
@@ -677,6 +672,9 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dibs->drv_priv = ism;
dibs->ops = &ism_ops;
+ /* enable ism device, but any interrupts and events will be ignored
+ * before dibs_dev_add() adds it to any clients.
+ */
ret = ism_dev_init(ism);
if (ret)
goto err_dibs;
@@ -766,17 +764,6 @@ module_exit(ism_exit);
/*************************** SMC-D Implementation *****************************/
#if IS_ENABLED(CONFIG_SMC)
-static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
- void *client)
-{
- return ism_register_dmb(smcd->priv, (struct ism_dmb *)dmb, client);
-}
-
-static int smcd_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
-{
- return ism_unregister_dmb(smcd->priv, (struct ism_dmb *)dmb);
-}
-
static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
u32 event_code, u64 info)
{
@@ -801,18 +788,8 @@ static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid,
trigger_irq, event_code, info);
}
-static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
- bool sf, unsigned int offset, void *data,
- unsigned int size)
-{
- return ism_move(smcd->priv, dmb_tok, idx, sf, offset, data, size);
-}
-
static const struct smcd_ops ism_smcd_ops = {
- .register_dmb = smcd_register_dmb,
- .unregister_dmb = smcd_unregister_dmb,
.signal_event = smcd_signal_ieq,
- .move_data = smcd_move,
};
const struct smcd_ops *ism_get_smcd_ops(void)
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index c75a40fe3039..be009c614205 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -36,12 +36,44 @@
* clients.
*/
+/* DMB - Direct Memory Buffer
+ * --------------------------
+ * A dibs client provides a dmb as input buffer for a local receiving
+ * dibs device for exactly one (remote) sending dibs device. Only this
+ * sending device can send data into this dmb using move_data(). Sender
+ * and receiver can be the same device. A dmb belongs to exactly one client.
+ */
+struct dibs_dmb {
+ /* tok - Token for this dmb
+ * Used by remote and local devices and clients to address this dmb.
+ * Provided by dibs fabric. Unique per dibs fabric.
+ */
+ u64 dmb_tok;
+ /* rgid - GID of designated remote sending device */
+ uuid_t rgid;
+ /* cpu_addr - buffer address */
+ void *cpu_addr;
+ /* len - buffer length */
+ u32 dmb_len;
+ /* idx - Index of this DMB on this receiving device */
+ u32 idx;
+ /* VLAN support (deprecated)
+ * In order to write into a vlan-tagged dmb, the remote device needs
+ * to belong to the this vlan
+ */
+ u32 vlan_valid;
+ u32 vlan_id;
+ /* optional, used by device driver */
+ dma_addr_t dma_addr;
+};
+
struct dibs_dev;
/* DIBS client
* -----------
*/
#define MAX_DIBS_CLIENTS 8
+#define NO_DIBS_CLIENT 0xff
/* All dibs clients have access to all dibs devices.
* A dibs client provides the following functions to be called by dibs layer or
* dibs device drivers:
@@ -69,6 +101,22 @@ struct dibs_client_ops {
* The device is no longer usable by this client after this call.
*/
void (*del_dev)(struct dibs_dev *dev);
+ /**
+ * handle_irq() - Handle signaling for a DMB
+ * @dev: device that owns the dmb
+ * @idx: Index of the dmb that got signalled
+ * @dmbemask: signaling mask of the dmb
+ *
+ * Handle signaling for a dmb that was registered by this client
+ * for this device.
+ * The dibs device can coalesce multiple signaling triggers into a
+ * single call of handle_irq(). dmbemask can be used to indicate
+ * different kinds of triggers.
+ *
+ * Context: Called in IRQ context by dibs device driver
+ */
+ void (*handle_irq)(struct dibs_dev *dev, unsigned int idx,
+ u16 dmbemask);
};
struct dibs_client {
@@ -147,6 +195,77 @@ struct dibs_dev_ops {
*/
int (*query_remote_gid)(struct dibs_dev *dev, const uuid_t *rgid,
u32 vid_valid, u32 vid);
+ /**
+ * max_dmbs()
+ * Return: Max number of DMBs that can be registered for this kind of
+ * dibs_dev
+ */
+ int (*max_dmbs)(void);
+ /**
+ * register_dmb() - allocate and register a dmb
+ * @dev: dibs device
+ * @dmb: dmb struct to be registered
+ * @client: dibs client
+ * @vid: VLAN id; deprecated, ignored if device does not support vlan
+ *
+ * The following fields of dmb must provide valid input:
+ * @rgid: gid of remote user device
+ * @dmb_len: buffer length
+ * @idx: Optionally:requested idx (if non-zero)
+ * @vlan_valid: if zero, vlan_id will be ignored;
+ * deprecated, ignored if device does not support vlan
+ * @vlan_id: deprecated, ignored if device does not support vlan
+ * Upon return in addition the following fields will be valid:
+ * @dmb_tok: for usage by remote and local devices and clients
+ * @cpu_addr: allocated buffer
+ * @idx: dmb index, unique per dibs device
+ * @dma_addr: to be used by device driver,if applicable
+ *
+ * Allocate a dmb buffer and register it with this device and for this
+ * client.
+ * Return: zero on success
+ */
+ int (*register_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb,
+ struct dibs_client *client);
+ /**
+ * unregister_dmb() - unregister and free a dmb
+ * @dev: dibs device
+ * @dmb: dmb struct to be unregistered
+ * The following fields of dmb must provide valid input:
+ * @dmb_tok
+ * @cpu_addr
+ * @idx
+ *
+ * Free dmb.cpu_addr and unregister the dmb from this device.
+ * Return: zero on success
+ */
+ int (*unregister_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb);
+ /**
+ * move_data() - write into a remote dmb
+ * @dev: Local sending dibs device
+ * @dmb_tok: Token of the remote dmb
+ * @idx: signaling index in dmbemask
+ * @sf: signaling flag;
+ * if true, idx will be turned on at target dmbemask mask
+ * and target device will be signaled.
+ * @offset: offset within target dmb
+ * @data: pointer to data to be sent
+ * @size: length of data to be sent, can be zero.
+ *
+ * Use dev to write data of size at offset into a remote dmb
+ * identified by dmb_tok. Data is moved synchronously, *data can
+ * be freed when this function returns.
+ *
+ * If signaling flag (sf) is true, bit number idx bit will be turned
+ * on in the dmbemask mask when handle_irq() is called at the remote
+ * dibs client that owns the target dmb. The target device may chose
+ * to coalesce the signaling triggers of multiple move_data() calls
+ * to the same target dmb into a single handle_irq() call.
+ * Return: zero on success
+ */
+ int (*move_data)(struct dibs_dev *dev, u64 dmb_tok, unsigned int idx,
+ bool sf, unsigned int offset, void *data,
+ unsigned int size);
/**
* add_vlan_id() - add dibs device to vlan (optional, deprecated)
* @dev: dibs device
@@ -166,6 +285,55 @@ struct dibs_dev_ops {
* Return: zero on success
*/
int (*del_vlan_id)(struct dibs_dev *dev, u64 vlan_id);
+ /**
+ * support_mmapped_rdmb() - can this device provide memory mapped
+ * remote dmbs? (optional)
+ * @dev: dibs device
+ *
+ * A dibs device can provide a kernel address + length, that represent
+ * a remote target dmb (like MMIO). Alternatively to calling
+ * move_data(), a dibs client can write into such a ghost-send-buffer
+ * (= to this kernel address) and the data will automatically
+ * immediately appear in the target dmb, even without calling
+ * move_data().
+ *
+ * Either all 3 function pointers for support_dmb_nocopy(),
+ * attach_dmb() and detach_dmb() are defined, or all of them must
+ * be NULL.
+ *
+ * Return: non-zero, if memory mapped remote dmbs are supported.
+ */
+ int (*support_mmapped_rdmb)(struct dibs_dev *dev);
+ /**
+ * attach_dmb() - attach local memory to a remote dmb
+ * @dev: Local sending ism device
+ * @dmb: all other parameters are passed in the form of a
+ * dmb struct
+ * TODO: (THIS IS CONFUSING, should be changed)
+ * dmb_tok: (in) Token of the remote dmb, we want to attach to
+ * cpu_addr: (out) MMIO address
+ * dma_addr: (out) MMIO address (if applicable, invalid otherwise)
+ * dmb_len: (out) length of local MMIO region,
+ * equal to length of remote DMB.
+ * sba_idx: (out) index of remote dmb (NOT HELPFUL, should be removed)
+ *
+ * Provides a memory address to the sender that can be used to
+ * directly write into the remote dmb.
+ * Memory is available until detach_dmb is called
+ *
+ * Return: Zero upon success, Error code otherwise
+ */
+ int (*attach_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb);
+ /**
+ * detach_dmb() - Detach the ghost buffer from a remote dmb
+ * @dev: ism device
+ * @token: dmb token of the remote dmb
+ *
+ * No need to free cpu_addr.
+ *
+ * Return: Zero upon success, Error code otherwise
+ */
+ int (*detach_dmb)(struct dibs_dev *dev, u64 token);
};
struct dibs_dev {
@@ -179,6 +347,15 @@ struct dibs_dev {
/* priv pointer per client; for client usage only */
void *priv[MAX_DIBS_CLIENTS];
+
+ /* get this lock before accessing any of the fields below */
+ spinlock_t lock;
+ /* array of client ids indexed by dmb idx;
+ * can be used as indices into priv and subs arrays
+ */
+ u8 *dmb_clientid_arr;
+ /* Sparse array of all ISM clients */
+ struct dibs_client *subs[MAX_DIBS_CLIENTS];
};
static inline void dibs_set_priv(struct dibs_dev *dev,
diff --git a/include/linux/ism.h b/include/linux/ism.h
index a926dd61b5a1..b7feb4dcd5a8 100644
--- a/include/linux/ism.h
+++ b/include/linux/ism.h
@@ -11,17 +11,6 @@
#include <linux/workqueue.h>
-struct ism_dmb {
- u64 dmb_tok;
- u64 rgid;
- u32 dmb_len;
- u32 sba_idx;
- u32 vlan_valid;
- u32 vlan_id;
- void *cpu_addr;
- dma_addr_t dma_addr;
-};
-
/* Unless we gain unexpected popularity, this limit should hold for a while */
#define MAX_CLIENTS 8
#define ISM_NR_DMBS 1920
@@ -36,7 +25,6 @@ struct ism_dev {
struct ism_sba *sba;
dma_addr_t sba_dma_addr;
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
- u8 *sba_client_arr; /* entries are indices into 'clients' array */
void *priv[MAX_CLIENTS];
struct ism_eq *ieq;
@@ -58,11 +46,6 @@ struct ism_event {
struct ism_client {
const char *name;
void (*handle_event)(struct ism_dev *dev, struct ism_event *event);
- /* Parameter dmbemask contains a bit vector with updated DMBEs, if sent
- * via ism_move_data(). Callback function must handle all active bits
- * indicated by dmbemask.
- */
- void (*handle_irq)(struct ism_dev *dev, unsigned int bit, u16 dmbemask);
/* Private area - don't touch! */
u8 id;
};
@@ -79,12 +62,6 @@ static inline void ism_set_priv(struct ism_dev *dev, struct ism_client *client,
dev->priv[client->id] = priv;
}
-int ism_register_dmb(struct ism_dev *dev, struct ism_dmb *dmb,
- struct ism_client *client);
-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);
-
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 5bd135fb4d49..8e3debcf7db5 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -28,17 +28,6 @@ struct smc_hashinfo {
};
/* SMCD/ISM device driver interface */
-struct smcd_dmb {
- u64 dmb_tok;
- u64 rgid;
- u32 dmb_len;
- u32 sba_idx;
- u32 vlan_valid;
- u32 vlan_id;
- void *cpu_addr;
- dma_addr_t dma_addr;
-};
-
#define ISM_EVENT_DMB 0
#define ISM_EVENT_GID 1
#define ISM_EVENT_SWR 2
@@ -53,25 +42,14 @@ struct smcd_gid {
};
struct smcd_ops {
- int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
- void *client);
- int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
- int (*move_data)(struct smcd_dev *dev, u64 dmb_tok, unsigned int idx,
- bool sf, unsigned int offset, void *data,
- unsigned int size);
-
/* optional operations */
int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
u32 trigger_irq, u32 event_code, u64 info);
- int (*support_dmb_nocopy)(struct smcd_dev *dev);
- int (*attach_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
- int (*detach_dmb)(struct smcd_dev *dev, u64 token);
};
struct smcd_dev {
const struct smcd_ops *ops;
void *priv;
- void *client;
struct dibs_dev *dibs;
struct list_head list;
spinlock_t lock;
diff --git a/net/smc/Makefile b/net/smc/Makefile
index 96ccfdf246df..0e754cbc38f9 100644
--- a/net/smc/Makefile
+++ b/net/smc/Makefile
@@ -6,4 +6,3 @@ smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o
smc-y += smc_tracepoint.o smc_inet.o
smc-$(CONFIG_SYSCTL) += smc_sysctl.o
-smc-y += smc_loopback.o
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index d20d00b46825..01e49371d23d 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -15,7 +15,6 @@
#include "smc.h"
#include "smc_core.h"
#include "smc_ism.h"
-#include "smc_loopback.h"
#include "smc_pnet.h"
#include "smc_netlink.h"
#include "linux/ism.h"
@@ -33,18 +32,19 @@ static void smcd_register_dev(struct dibs_dev *dibs);
static void smcd_unregister_dev(struct dibs_dev *dibs);
#if IS_ENABLED(CONFIG_ISM)
static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event);
-static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
- u16 dmbemask);
static struct ism_client smc_ism_client = {
.name = "SMC-D",
.handle_event = smcd_handle_event,
- .handle_irq = smcd_handle_irq,
};
#endif
+static void smcd_handle_irq(struct dibs_dev *dibs, unsigned int dmbno,
+ u16 dmbemask);
+
static struct dibs_client_ops smc_client_ops = {
.add_dev = smcd_register_dev,
.del_dev = smcd_unregister_dev,
+ .handle_irq = smcd_handle_irq,
};
static struct dibs_client smc_dibs_client = {
@@ -221,18 +221,19 @@ int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid)
void smc_ism_unregister_dmb(struct smcd_dev *smcd,
struct smc_buf_desc *dmb_desc)
{
- struct smcd_dmb dmb;
+ struct dibs_dmb dmb;
if (!dmb_desc->dma_addr)
return;
memset(&dmb, 0, sizeof(dmb));
dmb.dmb_tok = dmb_desc->token;
- dmb.sba_idx = dmb_desc->sba_idx;
+ dmb.idx = dmb_desc->sba_idx;
dmb.cpu_addr = dmb_desc->cpu_addr;
dmb.dma_addr = dmb_desc->dma_addr;
dmb.dmb_len = dmb_desc->len;
- smcd->ops->unregister_dmb(smcd, &dmb);
+
+ smcd->dibs->ops->unregister_dmb(smcd->dibs, &dmb);
return;
}
@@ -240,17 +241,20 @@ void smc_ism_unregister_dmb(struct smcd_dev *smcd,
int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
struct smc_buf_desc *dmb_desc)
{
- struct smcd_dmb dmb;
+ struct dibs_dev *dibs;
+ struct dibs_dmb dmb;
int rc;
memset(&dmb, 0, sizeof(dmb));
dmb.dmb_len = dmb_len;
- dmb.sba_idx = dmb_desc->sba_idx;
+ dmb.idx = dmb_desc->sba_idx;
dmb.vlan_id = lgr->vlan_id;
- dmb.rgid = lgr->peer_gid.gid;
- rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, lgr->smcd->client);
+ copy_to_dibsgid(&dmb.rgid, &lgr->peer_gid);
+
+ dibs = lgr->smcd->dibs;
+ rc = dibs->ops->register_dmb(dibs, &dmb, &smc_dibs_client);
if (!rc) {
- dmb_desc->sba_idx = dmb.sba_idx;
+ dmb_desc->sba_idx = dmb.idx;
dmb_desc->token = dmb.dmb_tok;
dmb_desc->cpu_addr = dmb.cpu_addr;
dmb_desc->dma_addr = dmb.dma_addr;
@@ -265,24 +269,24 @@ bool smc_ism_support_dmb_nocopy(struct smcd_dev *smcd)
* merging sndbuf with peer DMB to avoid
* data copies between them.
*/
- return (smcd->ops->support_dmb_nocopy &&
- smcd->ops->support_dmb_nocopy(smcd));
+ return (smcd->dibs->ops->support_mmapped_rdmb &&
+ smcd->dibs->ops->support_mmapped_rdmb(smcd->dibs));
}
int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
struct smc_buf_desc *dmb_desc)
{
- struct smcd_dmb dmb;
+ struct dibs_dmb dmb;
int rc = 0;
- if (!dev->ops->attach_dmb)
+ if (!dev->dibs->ops->attach_dmb)
return -EINVAL;
memset(&dmb, 0, sizeof(dmb));
dmb.dmb_tok = token;
- rc = dev->ops->attach_dmb(dev, &dmb);
+ rc = dev->dibs->ops->attach_dmb(dev->dibs, &dmb);
if (!rc) {
- dmb_desc->sba_idx = dmb.sba_idx;
+ dmb_desc->sba_idx = dmb.idx;
dmb_desc->token = dmb.dmb_tok;
dmb_desc->cpu_addr = dmb.cpu_addr;
dmb_desc->dma_addr = dmb.dma_addr;
@@ -294,10 +298,10 @@ int smc_ism_attach_dmb(struct smcd_dev *dev, u64 token,
int smc_ism_detach_dmb(struct smcd_dev *dev, u64 token)
{
- if (!dev->ops->detach_dmb)
+ if (!dev->dibs->ops->detach_dmb)
return -EINVAL;
- return dev->ops->detach_dmb(dev, token);
+ return dev->dibs->ops->detach_dmb(dev->dibs, token);
}
static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
@@ -503,26 +507,20 @@ static void smcd_register_dev(struct dibs_dev *dibs)
{
struct smcd_dev *smcd, *fentry;
const struct smcd_ops *ops;
- struct smc_lo_dev *smc_lo;
struct ism_dev *ism;
+ int max_dmbs;
- if (smc_ism_is_loopback(dibs)) {
- if (smc_loopback_init(&smc_lo))
- return;
- }
+ max_dmbs = dibs->ops->max_dmbs();
if (smc_ism_is_loopback(dibs)) {
- ops = smc_lo_get_smcd_ops();
- smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops,
- SMC_LO_MAX_DMBS);
+ ops = NULL;
} else {
ism = dibs->drv_priv;
#if IS_ENABLED(CONFIG_ISM)
ops = ism_get_smcd_ops();
#endif
- smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops,
- ISM_NR_DMBS);
}
+ smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops, max_dmbs);
if (!smcd)
return;
@@ -530,13 +528,11 @@ static void smcd_register_dev(struct dibs_dev *dibs)
dibs_set_priv(dibs, &smc_dibs_client, smcd);
if (smc_ism_is_loopback(dibs)) {
- smcd->priv = smc_lo;
- smc_lo->smcd = smcd;
+ smcd->priv = NULL;
} else {
smcd->priv = ism;
#if IS_ENABLED(CONFIG_ISM)
ism_set_priv(ism, &smc_ism_client, smcd);
- smcd->client = &smc_ism_client;
#endif
}
@@ -590,8 +586,6 @@ static void smcd_unregister_dev(struct dibs_dev *dibs)
list_del_init(&smcd->list);
mutex_unlock(&smcd_dev_list.mutex);
destroy_workqueue(smcd->event_wq);
- if (smc_ism_is_loopback(dibs))
- smc_loopback_exit();
kfree(smcd->conn);
kfree(smcd);
}
@@ -624,6 +618,7 @@ static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
wrk->event = *event;
queue_work(smcd->event_wq, &wrk->work);
}
+#endif
/* SMCD Device interrupt handler. Called from ISM device interrupt handler.
* Parameters are the ism device pointer, DMB number, and the DMBE bitmask.
@@ -632,10 +627,10 @@ static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
* Context:
* - Function called in IRQ context from ISM device driver IRQ handler.
*/
-static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
+static void smcd_handle_irq(struct dibs_dev *dibs, unsigned int dmbno,
u16 dmbemask)
{
- struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
+ struct smcd_dev *smcd = dibs_get_priv(dibs, &smc_dibs_client);
struct smc_connection *conn = NULL;
unsigned long flags;
@@ -645,7 +640,6 @@ static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
tasklet_schedule(&conn->rx_tsklet);
spin_unlock_irqrestore(&smcd->lock, flags);
}
-#endif
int smc_ism_signal_shutdown(struct smc_link_group *lgr)
{
diff --git a/net/smc/smc_ism.h b/net/smc/smc_ism.h
index 139e99da2c9f..a1575e31df73 100644
--- a/net/smc/smc_ism.h
+++ b/net/smc/smc_ism.h
@@ -69,7 +69,9 @@ static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok,
{
int rc;
- rc = smcd->ops->move_data(smcd, dmb_tok, idx, sf, offset, data, len);
+ rc = smcd->dibs->ops->move_data(smcd->dibs, dmb_tok, idx, sf, offset,
+ data, len);
+
return rc < 0 ? rc : 0;
}
diff --git a/net/smc/smc_loopback.c b/net/smc/smc_loopback.c
deleted file mode 100644
index 52cba01cb209..000000000000
--- a/net/smc/smc_loopback.c
+++ /dev/null
@@ -1,294 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Shared Memory Communications Direct over loopback-ism device.
- *
- * Functions for loopback-ism device.
- *
- * Copyright (c) 2024, Alibaba Inc.
- *
- * Author: Wen Gu <guwen@linux.alibaba.com>
- * Tony Lu <tonylu@linux.alibaba.com>
- *
- */
-
-#include <linux/device.h>
-#include <linux/types.h>
-#include <linux/dibs.h>
-#include <net/smc.h>
-
-#include "smc_cdc.h"
-#include "smc_ism.h"
-#include "smc_loopback.h"
-
-#define SMC_LO_SUPPORT_NOCOPY 0x1
-#define SMC_DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-static struct smc_lo_dev *lo_dev;
-
-static int smc_lo_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
- void *client_priv)
-{
- struct smc_lo_dmb_node *dmb_node, *tmp_node;
- struct smc_lo_dev *ldev = smcd->priv;
- int sba_idx, rc;
-
- /* check space for new dmb */
- for_each_clear_bit(sba_idx, ldev->sba_idx_mask, SMC_LO_MAX_DMBS) {
- if (!test_and_set_bit(sba_idx, ldev->sba_idx_mask))
- break;
- }
- if (sba_idx == SMC_LO_MAX_DMBS)
- return -ENOSPC;
-
- dmb_node = kzalloc(sizeof(*dmb_node), GFP_KERNEL);
- if (!dmb_node) {
- rc = -ENOMEM;
- goto err_bit;
- }
-
- dmb_node->sba_idx = sba_idx;
- dmb_node->len = dmb->dmb_len;
- dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL |
- __GFP_NOWARN | __GFP_NORETRY |
- __GFP_NOMEMALLOC);
- if (!dmb_node->cpu_addr) {
- rc = -ENOMEM;
- goto err_node;
- }
- dmb_node->dma_addr = SMC_DMA_ADDR_INVALID;
- refcount_set(&dmb_node->refcnt, 1);
-
-again:
- /* add new dmb into hash table */
- get_random_bytes(&dmb_node->token, sizeof(dmb_node->token));
- write_lock_bh(&ldev->dmb_ht_lock);
- hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_node->token) {
- if (tmp_node->token == dmb_node->token) {
- write_unlock_bh(&ldev->dmb_ht_lock);
- goto again;
- }
- }
- hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
- write_unlock_bh(&ldev->dmb_ht_lock);
- atomic_inc(&ldev->dmb_cnt);
-
- dmb->sba_idx = dmb_node->sba_idx;
- dmb->dmb_tok = dmb_node->token;
- dmb->cpu_addr = dmb_node->cpu_addr;
- dmb->dma_addr = dmb_node->dma_addr;
- dmb->dmb_len = dmb_node->len;
-
- return 0;
-
-err_node:
- kfree(dmb_node);
-err_bit:
- clear_bit(sba_idx, ldev->sba_idx_mask);
- return rc;
-}
-
-static void __smc_lo_unregister_dmb(struct smc_lo_dev *ldev,
- struct smc_lo_dmb_node *dmb_node)
-{
- /* remove dmb from hash table */
- write_lock_bh(&ldev->dmb_ht_lock);
- hash_del(&dmb_node->list);
- write_unlock_bh(&ldev->dmb_ht_lock);
-
- clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
- kvfree(dmb_node->cpu_addr);
- kfree(dmb_node);
-
- if (atomic_dec_and_test(&ldev->dmb_cnt))
- wake_up(&ldev->ldev_release);
-}
-
-static int smc_lo_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
-{
- struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
- struct smc_lo_dev *ldev = smcd->priv;
-
- /* find dmb from hash table */
- read_lock_bh(&ldev->dmb_ht_lock);
- hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
- if (tmp_node->token == dmb->dmb_tok) {
- dmb_node = tmp_node;
- break;
- }
- }
- if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
- return -EINVAL;
- }
- read_unlock_bh(&ldev->dmb_ht_lock);
-
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __smc_lo_unregister_dmb(ldev, dmb_node);
- return 0;
-}
-
-static int smc_lo_support_dmb_nocopy(struct smcd_dev *smcd)
-{
- return SMC_LO_SUPPORT_NOCOPY;
-}
-
-static int smc_lo_attach_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
-{
- struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
- struct smc_lo_dev *ldev = smcd->priv;
-
- /* find dmb_node according to dmb->dmb_tok */
- read_lock_bh(&ldev->dmb_ht_lock);
- hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
- if (tmp_node->token == dmb->dmb_tok) {
- dmb_node = tmp_node;
- break;
- }
- }
- if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
- return -EINVAL;
- }
- read_unlock_bh(&ldev->dmb_ht_lock);
-
- if (!refcount_inc_not_zero(&dmb_node->refcnt))
- /* the dmb is being unregistered, but has
- * not been removed from the hash table.
- */
- return -EINVAL;
-
- /* provide dmb information */
- dmb->sba_idx = dmb_node->sba_idx;
- dmb->dmb_tok = dmb_node->token;
- dmb->cpu_addr = dmb_node->cpu_addr;
- dmb->dma_addr = dmb_node->dma_addr;
- dmb->dmb_len = dmb_node->len;
- return 0;
-}
-
-static int smc_lo_detach_dmb(struct smcd_dev *smcd, u64 token)
-{
- struct smc_lo_dmb_node *dmb_node = NULL, *tmp_node;
- struct smc_lo_dev *ldev = smcd->priv;
-
- /* find dmb_node according to dmb->dmb_tok */
- read_lock_bh(&ldev->dmb_ht_lock);
- hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
- if (tmp_node->token == token) {
- dmb_node = tmp_node;
- break;
- }
- }
- if (!dmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
- return -EINVAL;
- }
- read_unlock_bh(&ldev->dmb_ht_lock);
-
- if (refcount_dec_and_test(&dmb_node->refcnt))
- __smc_lo_unregister_dmb(ldev, dmb_node);
- return 0;
-}
-
-static int smc_lo_move_data(struct smcd_dev *smcd, u64 dmb_tok,
- unsigned int idx, bool sf, unsigned int offset,
- void *data, unsigned int size)
-{
- struct smc_lo_dmb_node *rmb_node = NULL, *tmp_node;
- struct smc_lo_dev *ldev = smcd->priv;
- struct smc_connection *conn;
-
- read_lock_bh(&ldev->dmb_ht_lock);
- hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
- if (tmp_node->token == dmb_tok) {
- rmb_node = tmp_node;
- break;
- }
- }
- if (!rmb_node) {
- read_unlock_bh(&ldev->dmb_ht_lock);
- return -EINVAL;
- }
- memcpy((char *)rmb_node->cpu_addr + offset, data, size);
- read_unlock_bh(&ldev->dmb_ht_lock);
-
- if (!sf)
- return 0;
-
- conn = smcd->conn[rmb_node->sba_idx];
- if (!conn || conn->killed)
- return -EPIPE;
- tasklet_schedule(&conn->rx_tsklet);
- return 0;
-}
-
-static const struct smcd_ops lo_ops = {
- .register_dmb = smc_lo_register_dmb,
- .unregister_dmb = smc_lo_unregister_dmb,
- .support_dmb_nocopy = smc_lo_support_dmb_nocopy,
- .attach_dmb = smc_lo_attach_dmb,
- .detach_dmb = smc_lo_detach_dmb,
- .signal_event = NULL,
- .move_data = smc_lo_move_data,
-};
-
-const struct smcd_ops *smc_lo_get_smcd_ops(void)
-{
- return &lo_ops;
-}
-
-static void smc_lo_dev_init(struct smc_lo_dev *ldev)
-{
- rwlock_init(&ldev->dmb_ht_lock);
- hash_init(ldev->dmb_ht);
- atomic_set(&ldev->dmb_cnt, 0);
- init_waitqueue_head(&ldev->ldev_release);
-
- return;
-}
-
-static void smc_lo_dev_exit(struct smc_lo_dev *ldev)
-{
- if (atomic_read(&ldev->dmb_cnt))
- wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
-}
-
-static int smc_lo_dev_probe(void)
-{
- struct smc_lo_dev *ldev;
-
- ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
- if (!ldev)
- return -ENOMEM;
-
- smc_lo_dev_init(ldev);
-
- lo_dev = ldev; /* global loopback device */
-
- return 0;
-}
-
-static void smc_lo_dev_remove(void)
-{
- if (!lo_dev)
- return;
-
- smc_lo_dev_exit(lo_dev);
- kfree(lo_dev);
- lo_dev = NULL;
-}
-
-int smc_loopback_init(struct smc_lo_dev **smc_lb)
-{
- int ret;
-
- ret = smc_lo_dev_probe();
- if (!ret)
- *smc_lb = lo_dev;
- return ret;
-}
-
-void smc_loopback_exit(void)
-{
- smc_lo_dev_remove();
-}
diff --git a/net/smc/smc_loopback.h b/net/smc/smc_loopback.h
deleted file mode 100644
index 33bb96ec8b77..000000000000
--- a/net/smc/smc_loopback.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Shared Memory Communications Direct over loopback-ism device.
- *
- * SMC-D loopback-ism device structure definitions.
- *
- * Copyright (c) 2024, Alibaba Inc.
- *
- * Author: Wen Gu <guwen@linux.alibaba.com>
- * Tony Lu <tonylu@linux.alibaba.com>
- *
- */
-
-#ifndef _SMC_LOOPBACK_H
-#define _SMC_LOOPBACK_H
-
-#include <linux/device.h>
-#include <net/smc.h>
-
-#define SMC_LO_MAX_DMBS 5000
-#define SMC_LO_DMBS_HASH_BITS 12
-
-struct smc_lo_dmb_node {
- struct hlist_node list;
- u64 token;
- u32 len;
- u32 sba_idx;
- void *cpu_addr;
- dma_addr_t dma_addr;
- refcount_t refcnt;
-};
-
-struct smc_lo_dev {
- struct smcd_dev *smcd;
- atomic_t dmb_cnt;
- rwlock_t dmb_ht_lock;
- DECLARE_BITMAP(sba_idx_mask, SMC_LO_MAX_DMBS);
- DECLARE_HASHTABLE(dmb_ht, SMC_LO_DMBS_HASH_BITS);
- wait_queue_head_t ldev_release;
-};
-
-const struct smcd_ops *smc_lo_get_smcd_ops(void);
-
-int smc_loopback_init(struct smc_lo_dev **smc_lb);
-void smc_loopback_exit(void);
-
-#endif /* _SMC_LOOPBACK_H */
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v3 14/14] dibs: Move event handling to dibs layer
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (12 preceding siblings ...)
2025-09-18 11:04 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer Alexandra Winter
@ 2025-09-18 11:05 ` Alexandra Winter
2025-09-23 9:20 ` [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing patchwork-bot+netdevbpf
14 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-18 11:05 UTC (permalink / raw)
To: D. Wythe, Dust Li, Sidraya Jayagond, Wenjia Zhang, David Miller,
Jakub Kicinski, Paolo Abeni, Eric Dumazet, Andrew Lunn
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe
From: Julian Ruess <julianr@linux.ibm.com>
Add defines for all event types and subtypes an ism device is known to
produce as it can be helpful for debugging purposes.
Introduces a generic 'struct dibs_event' and adopt ism device driver
and smc-d client accordingly. Tolerate and ignore other type and subtype
values to enable future device extensions.
SMC-D and ISM are now independent.
struct ism_dev can be moved to drivers/s390/net/ism.h.
Note that in smc, the term 'ism' is still used. Future patches could
replace that with 'dibs' or 'smc-d' as appropriate.
Signed-off-by: Julian Ruess <julianr@linux.ibm.com>
Co-developed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
---
MAINTAINERS | 2 -
arch/s390/configs/debug_defconfig | 1 +
arch/s390/configs/defconfig | 1 +
drivers/dibs/dibs_main.c | 2 +-
drivers/s390/net/Kconfig | 1 -
drivers/s390/net/ism.h | 42 +++++-
drivers/s390/net/ism_drv.c | 221 ++++++++++--------------------
include/linux/dibs.h | 62 +++++++++
include/net/smc.h | 15 --
net/smc/Kconfig | 1 -
net/smc/smc_ism.c | 99 +++++--------
11 files changed, 208 insertions(+), 239 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 10d3ccebaa73..eccfc2eb153f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17576,7 +17576,6 @@ F: include/linux/fddidevice.h
F: include/linux/hippidevice.h
F: include/linux/if_*
F: include/linux/inetdevice.h
-F: include/linux/ism.h
F: include/linux/netdev*
F: include/linux/platform_data/wiznet.h
F: include/uapi/linux/cn_proc.h
@@ -22233,7 +22232,6 @@ L: linux-s390@vger.kernel.org
L: netdev@vger.kernel.org
S: Supported
F: drivers/s390/net/
-F: include/linux/ism.h
S390 PCI SUBSYSTEM
M: Niklas Schnelle <schnelle@linux.ibm.com>
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index a97c8d19f643..fdde8ee0d7bd 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -122,6 +122,7 @@ CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
+CONFIG_SMC=m
CONFIG_SMC_DIAG=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index 7f7b52d9a33c..bf9e7dbd4a89 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -113,6 +113,7 @@ CONFIG_XFRM_USER=m
CONFIG_NET_KEY=m
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
+CONFIG_SMC=m
CONFIG_SMC_DIAG=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index aacb3ea7825a..5425238d5a42 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -98,7 +98,7 @@ int dibs_unregister_client(struct dibs_client *client)
goto err_reg_dmb;
}
}
- /* Stop forwarding IRQs */
+ /* Stop forwarding IRQs and events */
dibs->subs[client->id] = NULL;
spin_unlock_irqrestore(&dibs->lock, flags);
clients[client->id]->ops->del_dev(dibs);
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 92985f595d59..0fd700c5745a 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -82,7 +82,6 @@ config CCWGROUP
config ISM
tristate "Support for ISM vPCI Adapter"
depends on PCI && DIBS
- imply SMC
default n
help
Select this option if you want to use the Internal Shared Memory
diff --git a/drivers/s390/net/ism.h b/drivers/s390/net/ism.h
index 1b9fa14da20c..08d17956cb36 100644
--- a/drivers/s390/net/ism.h
+++ b/drivers/s390/net/ism.h
@@ -6,13 +6,13 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/dibs.h>
-#include <linux/ism.h>
-#include <net/smc.h>
#include <asm/pci_insn.h>
#define UTIL_STR_LEN 16
#define ISM_ERROR 0xFFFF
+#define ISM_NR_DMBS 1920
+
/*
* Do not use the first word of the DMB bits to ensure 8 byte aligned access.
*/
@@ -34,6 +34,23 @@
#define ISM_UNREG_SBA 0x11
#define ISM_UNREG_IEQ 0x12
+enum ism_event_type {
+ ISM_EVENT_BUF = 0x00,
+ ISM_EVENT_DEV = 0x01,
+ ISM_EVENT_SWR = 0x02
+};
+
+enum ism_event_code {
+ ISM_BUF_DMB_UNREGISTERED = 0x04,
+ ISM_BUF_USING_ISM_DEV_DISABLED = 0x08,
+ ISM_BUF_OWNING_ISM_DEV_IN_ERR_STATE = 0x02,
+ ISM_BUF_USING_ISM_DEV_IN_ERR_STATE = 0x03,
+ ISM_BUF_VLAN_MISMATCH_WITH_OWNER = 0x05,
+ ISM_BUF_VLAN_MISMATCH_WITH_USER = 0x06,
+ ISM_DEV_GID_DISABLED = 0x07,
+ ISM_DEV_GID_ERR_STATE = 0x01
+};
+
struct ism_req_hdr {
u32 cmd;
u16 : 16;
@@ -185,6 +202,14 @@ struct ism_eq_header {
u64 : 64;
};
+struct ism_event {
+ u32 type;
+ u32 code;
+ u64 tok;
+ u64 time;
+ u64 info;
+};
+
struct ism_eq {
struct ism_eq_header header;
struct ism_event entry[15];
@@ -199,6 +224,19 @@ struct ism_sba {
u16 dmbe_mask[ISM_NR_DMBS];
};
+struct ism_dev {
+ spinlock_t cmd_lock; /* serializes cmds */
+ struct dibs_dev *dibs;
+ struct pci_dev *pdev;
+ struct ism_sba *sba;
+ dma_addr_t sba_dma_addr;
+ DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
+
+ struct ism_eq *ieq;
+ dma_addr_t ieq_dma_addr;
+ int ieq_idx;
+};
+
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \
((dmb) | (idx) << 24 | (sf) << 23 | (offset))
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
index 346d1ea8650b..f84aa2e676e9 100644
--- a/drivers/s390/net/ism_drv.c
+++ b/drivers/s390/net/ism_drv.c
@@ -31,86 +31,6 @@ 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);
-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;
- 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;
- 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;
-}
-EXPORT_SYMBOL_GPL(ism_unregister_client);
-
static int ism_cmd(struct ism_dev *ism, void *cmd)
{
struct ism_req_hdr *req = cmd;
@@ -445,6 +365,24 @@ static int ism_del_vlan_id(struct dibs_dev *dibs, u64 vlan_id)
return ism_cmd(ism, &cmd);
}
+static int ism_signal_ieq(struct dibs_dev *dibs, const uuid_t *rgid,
+ u32 trigger_irq, u32 event_code, u64 info)
+{
+ struct ism_dev *ism = dibs->drv_priv;
+ union ism_sig_ieq cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.request.hdr.cmd = ISM_SIGNAL_IEQ;
+ cmd.request.hdr.len = sizeof(cmd.request);
+
+ memcpy(&cmd.request.rgid, rgid, sizeof(cmd.request.rgid));
+ cmd.request.trigger_irq = trigger_irq;
+ cmd.request.event_code = event_code;
+ cmd.request.info = info;
+
+ return ism_cmd(ism, &cmd);
+}
+
static unsigned int max_bytes(unsigned int start, unsigned int len,
unsigned int boundary)
{
@@ -487,22 +425,68 @@ static u16 ism_get_chid(struct dibs_dev *dibs)
return to_zpci(ism->pdev)->pchid;
}
+static int ism_match_event_type(u32 s390_event_type)
+{
+ switch (s390_event_type) {
+ case ISM_EVENT_BUF:
+ return DIBS_BUF_EVENT;
+ case ISM_EVENT_DEV:
+ return DIBS_DEV_EVENT;
+ case ISM_EVENT_SWR:
+ return DIBS_SW_EVENT;
+ default:
+ return DIBS_OTHER_TYPE;
+ }
+}
+
+static int ism_match_event_subtype(u32 s390_event_subtype)
+{
+ switch (s390_event_subtype) {
+ case ISM_BUF_DMB_UNREGISTERED:
+ return DIBS_BUF_UNREGISTERED;
+ case ISM_DEV_GID_DISABLED:
+ return DIBS_DEV_DISABLED;
+ case ISM_DEV_GID_ERR_STATE:
+ return DIBS_DEV_ERR_STATE;
+ default:
+ return DIBS_OTHER_SUBTYPE;
+ }
+}
+
static void ism_handle_event(struct ism_dev *ism)
{
+ struct dibs_dev *dibs = ism->dibs;
+ struct dibs_event event;
struct ism_event *entry;
- struct ism_client *clt;
+ struct dibs_client *clt;
int i;
while ((ism->ieq_idx + 1) != READ_ONCE(ism->ieq->header.idx)) {
- if (++(ism->ieq_idx) == ARRAY_SIZE(ism->ieq->entry))
+ if (++ism->ieq_idx == ARRAY_SIZE(ism->ieq->entry))
ism->ieq_idx = 0;
entry = &ism->ieq->entry[ism->ieq_idx];
debug_event(ism_debug_info, 2, entry, sizeof(*entry));
- for (i = 0; i < max_client; ++i) {
- clt = ism->subs[i];
+ __memset(&event, 0, sizeof(event));
+ event.type = ism_match_event_type(entry->type);
+ if (event.type == DIBS_SW_EVENT)
+ event.subtype = entry->code;
+ else
+ event.subtype = ism_match_event_subtype(entry->code);
+ event.time = entry->time;
+ event.data = entry->info;
+ switch (event.type) {
+ case DIBS_BUF_EVENT:
+ event.buffer_tok = entry->tok;
+ break;
+ case DIBS_DEV_EVENT:
+ case DIBS_SW_EVENT:
+ memcpy(&event.gid, &entry->tok, sizeof(u64));
+ }
+ for (i = 0; i < MAX_DIBS_CLIENTS; ++i) {
+ clt = dibs->subs[i];
if (clt)
- clt->handle_event(ism, entry);
+ clt->ops->handle_event(dibs, &event);
}
}
}
@@ -560,12 +544,13 @@ static const struct dibs_dev_ops ism_ops = {
.move_data = ism_move,
.add_vlan_id = ism_add_vlan_id,
.del_vlan_id = ism_del_vlan_id,
+ .signal_event = ism_signal_ieq,
};
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)
@@ -584,18 +569,6 @@ static int ism_dev_init(struct ism_dev *ism)
if (ret)
goto unreg_sba;
- mutex_lock(&ism_dev_list.mutex);
- mutex_lock(&clients_lock);
- for (i = 0; i < max_client; ++i) {
- if (clients[i]) {
- ism_setup_forwarding(clients[i], ism);
- }
- }
- mutex_unlock(&clients_lock);
-
- list_add(&ism->list, &ism_dev_list.list);
- mutex_unlock(&ism_dev_list.mutex);
-
query_info(ism);
return 0;
@@ -612,22 +585,11 @@ static int ism_dev_init(struct ism_dev *ism)
static void ism_dev_exit(struct ism_dev *ism)
{
struct pci_dev *pdev = ism->pdev;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ism->lock, flags);
- for (i = 0; i < max_client; ++i)
- ism->subs[i] = NULL;
- spin_unlock_irqrestore(&ism->lock, flags);
-
- mutex_lock(&ism_dev_list.mutex);
unregister_ieq(ism);
unregister_sba(ism);
free_irq(pci_irq_vector(pdev, 0), ism);
pci_free_irq_vectors(pdev);
- list_del_init(&ism->list);
- mutex_unlock(&ism_dev_list.mutex);
}
static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -641,7 +603,6 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!ism)
return -ENOMEM;
- spin_lock_init(&ism->lock);
spin_lock_init(&ism->cmd_lock);
dev_set_drvdata(&pdev->dev, ism);
ism->pdev = pdev;
@@ -742,8 +703,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)
@@ -760,41 +719,3 @@ static void __exit ism_exit(void)
module_init(ism_init);
module_exit(ism_exit);
-
-/*************************** SMC-D Implementation *****************************/
-
-#if IS_ENABLED(CONFIG_SMC)
-static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
- u32 event_code, u64 info)
-{
- union ism_sig_ieq cmd;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.request.hdr.cmd = ISM_SIGNAL_IEQ;
- cmd.request.hdr.len = sizeof(cmd.request);
-
- cmd.request.rgid = rgid;
- cmd.request.trigger_irq = trigger_irq;
- cmd.request.event_code = event_code;
- cmd.request.info = info;
-
- return ism_cmd(ism, &cmd);
-}
-
-static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid,
- u32 trigger_irq, u32 event_code, u64 info)
-{
- return ism_signal_ieq(smcd->priv, rgid->gid,
- trigger_irq, event_code, info);
-}
-
-static const struct smcd_ops ism_smcd_ops = {
- .signal_event = smcd_signal_ieq,
-};
-
-const struct smcd_ops *ism_get_smcd_ops(void)
-{
- return &ism_smcd_ops;
-}
-EXPORT_SYMBOL_GPL(ism_get_smcd_ops);
-#endif
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index be009c614205..c75607f8a5cf 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -67,6 +67,41 @@ struct dibs_dmb {
dma_addr_t dma_addr;
};
+/* DIBS events
+ * -----------
+ * Dibs devices can optionally notify dibs clients about events that happened
+ * in the fabric or at the remote device or remote dmb.
+ */
+enum dibs_event_type {
+ /* Buffer event, e.g. a remote dmb was unregistered */
+ DIBS_BUF_EVENT,
+ /* Device event, e.g. a remote dibs device was disabled */
+ DIBS_DEV_EVENT,
+ /* Software event, a dibs client can send an event signal to a
+ * remote dibs device.
+ */
+ DIBS_SW_EVENT,
+ DIBS_OTHER_TYPE };
+
+enum dibs_event_subtype {
+ DIBS_BUF_UNREGISTERED,
+ DIBS_DEV_DISABLED,
+ DIBS_DEV_ERR_STATE,
+ DIBS_OTHER_SUBTYPE
+};
+
+struct dibs_event {
+ u32 type;
+ u32 subtype;
+ /* uuid_null if invalid */
+ uuid_t gid;
+ /* zero if invalid */
+ u64 buffer_tok;
+ u64 time;
+ /* additional data or zero */
+ u64 data;
+};
+
struct dibs_dev;
/* DIBS client
@@ -117,6 +152,15 @@ struct dibs_client_ops {
*/
void (*handle_irq)(struct dibs_dev *dev, unsigned int idx,
u16 dmbemask);
+ /**
+ * handle_event() - Handle control information sent by device
+ * @dev: device reporting the event
+ * @event: ism event structure
+ *
+ * * Context: Called in IRQ context by dibs device driver
+ */
+ void (*handle_event)(struct dibs_dev *dev,
+ const struct dibs_event *event);
};
struct dibs_client {
@@ -285,6 +329,24 @@ struct dibs_dev_ops {
* Return: zero on success
*/
int (*del_vlan_id)(struct dibs_dev *dev, u64 vlan_id);
+ /**
+ * signal_event() - trigger an event at a remote dibs device (optional)
+ * @dev: local dibs device
+ * @rgid: gid of remote dibs device
+ * trigger_irq: zero: notification may be coalesced with other events
+ * non-zero: notify immediately
+ * @subtype: 4 byte event code, meaning is defined by dibs client
+ * @data: 8 bytes of additional information,
+ * meaning is defined by dibs client
+ *
+ * dibs devices can offer support for sending a control event of type
+ * EVENT_SWR to a remote dibs device.
+ * NOTE: handle_event() will be called for all registered dibs clients
+ * at the remote device.
+ * Return: zero on success
+ */
+ int (*signal_event)(struct dibs_dev *dev, const uuid_t *rgid,
+ u32 trigger_irq, u32 event_code, u64 info);
/**
* support_mmapped_rdmb() - can this device provide memory mapped
* remote dmbs? (optional)
diff --git a/include/net/smc.h b/include/net/smc.h
index 8e3debcf7db5..08bee529ed8d 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -16,7 +16,6 @@
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/dibs.h>
-#include "linux/ism.h"
struct sock;
@@ -28,28 +27,14 @@ struct smc_hashinfo {
};
/* SMCD/ISM device driver interface */
-#define ISM_EVENT_DMB 0
-#define ISM_EVENT_GID 1
-#define ISM_EVENT_SWR 2
-
#define ISM_RESERVED_VLANID 0x1FFF
-struct smcd_dev;
-
struct smcd_gid {
u64 gid;
u64 gid_ext;
};
-struct smcd_ops {
- /* optional operations */
- int (*signal_event)(struct smcd_dev *dev, struct smcd_gid *rgid,
- u32 trigger_irq, u32 event_code, u64 info);
-};
-
struct smcd_dev {
- const struct smcd_ops *ops;
- void *priv;
struct dibs_dev *dibs;
struct list_head list;
spinlock_t lock;
diff --git a/net/smc/Kconfig b/net/smc/Kconfig
index 9535d88c2acb..99ecd59d1f4b 100644
--- a/net/smc/Kconfig
+++ b/net/smc/Kconfig
@@ -2,7 +2,6 @@
config SMC
tristate "SMC socket protocol family"
depends on INET && INFINIBAND && DIBS
- depends on m || ISM != m
help
SMC-R provides a "sockets over RDMA" solution making use of
RDMA over Converged Ethernet (RoCE) technology to upgrade
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c
index 01e49371d23d..7b228ca2f96a 100644
--- a/net/smc/smc_ism.c
+++ b/net/smc/smc_ism.c
@@ -17,7 +17,6 @@
#include "smc_ism.h"
#include "smc_pnet.h"
#include "smc_netlink.h"
-#include "linux/ism.h"
#include "linux/dibs.h"
struct smcd_dev_list smcd_dev_list = {
@@ -30,20 +29,15 @@ static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN];
static void smcd_register_dev(struct dibs_dev *dibs);
static void smcd_unregister_dev(struct dibs_dev *dibs);
-#if IS_ENABLED(CONFIG_ISM)
-static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event);
-
-static struct ism_client smc_ism_client = {
- .name = "SMC-D",
- .handle_event = smcd_handle_event,
-};
-#endif
+static void smcd_handle_event(struct dibs_dev *dibs,
+ const struct dibs_event *event);
static void smcd_handle_irq(struct dibs_dev *dibs, unsigned int dmbno,
u16 dmbemask);
static struct dibs_client_ops smc_client_ops = {
.add_dev = smcd_register_dev,
.del_dev = smcd_unregister_dev,
+ .handle_event = smcd_handle_event,
.handle_irq = smcd_handle_irq,
};
@@ -399,11 +393,10 @@ int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-#if IS_ENABLED(CONFIG_ISM)
struct smc_ism_event_work {
struct work_struct work;
struct smcd_dev *smcd;
- struct ism_event event;
+ struct dibs_event event;
};
#define ISM_EVENT_REQUEST 0x0001
@@ -423,25 +416,27 @@ union smcd_sw_event_info {
static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
{
- struct smcd_gid peer_gid = { .gid = wrk->event.tok,
- .gid_ext = 0 };
+ struct dibs_dev *dibs = wrk->smcd->dibs;
union smcd_sw_event_info ev_info;
+ struct smcd_gid peer_gid;
+ uuid_t ism_rgid;
- ev_info.info = wrk->event.info;
- switch (wrk->event.code) {
+ copy_to_smcdgid(&peer_gid, &wrk->event.gid);
+ ev_info.info = wrk->event.data;
+ switch (wrk->event.subtype) {
case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */
smc_smcd_terminate(wrk->smcd, &peer_gid, ev_info.vlan_id);
break;
case ISM_EVENT_CODE_TESTLINK: /* Activity timer */
if (ev_info.code == ISM_EVENT_REQUEST &&
- wrk->smcd->ops->signal_event) {
+ dibs->ops->signal_event) {
ev_info.code = ISM_EVENT_RESPONSE;
- wrk->smcd->ops->signal_event(wrk->smcd,
- &peer_gid,
- ISM_EVENT_REQUEST_IR,
- ISM_EVENT_CODE_TESTLINK,
- ev_info.info);
- }
+ copy_to_dibsgid(&ism_rgid, &peer_gid);
+ dibs->ops->signal_event(dibs, &ism_rgid,
+ ISM_EVENT_REQUEST_IR,
+ ISM_EVENT_CODE_TESTLINK,
+ ev_info.info);
+ }
break;
}
}
@@ -451,26 +446,24 @@ static void smc_ism_event_work(struct work_struct *work)
{
struct smc_ism_event_work *wrk =
container_of(work, struct smc_ism_event_work, work);
- struct smcd_gid smcd_gid = { .gid = wrk->event.tok,
- .gid_ext = 0 };
+ struct smcd_gid smcd_gid;
+
+ copy_to_smcdgid(&smcd_gid, &wrk->event.gid);
switch (wrk->event.type) {
- case ISM_EVENT_GID: /* GID event, token is peer GID */
+ case DIBS_DEV_EVENT: /* GID event, token is peer GID */
smc_smcd_terminate(wrk->smcd, &smcd_gid, VLAN_VID_MASK);
break;
- case ISM_EVENT_DMB:
+ case DIBS_BUF_EVENT:
break;
- case ISM_EVENT_SWR: /* Software defined event */
+ case DIBS_SW_EVENT: /* Software defined event */
smcd_handle_sw_event(wrk);
break;
}
kfree(wrk);
}
-#endif
-static struct smcd_dev *smcd_alloc_dev(const char *name,
- const struct smcd_ops *ops,
- int max_dmbs)
+static struct smcd_dev *smcd_alloc_dev(const char *name, int max_dmbs)
{
struct smcd_dev *smcd;
@@ -487,8 +480,6 @@ static struct smcd_dev *smcd_alloc_dev(const char *name,
if (!smcd->event_wq)
goto free_conn;
- smcd->ops = ops;
-
spin_lock_init(&smcd->lock);
spin_lock_init(&smcd->lgr_lock);
INIT_LIST_HEAD(&smcd->vlan);
@@ -506,36 +497,17 @@ static struct smcd_dev *smcd_alloc_dev(const char *name,
static void smcd_register_dev(struct dibs_dev *dibs)
{
struct smcd_dev *smcd, *fentry;
- const struct smcd_ops *ops;
- struct ism_dev *ism;
int max_dmbs;
max_dmbs = dibs->ops->max_dmbs();
- if (smc_ism_is_loopback(dibs)) {
- ops = NULL;
- } else {
- ism = dibs->drv_priv;
-#if IS_ENABLED(CONFIG_ISM)
- ops = ism_get_smcd_ops();
-#endif
- }
- smcd = smcd_alloc_dev(dev_name(&dibs->dev), ops, max_dmbs);
+ smcd = smcd_alloc_dev(dev_name(&dibs->dev), max_dmbs);
if (!smcd)
return;
smcd->dibs = dibs;
dibs_set_priv(dibs, &smc_dibs_client, smcd);
- if (smc_ism_is_loopback(dibs)) {
- smcd->priv = NULL;
- } else {
- smcd->priv = ism;
-#if IS_ENABLED(CONFIG_ISM)
- ism_set_priv(ism, &smc_ism_client, smcd);
-#endif
- }
-
if (smc_pnetid_by_dev_port(dibs->dev.parent, 0, smcd->pnetid))
smc_pnetid_by_table_smcd(smcd);
@@ -590,7 +562,6 @@ static void smcd_unregister_dev(struct dibs_dev *dibs)
kfree(smcd);
}
-#if IS_ENABLED(CONFIG_ISM)
/* SMCD Device event handler. Called from ISM device interrupt handler.
* Parameters are ism device pointer,
* - event->type (0 --> DMB, 1 --> GID),
@@ -602,9 +573,10 @@ static void smcd_unregister_dev(struct dibs_dev *dibs)
* Context:
* - Function called in IRQ context from ISM device driver event handler.
*/
-static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
+static void smcd_handle_event(struct dibs_dev *dibs,
+ const struct dibs_event *event)
{
- struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
+ struct smcd_dev *smcd = dibs_get_priv(dibs, &smc_dibs_client);
struct smc_ism_event_work *wrk;
if (smcd->going_away)
@@ -618,7 +590,6 @@ static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
wrk->event = *event;
queue_work(smcd->event_wq, &wrk->work);
}
-#endif
/* SMCD Device interrupt handler. Called from ISM device interrupt handler.
* Parameters are the ism device pointer, DMB number, and the DMBE bitmask.
@@ -644,22 +615,22 @@ static void smcd_handle_irq(struct dibs_dev *dibs, unsigned int dmbno,
int smc_ism_signal_shutdown(struct smc_link_group *lgr)
{
int rc = 0;
-#if IS_ENABLED(CONFIG_ISM)
union smcd_sw_event_info ev_info;
+ uuid_t ism_rgid;
if (lgr->peer_shutdown)
return 0;
- if (!lgr->smcd->ops->signal_event)
+ if (!lgr->smcd->dibs->ops->signal_event)
return 0;
memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
ev_info.vlan_id = lgr->vlan_id;
ev_info.code = ISM_EVENT_REQUEST;
- rc = lgr->smcd->ops->signal_event(lgr->smcd, &lgr->peer_gid,
+ copy_to_dibsgid(&ism_rgid, &lgr->peer_gid);
+ rc = lgr->smcd->dibs->ops->signal_event(lgr->smcd->dibs, &ism_rgid,
ISM_EVENT_REQUEST_IR,
ISM_EVENT_CODE_SHUTDOWN,
ev_info.info);
-#endif
return rc;
}
@@ -670,9 +641,6 @@ int smc_ism_init(void)
smc_ism_v2_capable = false;
smc_ism_create_system_eid();
-#if IS_ENABLED(CONFIG_ISM)
- rc = ism_register_client(&smc_ism_client);
-#endif
rc = dibs_register_client(&smc_dibs_client);
return rc;
}
@@ -680,7 +648,4 @@ int smc_ism_init(void)
void smc_ism_exit(void)
{
dibs_unregister_client(&smc_dibs_client);
-#if IS_ENABLED(CONFIG_ISM)
- ism_unregister_client(&smc_ism_client);
-#endif
}
--
2.48.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
` (13 preceding siblings ...)
2025-09-18 11:05 ` [PATCH net-next v3 14/14] dibs: Move event handling to dibs layer Alexandra Winter
@ 2025-09-23 9:20 ` patchwork-bot+netdevbpf
14 siblings, 0 replies; 21+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-09-23 9:20 UTC (permalink / raw)
To: Alexandra Winter
Cc: alibuda, dust.li, sidraya, wenjia, davem, kuba, pabeni, edumazet,
andrew+netdev, julianr, aswin, pasic, mjambigi, tonylu, guwen,
linux-rdma, netdev, linux-s390, hca, gor, agordeev, borntraeger,
svens, horms, ebiggers, ardb, herbert, freude, kshk,
dan.j.williams, dave.jiang, Jonathan.Cameron, sln, geert, jgg
Hello:
This series was applied to netdev/net-next.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Thu, 18 Sep 2025 13:04:46 +0200 you wrote:
> This series introduces a generic abstraction of existing components like:
> - the s390 specific ISM device (Internal Shared Memory),
> - the SMC-D loopback mechanism (Shared Memory Communication - Direct)
> - the client interface of the SMC-D module to the transport devices
> This generic shim layer can be extended with more devices, more clients and
> more features in the future.
>
> [...]
Here is the summary with links:
- [net-next,v3,01/14] net/smc: Remove error handling of unregister_dmb()
https://git.kernel.org/netdev/net-next/c/884eee8e43f3
- [net-next,v3,02/14] net/smc: Decouple sf and attached send_buf in smc_loopback
https://git.kernel.org/netdev/net-next/c/a4997e17d137
- [net-next,v3,03/14] dibs: Create drivers/dibs
https://git.kernel.org/netdev/net-next/c/35758b0032c0
- [net-next,v3,04/14] dibs: Register smc as dibs_client
https://git.kernel.org/netdev/net-next/c/d324a2ca3f8e
- [net-next,v3,05/14] dibs: Register ism as dibs device
https://git.kernel.org/netdev/net-next/c/269726968f95
- [net-next,v3,06/14] dibs: Define dibs loopback
https://git.kernel.org/netdev/net-next/c/cb990a45d7f6
- [net-next,v3,07/14] dibs: Define dibs_client_ops and dibs_dev_ops
https://git.kernel.org/netdev/net-next/c/69baaac9361e
- [net-next,v3,08/14] dibs: Move struct device to dibs_dev
https://git.kernel.org/netdev/net-next/c/845c334a0186
- [net-next,v3,09/14] dibs: Create class dibs
https://git.kernel.org/netdev/net-next/c/804737349813
- [net-next,v3,10/14] dibs: Local gid for dibs devices
https://git.kernel.org/netdev/net-next/c/05e68d8dedf3
- [net-next,v3,11/14] dibs: Move vlan support to dibs_dev_ops
https://git.kernel.org/netdev/net-next/c/92a0f7bb081d
- [net-next,v3,12/14] dibs: Move query_remote_gid() to dibs_dev_ops
https://git.kernel.org/netdev/net-next/c/719c3b67bb7e
- [net-next,v3,13/14] dibs: Move data path to dibs layer
https://git.kernel.org/netdev/net-next/c/cc21191b584c
- [net-next,v3,14/14] dibs: Move event handling to dibs layer
https://git.kernel.org/netdev/net-next/c/a612dbe8d04d
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge
2025-09-18 11:04 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer Alexandra Winter
@ 2025-09-24 9:07 ` Matthieu Baerts
2025-09-24 17:34 ` Alexandra Winter
` (2 more replies)
0 siblings, 3 replies; 21+ messages in thread
From: Matthieu Baerts @ 2025-09-24 9:07 UTC (permalink / raw)
To: Alexandra Winter, Sidraya Jayagond
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe, D. Wythe, Dust Li,
Wenjia Zhang, David Miller, Jakub Kicinski, Paolo Abeni,
Eric Dumazet, Andrew Lunn, Stephen Rothwell
[-- Attachment #1: Type: text/plain, Size: 2586 bytes --]
Hi Alexandra, Sidraya,
On 18/09/2025 12:04, Alexandra Winter wrote:
> Use struct dibs_dmb instead of struct smc_dmb and move the corresponding
> client tables to dibs_dev. Leave driver specific implementation details
> like sba in the device drivers.
>
> Register and unregister dmbs via dibs_dev_ops. A dmb is dedicated to a
> single client, but a dibs device can have dmbs for more than one client.
>
> Trigger dibs clients via dibs_client_ops->handle_irq(), when data is
> received into a dmb. For dibs_loopback replace scheduling an smcd receive
> tasklet with calling dibs_client_ops->handle_irq().
>
> For loopback devices attach_dmb(), detach_dmb() and move_data() need to
> access the dmb tables, so move those to dibs_dev_ops in this patch as well.
>
> Remove remaining definitions of smc_loopback as they are no longer
> required, now that everything is in dibs_loopback.
>
> Note that struct ism_client and struct ism_dev are still required in smc
> until a follow-on patch moves event handling to dibs. (Loopback does not
> use events).
FYI, we got a conflict when merging 'net' in 'net-next' in the MPTCP
tree due to this patch applied in 'net':
a35c04de2565 ("net/smc: fix warning in smc_rx_splice() when calling
get_page()")
and this one from 'net-next':
cc21191b584c ("dibs: Move data path to dibs layer")
----- Generic Message -----
The best is to avoid conflicts between 'net' and 'net-next' trees but if
they cannot be avoided when preparing patches, a note about how to fix
them is much appreciated.
The conflict has been resolved on our side[1] and the resolution we
suggest is attached to this email. Please report any issues linked to
this conflict resolution as it might be used by others. If you worked on
the mentioned patches, don't hesitate to ACK this conflict resolution.
---------------------------
Regarding this conflict, I hope the resolution is correct. The patch
from 'net' was modifying 'net/smc/smc_loopback.c' in
smc_lo_register_dmb() and __smc_lo_unregister_dmb(). I applied the same
modifications in 'drivers/dibs/dibs_loopback.c', in
dibs_lo_register_dmb() and __dibs_lo_unregister_dmb(). In net-next,
kfree(cpu_addr) was used instead of kvfree(cpu_addr), but this was done
on purpose. Also, I had to include mm.h to be able to build this driver.
I also attached a simple diff of the modifications I did.
Does that look OK to both of you?
Note: no rerere cache is available for this kind of conflicts.
Cheers,
Matt
[1] https://github.com/multipath-tcp/mptcp_net-next/commit/af2dbdbb0a91
--
Sponsored by the NGI0 Core fund.
[-- Attachment #2: af2dbdbb0a91d92af6248888b566b8b154ebce6d.patch --]
[-- Type: text/x-patch, Size: 9619 bytes --]
diff --cc drivers/dibs/dibs_loopback.c
index 000000000000,b3fd0f8100d4..aa029e29c6b2
mode 000000,100644..100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@@ -1,0 -1,356 +1,361 @@@
+ // SPDX-License-Identifier: GPL-2.0
+ /*
+ * Functions for dibs loopback/loopback-ism device.
+ *
+ * Copyright (c) 2024, Alibaba Inc.
+ *
+ * Author: Wen Gu <guwen@linux.alibaba.com>
+ * Tony Lu <tonylu@linux.alibaba.com>
+ *
+ */
+
+ #include <linux/bitops.h>
+ #include <linux/device.h>
+ #include <linux/dibs.h>
++#include <linux/mm.h>
+ #include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <linux/types.h>
+
+ #include "dibs_loopback.h"
+
+ #define DIBS_LO_SUPPORT_NOCOPY 0x1
+ #define DIBS_DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+ static const char dibs_lo_dev_name[] = "lo";
+ /* global loopback device */
+ static struct dibs_lo_dev *lo_dev;
+
+ static u16 dibs_lo_get_fabric_id(struct dibs_dev *dibs)
+ {
+ return DIBS_LOOPBACK_FABRIC;
+ }
+
+ static int dibs_lo_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
+ u32 vid_valid, u32 vid)
+ {
+ /* rgid should be the same as lgid */
+ if (!uuid_equal(rgid, &dibs->gid))
+ return -ENETUNREACH;
+ return 0;
+ }
+
+ static int dibs_lo_max_dmbs(void)
+ {
+ return DIBS_LO_MAX_DMBS;
+ }
+
+ static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
+ struct dibs_client *client)
+ {
+ struct dibs_lo_dmb_node *dmb_node, *tmp_node;
+ struct dibs_lo_dev *ldev;
++ struct folio *folio;
+ unsigned long flags;
+ int sba_idx, rc;
+
+ ldev = dibs->drv_priv;
+ sba_idx = dmb->idx;
+ /* check space for new dmb */
+ for_each_clear_bit(sba_idx, ldev->sba_idx_mask, DIBS_LO_MAX_DMBS) {
+ if (!test_and_set_bit(sba_idx, ldev->sba_idx_mask))
+ break;
+ }
+ if (sba_idx == DIBS_LO_MAX_DMBS)
+ return -ENOSPC;
+
+ dmb_node = kzalloc(sizeof(*dmb_node), GFP_KERNEL);
+ if (!dmb_node) {
+ rc = -ENOMEM;
+ goto err_bit;
+ }
+
+ dmb_node->sba_idx = sba_idx;
+ dmb_node->len = dmb->dmb_len;
- dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL |
- __GFP_NOWARN | __GFP_NORETRY |
- __GFP_NOMEMALLOC);
- if (!dmb_node->cpu_addr) {
++
++ /* not critical; fail under memory pressure and fallback to TCP */
++ folio = folio_alloc(GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC |
++ __GFP_NORETRY | __GFP_ZERO,
++ get_order(dmb_node->len));
++ if (!folio) {
+ rc = -ENOMEM;
+ goto err_node;
+ }
++ dmb_node->cpu_addr = folio_address(folio);
+ dmb_node->dma_addr = DIBS_DMA_ADDR_INVALID;
+ refcount_set(&dmb_node->refcnt, 1);
+
+ again:
+ /* add new dmb into hash table */
+ get_random_bytes(&dmb_node->token, sizeof(dmb_node->token));
+ write_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_node->token) {
+ if (tmp_node->token == dmb_node->token) {
+ write_unlock_bh(&ldev->dmb_ht_lock);
+ goto again;
+ }
+ }
+ hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+ atomic_inc(&ldev->dmb_cnt);
+
+ dmb->idx = dmb_node->sba_idx;
+ dmb->dmb_tok = dmb_node->token;
+ dmb->cpu_addr = dmb_node->cpu_addr;
+ dmb->dma_addr = dmb_node->dma_addr;
+ dmb->dmb_len = dmb_node->len;
+
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[sba_idx] = client->id;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+
+ return 0;
+
+ err_node:
+ kfree(dmb_node);
+ err_bit:
+ clear_bit(sba_idx, ldev->sba_idx_mask);
+ return rc;
+ }
+
+ static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
+ struct dibs_lo_dmb_node *dmb_node)
+ {
+ /* remove dmb from hash table */
+ write_lock_bh(&ldev->dmb_ht_lock);
+ hash_del(&dmb_node->list);
+ write_unlock_bh(&ldev->dmb_ht_lock);
+
+ clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
- kfree(dmb_node->cpu_addr);
++ folio_put(virt_to_folio(dmb_node->cpu_addr));
+ kfree(dmb_node);
+
+ if (atomic_dec_and_test(&ldev->dmb_cnt))
+ wake_up(&ldev->ldev_release);
+ }
+
+ static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
+ {
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+ unsigned long flags;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb from hash table */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
+ if (tmp_node->token == dmb->dmb_tok) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ if (!dmb_node)
+ return -EINVAL;
+
+ if (refcount_dec_and_test(&dmb_node->refcnt)) {
+ spin_lock_irqsave(&dibs->lock, flags);
+ dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
+ spin_unlock_irqrestore(&dibs->lock, flags);
+
+ __dibs_lo_unregister_dmb(ldev, dmb_node);
+ }
+ return 0;
+ }
+
+ static int dibs_lo_support_dmb_nocopy(struct dibs_dev *dibs)
+ {
+ return DIBS_LO_SUPPORT_NOCOPY;
+ }
+
+ static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
+ {
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb_node according to dmb->dmb_tok */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
+ if (tmp_node->token == dmb->dmb_tok) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!dmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (!refcount_inc_not_zero(&dmb_node->refcnt))
+ /* the dmb is being unregistered, but has
+ * not been removed from the hash table.
+ */
+ return -EINVAL;
+
+ /* provide dmb information */
+ dmb->idx = dmb_node->sba_idx;
+ dmb->dmb_tok = dmb_node->token;
+ dmb->cpu_addr = dmb_node->cpu_addr;
+ dmb->dma_addr = dmb_node->dma_addr;
+ dmb->dmb_len = dmb_node->len;
+ return 0;
+ }
+
+ static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
+ {
+ struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+
+ ldev = dibs->drv_priv;
+
+ /* find dmb_node according to dmb->dmb_tok */
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
+ if (tmp_node->token == token) {
+ dmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!dmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (refcount_dec_and_test(&dmb_node->refcnt))
+ __dibs_lo_unregister_dmb(ldev, dmb_node);
+ return 0;
+ }
+
+ static int dibs_lo_move_data(struct dibs_dev *dibs, u64 dmb_tok,
+ unsigned int idx, bool sf, unsigned int offset,
+ void *data, unsigned int size)
+ {
+ struct dibs_lo_dmb_node *rmb_node = NULL, *tmp_node;
+ struct dibs_lo_dev *ldev;
+ u16 s_mask;
+ u8 client_id;
+ u32 sba_idx;
+
+ ldev = dibs->drv_priv;
+
+ read_lock_bh(&ldev->dmb_ht_lock);
+ hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
+ if (tmp_node->token == dmb_tok) {
+ rmb_node = tmp_node;
+ break;
+ }
+ }
+ if (!rmb_node) {
+ read_unlock_bh(&ldev->dmb_ht_lock);
+ return -EINVAL;
+ }
+ memcpy((char *)rmb_node->cpu_addr + offset, data, size);
+ sba_idx = rmb_node->sba_idx;
+ read_unlock_bh(&ldev->dmb_ht_lock);
+
+ if (!sf)
+ return 0;
+
+ spin_lock(&dibs->lock);
+ client_id = dibs->dmb_clientid_arr[sba_idx];
+ s_mask = ror16(0x1000, idx);
+ if (likely(client_id != NO_DIBS_CLIENT && dibs->subs[client_id]))
+ dibs->subs[client_id]->ops->handle_irq(dibs, sba_idx, s_mask);
+ spin_unlock(&dibs->lock);
+
+ return 0;
+ }
+
+ static const struct dibs_dev_ops dibs_lo_ops = {
+ .get_fabric_id = dibs_lo_get_fabric_id,
+ .query_remote_gid = dibs_lo_query_rgid,
+ .max_dmbs = dibs_lo_max_dmbs,
+ .register_dmb = dibs_lo_register_dmb,
+ .unregister_dmb = dibs_lo_unregister_dmb,
+ .move_data = dibs_lo_move_data,
+ .support_mmapped_rdmb = dibs_lo_support_dmb_nocopy,
+ .attach_dmb = dibs_lo_attach_dmb,
+ .detach_dmb = dibs_lo_detach_dmb,
+ };
+
+ static void dibs_lo_dev_init(struct dibs_lo_dev *ldev)
+ {
+ rwlock_init(&ldev->dmb_ht_lock);
+ hash_init(ldev->dmb_ht);
+ atomic_set(&ldev->dmb_cnt, 0);
+ init_waitqueue_head(&ldev->ldev_release);
+ }
+
+ static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
+ {
+ if (atomic_read(&ldev->dmb_cnt))
+ wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
+ }
+
+ static int dibs_lo_dev_probe(void)
+ {
+ struct dibs_lo_dev *ldev;
+ struct dibs_dev *dibs;
+ int ret;
+
+ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ if (!ldev)
+ return -ENOMEM;
+
+ dibs = dibs_dev_alloc();
+ if (!dibs) {
+ kfree(ldev);
+ return -ENOMEM;
+ }
+
+ ldev->dibs = dibs;
+ dibs->drv_priv = ldev;
+ dibs_lo_dev_init(ldev);
+ uuid_gen(&dibs->gid);
+ dibs->ops = &dibs_lo_ops;
+
+ dibs->dev.parent = NULL;
+ dev_set_name(&dibs->dev, "%s", dibs_lo_dev_name);
+
+ ret = dibs_dev_add(dibs);
+ if (ret)
+ goto err_reg;
+ lo_dev = ldev;
+ return 0;
+
+ err_reg:
+ kfree(dibs->dmb_clientid_arr);
+ /* pairs with dibs_dev_alloc() */
+ put_device(&dibs->dev);
+ kfree(ldev);
+
+ return ret;
+ }
+
+ static void dibs_lo_dev_remove(void)
+ {
+ if (!lo_dev)
+ return;
+
+ dibs_dev_del(lo_dev->dibs);
+ dibs_lo_dev_exit(lo_dev);
+ /* pairs with dibs_dev_alloc() */
+ put_device(&lo_dev->dibs->dev);
+ kfree(lo_dev);
+ lo_dev = NULL;
+ }
+
+ int dibs_loopback_init(void)
+ {
+ return dibs_lo_dev_probe();
+ }
+
+ void dibs_loopback_exit(void)
+ {
+ dibs_lo_dev_remove();
+ }
[-- Attachment #3: conflict_dibs.patch --]
[-- Type: text/x-patch, Size: 1658 bytes --]
diff --git a/drivers/dibs/dibs_loopback.c b/drivers/dibs/dibs_loopback.c
index b3fd0f8100d4..aa029e29c6b2 100644
--- a/drivers/dibs/dibs_loopback.c
+++ b/drivers/dibs/dibs_loopback.c
@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/dibs.h>
+#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -49,6 +50,7 @@ static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
{
struct dibs_lo_dmb_node *dmb_node, *tmp_node;
struct dibs_lo_dev *ldev;
+ struct folio *folio;
unsigned long flags;
int sba_idx, rc;
@@ -70,13 +72,16 @@ static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
dmb_node->sba_idx = sba_idx;
dmb_node->len = dmb->dmb_len;
- dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL |
- __GFP_NOWARN | __GFP_NORETRY |
- __GFP_NOMEMALLOC);
- if (!dmb_node->cpu_addr) {
+
+ /* not critical; fail under memory pressure and fallback to TCP */
+ folio = folio_alloc(GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC |
+ __GFP_NORETRY | __GFP_ZERO,
+ get_order(dmb_node->len));
+ if (!folio) {
rc = -ENOMEM;
goto err_node;
}
+ dmb_node->cpu_addr = folio_address(folio);
dmb_node->dma_addr = DIBS_DMA_ADDR_INVALID;
refcount_set(&dmb_node->refcnt, 1);
@@ -122,7 +127,7 @@ static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
write_unlock_bh(&ldev->dmb_ht_lock);
clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
- kfree(dmb_node->cpu_addr);
+ folio_put(virt_to_folio(dmb_node->cpu_addr));
kfree(dmb_node);
if (atomic_dec_and_test(&ldev->dmb_cnt))
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge
2025-09-24 9:07 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge Matthieu Baerts
@ 2025-09-24 17:34 ` Alexandra Winter
2025-09-25 6:00 ` Sidraya Jayagond
2025-09-25 17:57 ` Jakub Kicinski
2 siblings, 0 replies; 21+ messages in thread
From: Alexandra Winter @ 2025-09-24 17:34 UTC (permalink / raw)
To: Matthieu Baerts, Sidraya Jayagond
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe, D. Wythe, Dust Li,
Wenjia Zhang, David Miller, Jakub Kicinski, Paolo Abeni,
Eric Dumazet, Andrew Lunn, Stephen Rothwell
On 24.09.25 11:07, Matthieu Baerts wrote:
> Hi Alexandra, Sidraya,
>
> On 18/09/2025 12:04, Alexandra Winter wrote:
>> Use struct dibs_dmb instead of struct smc_dmb and move the corresponding
>> client tables to dibs_dev. Leave driver specific implementation details
>> like sba in the device drivers.
>>
>> Register and unregister dmbs via dibs_dev_ops. A dmb is dedicated to a
>> single client, but a dibs device can have dmbs for more than one client.
>>
>> Trigger dibs clients via dibs_client_ops->handle_irq(), when data is
>> received into a dmb. For dibs_loopback replace scheduling an smcd receive
>> tasklet with calling dibs_client_ops->handle_irq().
>>
>> For loopback devices attach_dmb(), detach_dmb() and move_data() need to
>> access the dmb tables, so move those to dibs_dev_ops in this patch as well.
>>
>> Remove remaining definitions of smc_loopback as they are no longer
>> required, now that everything is in dibs_loopback.
>>
>> Note that struct ism_client and struct ism_dev are still required in smc
>> until a follow-on patch moves event handling to dibs. (Loopback does not
>> use events).
>
> FYI, we got a conflict when merging 'net' in 'net-next' in the MPTCP
> tree due to this patch applied in 'net':
>
> a35c04de2565 ("net/smc: fix warning in smc_rx_splice() when calling
> get_page()")
>
> and this one from 'net-next':
>
> cc21191b584c ("dibs: Move data path to dibs layer")
>
> ----- Generic Message -----
> The best is to avoid conflicts between 'net' and 'net-next' trees but if
> they cannot be avoided when preparing patches, a note about how to fix
> them is much appreciated.
> The conflict has been resolved on our side[1] and the resolution we
> suggest is attached to this email. Please report any issues linked to
> this conflict resolution as it might be used by others. If you worked on
> the mentioned patches, don't hesitate to ACK this conflict resolution.
> ---------------------------
>
> Regarding this conflict, I hope the resolution is correct. The patch
> from 'net' was modifying 'net/smc/smc_loopback.c' in
> smc_lo_register_dmb() and __smc_lo_unregister_dmb(). I applied the same
> modifications in 'drivers/dibs/dibs_loopback.c', in
> dibs_lo_register_dmb() and __dibs_lo_unregister_dmb(). In net-next,
> kfree(cpu_addr) was used instead of kvfree(cpu_addr), but this was done
> on purpose. Also, I had to include mm.h to be able to build this driver.
> I also attached a simple diff of the modifications I did.
>
> Does that look OK to both of you?
>
> Note: no rerere cache is available for this kind of conflicts.
>
> Cheers,
> Matt
>
> [1] https://github.com/multipath-tcp/mptcp_net-next/commit/af2dbdbb0a91
Acked-by: Alexandra Winter <wintera@linux.ibm.com>
LGTM, thank you very much Matthieu.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge
2025-09-24 9:07 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge Matthieu Baerts
2025-09-24 17:34 ` Alexandra Winter
@ 2025-09-25 6:00 ` Sidraya Jayagond
2025-09-25 17:57 ` Jakub Kicinski
2 siblings, 0 replies; 21+ messages in thread
From: Sidraya Jayagond @ 2025-09-25 6:00 UTC (permalink / raw)
To: Matthieu Baerts, Alexandra Winter
Cc: Julian Ruess, Aswin Karuvally, Halil Pasic, Mahanta Jambigi,
Tony Lu, Wen Gu, linux-rdma, netdev, linux-s390, Heiko Carstens,
Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
Sven Schnelle, Simon Horman, Eric Biggers, Ard Biesheuvel,
Herbert Xu, Harald Freudenberger, Konstantin Shkolnyy,
Dan Williams, Dave Jiang, Jonathan Cameron, Shannon Nelson,
Geert Uytterhoeven, Jason Gunthorpe, D. Wythe, Dust Li,
Wenjia Zhang, David Miller, Jakub Kicinski, Paolo Abeni,
Eric Dumazet, Andrew Lunn, Stephen Rothwell
On 24/09/25 2:37 pm, Matthieu Baerts wrote:
> Hi Alexandra, Sidraya,
>
> On 18/09/2025 12:04, Alexandra Winter wrote:
>> Use struct dibs_dmb instead of struct smc_dmb and move the corresponding
>> client tables to dibs_dev. Leave driver specific implementation details
>> like sba in the device drivers.
>>
>> Register and unregister dmbs via dibs_dev_ops. A dmb is dedicated to a
>> single client, but a dibs device can have dmbs for more than one client.
>>
>> Trigger dibs clients via dibs_client_ops->handle_irq(), when data is
>> received into a dmb. For dibs_loopback replace scheduling an smcd receive
>> tasklet with calling dibs_client_ops->handle_irq().
>>
>> For loopback devices attach_dmb(), detach_dmb() and move_data() need to
>> access the dmb tables, so move those to dibs_dev_ops in this patch as well.
>>
>> Remove remaining definitions of smc_loopback as they are no longer
>> required, now that everything is in dibs_loopback.
>>
>> Note that struct ism_client and struct ism_dev are still required in smc
>> until a follow-on patch moves event handling to dibs. (Loopback does not
>> use events).
>
> FYI, we got a conflict when merging 'net' in 'net-next' in the MPTCP
> tree due to this patch applied in 'net':
>
> a35c04de2565 ("net/smc: fix warning in smc_rx_splice() when calling
> get_page()")
>
> and this one from 'net-next':
>
> cc21191b584c ("dibs: Move data path to dibs layer")
>
> ----- Generic Message -----
> The best is to avoid conflicts between 'net' and 'net-next' trees but if
> they cannot be avoided when preparing patches, a note about how to fix
> them is much appreciated.
> The conflict has been resolved on our side[1] and the resolution we
> suggest is attached to this email. Please report any issues linked to
> this conflict resolution as it might be used by others. If you worked on
> the mentioned patches, don't hesitate to ACK this conflict resolution.
> ---------------------------
>
> Regarding this conflict, I hope the resolution is correct. The patch
> from 'net' was modifying 'net/smc/smc_loopback.c' in
> smc_lo_register_dmb() and __smc_lo_unregister_dmb(). I applied the same
> modifications in 'drivers/dibs/dibs_loopback.c', in
> dibs_lo_register_dmb() and __dibs_lo_unregister_dmb(). In net-next,
> kfree(cpu_addr) was used instead of kvfree(cpu_addr), but this was done
> on purpose. Also, I had to include mm.h to be able to build this driver.
> I also attached a simple diff of the modifications I did.
>
> Does that look OK to both of you?
>
> Note: no rerere cache is available for this kind of conflicts.
>
> Cheers,
> Matt
>
> [1] https://github.com/multipath-tcp/mptcp_net-next/commit/af2dbdbb0a91
Acked-by: Sidraya Jayagond <sidraya@linux.ibm.com>
LGTM, thank you Matthieu.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge
2025-09-24 9:07 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge Matthieu Baerts
2025-09-24 17:34 ` Alexandra Winter
2025-09-25 6:00 ` Sidraya Jayagond
@ 2025-09-25 17:57 ` Jakub Kicinski
2025-09-29 18:29 ` Matthieu Baerts
2 siblings, 1 reply; 21+ messages in thread
From: Jakub Kicinski @ 2025-09-25 17:57 UTC (permalink / raw)
To: Matthieu Baerts
Cc: Alexandra Winter, Sidraya Jayagond, Julian Ruess, Aswin Karuvally,
Halil Pasic, Mahanta Jambigi, Tony Lu, Wen Gu, linux-rdma, netdev,
linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Simon Horman, Eric Biggers,
Ard Biesheuvel, Herbert Xu, Harald Freudenberger,
Konstantin Shkolnyy, Dan Williams, Dave Jiang, Jonathan Cameron,
Shannon Nelson, Geert Uytterhoeven, Jason Gunthorpe, D. Wythe,
Dust Li, Wenjia Zhang, David Miller, Paolo Abeni, Eric Dumazet,
Andrew Lunn, Stephen Rothwell
On Wed, 24 Sep 2025 10:07:35 +0100 Matthieu Baerts wrote:
> Regarding this conflict, I hope the resolution is correct. The patch
> from 'net' was modifying 'net/smc/smc_loopback.c' in
> smc_lo_register_dmb() and __smc_lo_unregister_dmb(). I applied the same
> modifications in 'drivers/dibs/dibs_loopback.c', in
> dibs_lo_register_dmb() and __dibs_lo_unregister_dmb(). In net-next,
> kfree(cpu_addr) was used instead of kvfree(cpu_addr), but this was done
> on purpose. Also, I had to include mm.h to be able to build this driver.
> I also attached a simple diff of the modifications I did.
Thanks a lot for sharing the resolutions!
> Note: no rerere cache is available for this kind of conflicts.
BTW have you figured out how to resolve that automatically?
NIPA does trusts rerere but because it didn't work we were running
without net for the last few days (knowingly) :(
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge
2025-09-25 17:57 ` Jakub Kicinski
@ 2025-09-29 18:29 ` Matthieu Baerts
0 siblings, 0 replies; 21+ messages in thread
From: Matthieu Baerts @ 2025-09-29 18:29 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Alexandra Winter, Sidraya Jayagond, Julian Ruess, Aswin Karuvally,
Halil Pasic, Mahanta Jambigi, Tony Lu, Wen Gu, linux-rdma, netdev,
linux-s390, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
Christian Borntraeger, Sven Schnelle, Simon Horman, Eric Biggers,
Ard Biesheuvel, Herbert Xu, Harald Freudenberger,
Konstantin Shkolnyy, Dan Williams, Dave Jiang, Jonathan Cameron,
Shannon Nelson, Geert Uytterhoeven, Jason Gunthorpe, D. Wythe,
Dust Li, Wenjia Zhang, David Miller, Paolo Abeni, Eric Dumazet,
Andrew Lunn, Stephen Rothwell
Hi Jakub,
(Sorry for the delay, I was travelling)
On 25/09/2025 18:57, Jakub Kicinski wrote:
> On Wed, 24 Sep 2025 10:07:35 +0100 Matthieu Baerts wrote:
>> Regarding this conflict, I hope the resolution is correct. The patch
>> from 'net' was modifying 'net/smc/smc_loopback.c' in
>> smc_lo_register_dmb() and __smc_lo_unregister_dmb(). I applied the same
>> modifications in 'drivers/dibs/dibs_loopback.c', in
>> dibs_lo_register_dmb() and __dibs_lo_unregister_dmb(). In net-next,
>> kfree(cpu_addr) was used instead of kvfree(cpu_addr), but this was done
>> on purpose. Also, I had to include mm.h to be able to build this driver.
>> I also attached a simple diff of the modifications I did.
>
> Thanks a lot for sharing the resolutions!
You are very welcome!
>> Note: no rerere cache is available for this kind of conflicts.
>
> BTW have you figured out how to resolve that automatically?
> NIPA does trusts rerere but because it didn't work we were running
> without net for the last few days (knowingly) :(
When I was in charge of supporting MPTCP on top of a few old stable
kernels, and keeping new features in sync on all these kernels, I ended
up automating the resolution of such conflicts. In my case, I was
cherry-picking patches, and I could then simply take a fingerprint based
on the 'git diff' output without the index and lines numbers. With the
hash of the diff, I could either create or get the corresponding
'.patch' file can be automatically applied with the 'patch' command to
resolve the conflicts.
In your case, you are merging trees that are regularly changing, if I'm
not mistaken. In this case, the fingerprint should not be based on
everything pending during the merge, but I guess it should be possible
to get a fingerprint, e.g. a diff showing the conflicts.
Note that in the MPTCP tree, we use 'TopGit' [1], and our tree is
regularly synced with 'net' and 'net-next'. When there are conflicts, I
only have to fix them once, because TopGit merges multiple branches and
keep a continuous history. That's another solution, but it might not be
adapted to NIPA's needs.
[1] https://mackyle.github.io/topgit/
Cheers,
Matt
--
Sponsored by the NGI0 Core fund.
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-09-29 18:30 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 11:04 [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 01/14] net/smc: Remove error handling of unregister_dmb() Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 02/14] net/smc: Decouple sf and attached send_buf in smc_loopback Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 03/14] dibs: Create drivers/dibs Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 04/14] dibs: Register smc as dibs_client Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 05/14] dibs: Register ism as dibs device Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 06/14] dibs: Define dibs loopback Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 07/14] dibs: Define dibs_client_ops and dibs_dev_ops Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 08/14] dibs: Move struct device to dibs_dev Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 09/14] dibs: Create class dibs Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 10/14] dibs: Local gid for dibs devices Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 11/14] dibs: Move vlan support to dibs_dev_ops Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 12/14] dibs: Move query_remote_gid() " Alexandra Winter
2025-09-18 11:04 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer Alexandra Winter
2025-09-24 9:07 ` [PATCH net-next v3 13/14] dibs: Move data path to dibs layer: manual merge Matthieu Baerts
2025-09-24 17:34 ` Alexandra Winter
2025-09-25 6:00 ` Sidraya Jayagond
2025-09-25 17:57 ` Jakub Kicinski
2025-09-29 18:29 ` Matthieu Baerts
2025-09-18 11:05 ` [PATCH net-next v3 14/14] dibs: Move event handling to dibs layer Alexandra Winter
2025-09-23 9:20 ` [PATCH net-next v3 00/14] dibs - Direct Internal Buffer Sharing patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).