1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
|
/* 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
#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
* 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.
*/
/* 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;
};
/* 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
* -----------
*/
#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:
*/
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);
/**
* 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);
/**
* 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 {
/* 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;
};
/* Functions to be called by dibs clients:
*/
/**
* 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);
/**
* 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);
/**
* 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);
/**
* 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
* @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);
/**
* 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)
* @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 {
struct list_head list;
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;
/* 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,
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:
*/
/**
* 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 */
|