From: Julian Ruess <julianr@linux.ibm.com>
To: schnelle@linux.ibm.com, wintera@linux.ibm.com, ts@linux.ibm.com,
oberpar@linux.ibm.com, gbayer@linux.ibm.com
Cc: mjrosato@linux.ibm.com, alifm@linux.ibm.com, raspl@linux.ibm.com,
hca@linux.ibm.com, agordeev@linux.ibm.com, gor@linux.ibm.com,
julianr@linux.ibm.com,
linux390-list@tuxmaker.boeblingen.de.ibm.com,
linux-s390@vger.kernel.org
Subject: [PATCH 1/4] dibs: introduce ring-buffer send/receive API
Date: Thu, 08 Oct 2026 10:08:03 +0200 [thread overview]
Message-ID: <20261008-console_server-v1-1-636b11ebf191@linux.ibm.com> (raw)
In-Reply-To: <20261008-console_server-v1-0-636b11ebf191@linux.ibm.com>
From: Tobias Schumacher <ts@linux.ibm.com>
Introduce a centralized API for sending and receiving data between dibs
peers via ring buffers. With this API, drivers no longer need to
interact directly with DMBs and manage read/write pointers.
A driver must first register its ring buffer using
dibs_register_ring_buffer() and set the rdmb_tok via
dibs_ring_set_rdmb_tok(). After that, data can be sent using
dibs_ring_send().
Receiving messages is split into two steps: dibs_ring_recv() returns a
pointer to the next DIBS message if one is available. After the message
is processed, dibs_ring_ack() must be called to free up the message
buffers and to advance the read pointer. If no message is available,
dibs_ring_recv() returns NULL.
Co-developed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Tobias Schumacher <ts@linux.ibm.com>
---
drivers/dibs/dibs_main.c | 493 ++++++++++++++++++++++++++++++++++++++++++++++-
include/linux/dibs.h | 99 ++++++++++
2 files changed, 590 insertions(+), 2 deletions(-)
diff --git a/drivers/dibs/dibs_main.c b/drivers/dibs/dibs_main.c
index 20c50997a7cf..e3a33bc42fe8 100644
--- a/drivers/dibs/dibs_main.c
+++ b/drivers/dibs/dibs_main.c
@@ -13,6 +13,9 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/dibs.h>
+#include <linux/circ_buf.h>
+#include <linux/log2.h>
+#include <asm/barrier.h>
#include "dibs_loopback.h"
@@ -20,7 +23,7 @@ MODULE_DESCRIPTION("Direct Internal Buffer Sharing class");
MODULE_LICENSE("GPL");
static const struct class dibs_class = {
- .name = "dibs",
+ .name = "dibs",
};
/* use an array rather a list for fast mapping: */
@@ -93,7 +96,8 @@ int dibs_unregister_client(struct dibs_client *client)
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",
+ WARN(1,
+ "%s: attempt to unregister '%s' with registered dmb(s)\n",
__func__, client->name);
rc = -EBUSY;
goto err_reg_dmb;
@@ -245,6 +249,491 @@ void dibs_dev_del(struct dibs_dev *dibs)
}
EXPORT_SYMBOL_GPL(dibs_dev_del);
+/**
+ * dibs_ring_peer_meta() - take a snapshot of the peer's ring metadata
+ * @rb: pointer to the ring buffer
+ * @peer: snapshot to fill in
+ *
+ * The peer writes its metadata dmb at any time, so read each field once and
+ * copy to the snapshot.
+ */
+static void dibs_ring_peer_meta(struct dibs_ring_buffer *rb,
+ struct dibs_ring_meta *peer)
+{
+ peer->meta_dmb_tok = READ_ONCE(rb->rd_ring_meta->meta_dmb_tok);
+ peer->buff_dmb_tok = READ_ONCE(rb->rd_ring_meta->buff_dmb_tok);
+ peer->size = READ_ONCE(rb->rd_ring_meta->size);
+ peer->head = READ_ONCE(rb->rd_ring_meta->head);
+ peer->tail = READ_ONCE(rb->rd_ring_meta->tail);
+ peer->reserved = 0;
+}
+
+static int dibs_ring_send_hdr(struct dibs_ring_buffer *rb, u64 meta_dmb_tok)
+{
+ int res;
+
+ if (!meta_dmb_tok)
+ return 0;
+
+ res = rb->dibs->ops->move_data(rb->dibs, meta_dmb_tok, 0, true, 0,
+ &rb->wr_ring_meta,
+ sizeof(struct dibs_ring_meta));
+
+ if (!res)
+ rb->hdr_sent = true;
+
+ return res;
+}
+
+/**
+ * dibs_ring_register() - register a DIBS ring buffer
+ * @name: name of the ring buffer. This will be used in debug output to
+ * support identifying the ring buffer.
+ * @rb: pointer to the ring buffer struct. The fields in the struct don't have
+ * to be initialized.
+ * @client: pointer to the DIBS client
+ * @dibs: pointer to the DIBS device
+ * @rgid: the remote GID that will be allowed to write into this ring buffer
+ * @size: size of the ring buffer in bytes
+ *
+ * Register and initialize a DIBS ring buffer. Allocates the metadata DMB and
+ * the payload DMB, initializes the fields in dibs_ring_buffer.
+ *
+ * Return: 0 in case of success, an error code in case of failure
+ */
+int dibs_ring_register(char *name, struct dibs_ring_buffer *rb,
+ struct dibs_client *client, struct dibs_dev *dibs,
+ uuid_t rgid, u32 size)
+{
+ int ret;
+
+ if (!size || !is_power_of_2(size))
+ return -EINVAL;
+
+ strscpy(rb->name, name, sizeof(rb->name));
+ rb->dibs = dibs;
+ rb->dmb.rgid = rgid;
+
+ rb->rd_meta_dmb.dmb_len = ALIGN(sizeof(struct dibs_ring_meta), 4096);
+ rb->rd_meta_dmb.rgid = rgid;
+ ret = dibs->ops->register_dmb(dibs, &rb->rd_meta_dmb, client);
+ if (ret)
+ return ret;
+
+ rb->dmb.dmb_len = ALIGN(size, 4096);
+ ret = dibs->ops->register_dmb(dibs, &rb->dmb, client);
+ if (ret) {
+ dibs->ops->unregister_dmb(rb->dibs, &rb->rd_meta_dmb);
+ return ret;
+ }
+
+ rb->dmb_registered = 1;
+
+ rb->wr_ring_meta.meta_dmb_tok = rb->rd_meta_dmb.dmb_tok;
+ rb->wr_ring_meta.buff_dmb_tok = rb->dmb.dmb_tok;
+ rb->wr_ring_meta.size = size;
+ rb->wr_ring_meta.head = 0;
+ rb->wr_ring_meta.tail = 0;
+ rb->wr_ring_meta.reserved = 0;
+
+ rb->rd_ring_meta = rb->rd_meta_dmb.cpu_addr;
+ rb->peer_buff_dmb_tok = 0;
+ rb->msg_size = 0;
+ rb->hdr_sent = false;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dibs_ring_register);
+
+/**
+ * dibs_ring_unregister() - unregister a DIBS ring buffer
+ * @rb: pointer to the ring buffer to unregister
+ *
+ * Free the resources allocated by dibs_ring_register().
+ *
+ * Return: 0 in case of success, an error code in case of failure
+ */
+int dibs_ring_unregister(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+ int ret;
+
+ rb->wr_ring_meta.meta_dmb_tok = 0;
+ rb->wr_ring_meta.buff_dmb_tok = 0;
+ rb->wr_ring_meta.size = 0;
+ rb->wr_ring_meta.head = 0;
+ rb->wr_ring_meta.tail = 0;
+
+ dibs_ring_peer_meta(rb, &peer);
+ if (peer.meta_dmb_tok) {
+ ret = dibs_ring_send_hdr(rb, peer.meta_dmb_tok);
+ if (ret)
+ pr_warn("%s: failed to send header update: %d\n",
+ __func__, ret);
+ }
+
+ ret = rb->dibs->ops->unregister_dmb(rb->dibs, &rb->dmb);
+ if (ret)
+ pr_warn("%s: failed to unregister payload dmb: %d\n", __func__,
+ ret);
+
+ ret = rb->dibs->ops->unregister_dmb(rb->dibs, &rb->rd_meta_dmb);
+ if (ret)
+ pr_warn("%s: failed to unregister metadata dmb: %d\n", __func__,
+ ret);
+
+ rb->dmb_registered = 0;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dibs_ring_unregister);
+
+/**
+ * dibs_ring_peer_replaced() - check if the peer has replaced its ring buffer
+ * @rb: pointer to the ring buffer
+ * @peer: snapshot of the peer's metadata
+ *
+ * The fabric hands out a new dmb token for every registration, so a buffer
+ * token that differs from the one this side is synchronized to means the peer
+ * ring this side writes into is a different one.
+ *
+ * Return: true if the peer ring has been replaced, false otherwise
+ */
+static bool dibs_ring_peer_replaced(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ return peer->buff_dmb_tok != rb->peer_buff_dmb_tok;
+}
+
+/**
+ * dibs_ring_sync_peer() - synchronize with a replaced peer ring buffer
+ * @rb: pointer to the ring buffer
+ * @peer: snapshot of the peer's metadata
+ *
+ * Restart both pointers: head is this side's write position in the peer's
+ * buffer, which is a new and empty one, and tail is this side's read position
+ * in its own buffer, which the peer has started to write at offset 0 again.
+ * Sends the updated metadata header to the peer and only then remembers the
+ * new token, so that a failed send is retried on the next call.
+ *
+ * A peer that has torn its ring down is not synchronized to, it is only
+ * forgotten - this side cannot send anything until the peer registers again.
+ */
+static void dibs_ring_sync_peer(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ if (!peer->buff_dmb_tok) {
+ rb->wr_ring_meta.tail = 0;
+ rb->peer_buff_dmb_tok = 0;
+ rb->hdr_sent = false;
+ return;
+ }
+
+ rb->wr_ring_meta.head = 0;
+ rb->wr_ring_meta.tail = 0;
+
+ if (dibs_ring_send_hdr(rb, peer->meta_dmb_tok)) {
+ pr_warn("%s(%s): failed to send header after peer restart\n",
+ __func__, rb->name);
+ return;
+ }
+
+ rb->peer_buff_dmb_tok = peer->buff_dmb_tok;
+}
+
+/**
+ * dibs_ring_peer_ready() - check if the peer ring can be written to
+ * @peer: snapshot of the peer's metadata
+ *
+ * All of the peer's metadata is remote controlled. Its size is used as a mask
+ * for the head pointer and by the CIRC_* helpers, both of which require a
+ * power of two, so validate it before anything is derived from it.
+ *
+ * Return: true if the peer ring can be used, false otherwise
+ */
+static bool dibs_ring_peer_ready(const struct dibs_ring_meta *peer)
+{
+ if (!peer->meta_dmb_tok || !peer->buff_dmb_tok)
+ return false;
+
+ return is_power_of_2(peer->size);
+}
+
+static size_t __dibs_ring_space(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ if (!dibs_ring_peer_ready(peer))
+ return 0;
+
+ return CIRC_SPACE(rb->wr_ring_meta.head, peer->tail, peer->size);
+}
+
+static size_t __dibs_ring_space_to_end(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ if (!dibs_ring_peer_ready(peer))
+ return 0;
+
+ return CIRC_SPACE_TO_END(rb->wr_ring_meta.head, peer->tail, peer->size);
+}
+
+static u32 __dibs_ring_cnt(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ return CIRC_CNT(peer->head, rb->wr_ring_meta.tail,
+ rb->wr_ring_meta.size);
+}
+
+static u32 __dibs_ring_cnt_to_end(struct dibs_ring_buffer *rb,
+ const struct dibs_ring_meta *peer)
+{
+ return CIRC_CNT_TO_END(peer->head, rb->wr_ring_meta.tail,
+ rb->wr_ring_meta.size);
+}
+
+/**
+ * dibs_ring_space() - query the ring buffer's free space for sending
+ * @rb: pointer to the ring buffer
+ *
+ * Get the free space in the ring buffer that can be used for sending data.
+ * Automatically resynchronizes if the peer has replaced its ring.
+ *
+ * Return: the free space in the ring buffer
+ */
+size_t dibs_ring_space(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (dibs_ring_peer_replaced(rb, &peer))
+ dibs_ring_sync_peer(rb, &peer);
+
+ return __dibs_ring_space(rb, &peer);
+}
+
+/**
+ * dibs_ring_space_to_end() - query the rb's space until the end of the DMB
+ * @rb: pointer to the ring buffer
+ *
+ * Get the free space in the ring buffer until the end of the underlying DMB.
+ * This is the amount of data that can be written without wrapping to the
+ * beginning of the DMB.
+ *
+ * Return: the free space in the ring buffer until the end of the DMB.
+ */
+size_t dibs_ring_space_to_end(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ return __dibs_ring_space_to_end(rb, &peer);
+}
+
+/**
+ * dibs_ring_cnt() - query the ring buffer's fill state
+ * @rb: pointer to the ring buffer
+ *
+ * Get the number of bytes available in the ring buffer for reading.
+ * Automatically resynchronizes if the peer has replaced its ring.
+ *
+ * Return: fill state of the ring buffer
+ */
+u32 dibs_ring_cnt(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (dibs_ring_peer_replaced(rb, &peer))
+ dibs_ring_sync_peer(rb, &peer);
+
+ return __dibs_ring_cnt(rb, &peer);
+}
+
+/**
+ * dibs_ring_cnt_to_end() - query the number of bytes in rb before wrap
+ * @rb: pointer to the ring buffer
+ *
+ * Get the number of bytes that can be read from the ring buffer without
+ * wrapping the tail pointer.
+ *
+ * Return: number of consecutive readable bytes
+ */
+u32 dibs_ring_cnt_to_end(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ return __dibs_ring_cnt_to_end(rb, &peer);
+}
+
+/**
+ * dibs_ring_set_rdmb_tok() - complete ring buffer token exchange
+ * @rb: pointer to the ring buffer
+ * @rdmb_tok: remote peer's metadata DMB token
+ *
+ * Completes the ring buffer setup by storing the remote peer's metadata DMB
+ * token and sending our local metadata to the peer. Normally, DMB tokens are
+ * read from rd_meta_dmb, but this creates a circular dependency during initial
+ * setup (need the token to read the metadata that contains the token). To break
+ * this, one peer must receive the remote token through an alternative channel
+ * and call this function to send its own header as the initial handshake step.
+ * After this, both peers can read each other's metadata.
+ */
+void dibs_ring_set_rdmb_tok(struct dibs_ring_buffer *rb, u64 rdmb_tok)
+{
+ WRITE_ONCE(rb->rd_ring_meta->meta_dmb_tok, rdmb_tok);
+ dibs_ring_send_hdr(rb, rdmb_tok);
+}
+EXPORT_SYMBOL_GPL(dibs_ring_set_rdmb_tok);
+
+/**
+ * dibs_ring_send() - Send DIBS message to peer
+ * @rb: Ring buffer to send message to
+ * @msg: Message to send
+ * @size: size of the message to be sent
+ * @notify: if true, update the remote's ring header and generate an IRQ after
+ * sending.
+ *
+ * Send a DIBS message to the peer device using the specified ring buffer.
+ *
+ * Return: zero in case of success, an error code in case of failure
+ */
+int dibs_ring_send(struct dibs_ring_buffer *rb, void *msg, u16 size,
+ bool notify)
+{
+ struct dibs_ring_meta peer;
+ u32 old_head;
+ int ret;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (!dibs_ring_peer_ready(&peer))
+ return -EAGAIN;
+
+ if (__dibs_ring_space_to_end(rb, &peer) < size)
+ return -ENOSPC;
+
+ ret = rb->dibs->ops->move_data(rb->dibs, peer.buff_dmb_tok, 0, false,
+ rb->wr_ring_meta.head, msg, size);
+ if (ret)
+ return ret;
+
+ old_head = rb->wr_ring_meta.head;
+ rb->wr_ring_meta.head = (old_head + size) & (peer.size - 1);
+
+ if (notify) {
+ ret = dibs_ring_send_hdr(rb, peer.meta_dmb_tok);
+ if (ret) {
+ rb->wr_ring_meta.head = old_head;
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dibs_ring_send);
+
+/**
+ * dibs_ring_send_padding() - send padding data to ring buffer
+ * @rb: pointer to the ring buffer
+ * @size: number of bytes to send
+ *
+ * Advance the ring buffer's head pointer by size byte without actually
+ * writing any data into the data buffer. This can be used by higher level
+ * APIs to send padding data which shall be ignored by the receiving peer.
+ *
+ * Return: zero in case of success, an error code in case of failure
+ */
+int dibs_ring_send_padding(struct dibs_ring_buffer *rb, u16 size)
+{
+ struct dibs_ring_meta peer;
+ u32 old_head;
+ int ret;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (!dibs_ring_peer_ready(&peer))
+ return -EAGAIN;
+
+ if (__dibs_ring_space(rb, &peer) < size)
+ return -ENOSPC;
+
+ old_head = rb->wr_ring_meta.head;
+ rb->wr_ring_meta.head = (old_head + size) & (peer.size - 1);
+
+ ret = dibs_ring_send_hdr(rb, peer.meta_dmb_tok);
+ if (ret) {
+ rb->wr_ring_meta.head = old_head;
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dibs_ring_send_padding);
+
+/**
+ * dibs_ring_recv() - Receive message from DIBS ring buffer
+ * @rb: Ring buffer to get message from
+ *
+ * Get the next message from the ring buffer. After processing, the caller must
+ * call dibs_ring_ack() to update the ring buffer.
+ *
+ * Return: pointer to the DIBS message or NULL if the ring buffer is empty
+ */
+void *dibs_ring_recv(struct dibs_ring_buffer *rb)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (unlikely(!rb->hdr_sent))
+ dibs_ring_send_hdr(rb, peer.meta_dmb_tok);
+
+ if (dibs_ring_peer_replaced(rb, &peer))
+ dibs_ring_sync_peer(rb, &peer);
+
+ if (!__dibs_ring_cnt(rb, &peer))
+ return NULL;
+
+ /* pairs with the peer filling the payload before publishing head */
+ dma_rmb();
+
+ return rb->dmb.cpu_addr + rb->wr_ring_meta.tail;
+}
+EXPORT_SYMBOL_GPL(dibs_ring_recv);
+
+/**
+ * dibs_ring_ack() - Acknowledge received message
+ * @rb: Ring buffer to operate on
+ *
+ * Acknowledges the message received by dibs_ring_recv(). This means, the read
+ * pointer in the ring buffer header is incremented and the updated header is
+ * sent to the remote side. After calling dibs_ring_ack(), the message structure
+ * returned by dibs_ring_recv() may be reused, so the driver must not use it
+ * anymore.
+ */
+int dibs_ring_ack(struct dibs_ring_buffer *rb, size_t size)
+{
+ struct dibs_ring_meta peer;
+
+ dibs_ring_peer_meta(rb, &peer);
+
+ if (size > __dibs_ring_cnt(rb, &peer)) {
+ pr_warn("%s(%s, %lx): error: tail would overtake head\n",
+ __func__, rb->name, size);
+ return -EINVAL;
+ }
+
+ rb->wr_ring_meta.tail = (rb->wr_ring_meta.tail + size) &
+ (rb->wr_ring_meta.size - 1);
+
+ return dibs_ring_send_hdr(rb, peer.meta_dmb_tok);
+}
+EXPORT_SYMBOL_GPL(dibs_ring_ack);
+
static int __init dibs_init(void)
{
int rc;
diff --git a/include/linux/dibs.h b/include/linux/dibs.h
index 0c10c224bcca..30ae03484b58 100644
--- a/include/linux/dibs.h
+++ b/include/linux/dibs.h
@@ -67,6 +67,83 @@ struct dibs_dmb {
dma_addr_t dma_addr;
};
+/* Ring Buffer Communication
+ * -------------------------
+ * Based on the DMBs, DIBS provides a ring buffer mechanism for bi-directional
+ * communication between two peers. For each ring-buffer connection, two DMBs
+ * are allocated per peer:
+ * - one DMB holding metadata about the ring and
+ * - one DMB holding the actual data to be transferred.
+ *
+ * Metadata consists of parameters like the DMB tokens, size, head pointer and
+ * tail pointer. Note that the metadata stored in the locally allocated
+ * metadata DMB does not necessarily corelate to the locally allocated payload
+ * DMB. As illustrated below, each peer has access to one wr_ring_meta DMB
+ * (the one the other peer has allocated) and one rd_ring_meta DMB (the one
+ * it has allocated itself). This is because the locally allocated DMB can only
+ * be written by the other peer and vice versa.
+ *
+ * Peer A Peer B
+ * --------------- ---------------
+ * wr_ring_meta ----------> rd_ring_meta
+ * rd_ring_meta <---------- wr_ring_meta
+ * send_buffer ----------> recv_buffer
+ * recv_buffer <---------- send_buffer
+ *
+ * Consider for example that peer A wants to send data to peer B. It first has
+ * to check how much data it previously has written (head pointer) and how far
+ * peer B has read (tail pointer) and compare this to the size. Since for send
+ * operations head is updated by peer A, it is located in the wr_ring_meta DMB.
+ * Tail is updated by the receiving side, peer B in this case, so peer A will
+ * find the current value in rd_ring_meta. The payload DMB was allocated by
+ * peer B, so peer B also updated the size - peer A therefore finds the correct
+ * value in rd_ring_meta.
+ *
+ * Now peer a can write data into the send_buffer and update the head pointer
+ * in wr_ring_meta. Peer B then reads this head pointer from its rd_ring_meta
+ * DMB, process the data and update tail in its wr_ring_meta.
+ */
+struct dibs_ring_meta {
+ /* meta_dmb_tok - Token for the metadata dmb. */
+ u64 meta_dmb_tok;
+ /* buff_dmb_tok - Token for the buffer dmb */
+ u64 buff_dmb_tok;
+ /* size - size of the buffer for receiving data in number of byte */
+ u32 size;
+ /* head - points to the head of the ring buffer, i.e., the element
+ * that will be written next
+ */
+ u32 head;
+ /* tail - points to the end of the ring-buffer, i.e., the element
+ * that will be read next
+ */
+ u32 tail;
+ /* reserved - keeps the struct at its natural size, must be zero */
+ u32 reserved;
+};
+
+struct dibs_ring_buffer {
+ char name[256];
+ struct dibs_dev *dibs;
+ int dmb_registered;
+ bool hdr_sent;
+ struct dibs_dmb dmb;
+ /* dmb for the ring metadata this side can read, peer can write */
+ struct dibs_dmb rd_meta_dmb;
+ /* ring metadata this side can write, peer can read */
+ struct dibs_ring_meta wr_ring_meta;
+ /* ring metadata this side can read, peer can write */
+ struct dibs_ring_meta *rd_ring_meta;
+ /* size validated by dibs_pbd_msg_recv(), acked by dibs_pbd_msg_ack() */
+ u32 msg_size;
+ /* buff_dmb_tok of the peer ring this side is synchronized to. The
+ * fabric hands out a new token for every registration, so a different
+ * token means the peer has replaced its ring and the pointers into it
+ * are stale.
+ */
+ u64 peer_buff_dmb_tok;
+};
+
/* DIBS events
* -----------
* Dibs devices can optionally notify dibs clients about events that happened
@@ -432,6 +509,22 @@ static inline void *dibs_get_priv(struct dibs_dev *dev,
return dev->priv[client->id];
}
+int dibs_ring_register(char *name, struct dibs_ring_buffer *rb,
+ struct dibs_client *client,
+ struct dibs_dev *dibs,
+ uuid_t rgid,
+ u32 size);
+int dibs_ring_unregister(struct dibs_ring_buffer *rb);
+size_t dibs_ring_space(struct dibs_ring_buffer *rb);
+size_t dibs_ring_space_to_end(struct dibs_ring_buffer *rb);
+u32 dibs_ring_cnt(struct dibs_ring_buffer *rb);
+u32 dibs_ring_cnt_to_end(struct dibs_ring_buffer *rb);
+void dibs_ring_set_rdmb_tok(struct dibs_ring_buffer *rb, u64 rdmb_tok);
+int dibs_ring_send(struct dibs_ring_buffer *rb, void *msg, u16 size, bool notify);
+int dibs_ring_send_padding(struct dibs_ring_buffer *rb, u16 size);
+void *dibs_ring_recv(struct dibs_ring_buffer *rb);
+int dibs_ring_ack(struct dibs_ring_buffer *rb, size_t size);
+
/* ------- End of client-only functions ----------- */
/* Functions to be called by dibs device drivers:
@@ -461,4 +554,10 @@ int dibs_dev_add(struct dibs_dev *dibs);
*/
void dibs_dev_del(struct dibs_dev *dibs);
+struct dibs_msg_hdr {
+ u8 version;
+ u8 type;
+ u16 datalen;
+} __packed;
+
#endif /* _DIBS_H */
--
2.53.0
next prev parent reply other threads:[~2026-10-08 8:08 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 8:08 [PATCH 0/4] Introduce dibs peer bus driver, dibs console and dibs block device driver Julian Ruess
2026-10-08 8:08 ` Julian Ruess [this message]
2026-10-08 8:21 ` [PATCH 1/4] dibs: introduce ring-buffer send/receive API sashiko-bot
2026-10-09 20:47 ` Niklas Schnelle
2026-10-08 8:08 ` [PATCH 2/4] dibs: introduce dibs peer device bus driver Julian Ruess
2026-10-08 8:27 ` sashiko-bot
2026-10-08 8:08 ` [PATCH 3/4] dibs: introduce dibs console peer device driver Julian Ruess
2026-10-08 8:26 ` sashiko-bot
2026-10-08 8:08 ` [PATCH 4/4] dibs: introduce dibs block device " Julian Ruess
2026-10-08 8:30 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261008-console_server-v1-1-636b11ebf191@linux.ibm.com \
--to=julianr@linux.ibm.com \
--cc=agordeev@linux.ibm.com \
--cc=alifm@linux.ibm.com \
--cc=gbayer@linux.ibm.com \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=linux-s390@vger.kernel.org \
--cc=linux390-list@tuxmaker.boeblingen.de.ibm.com \
--cc=mjrosato@linux.ibm.com \
--cc=oberpar@linux.ibm.com \
--cc=raspl@linux.ibm.com \
--cc=schnelle@linux.ibm.com \
--cc=ts@linux.ibm.com \
--cc=wintera@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox