| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * Direct Internal Buffer Sharing |
| 4 | * |
| 5 | * Definitions for the DIBS module |
| 6 | * |
| 7 | * Copyright IBM Corp. 2025 |
| 8 | */ |
| 9 | #ifndef _DIBS_H |
| 10 | #define _DIBS_H |
| 11 | |
| 12 | #include <linux/device.h> |
| 13 | #include <linux/uuid.h> |
| 14 | |
| 15 | /* DIBS - Direct Internal Buffer Sharing - concept |
| 16 | * ----------------------------------------------- |
| 17 | * In the case of multiple system sharing the same hardware, dibs fabrics can |
| 18 | * provide dibs devices to these systems. The systems use dibs devices of the |
| 19 | * same fabric to communicate via dmbs (Direct Memory Buffers). Each dmb has |
| 20 | * exactly one owning local dibs device and one remote using dibs device, that |
| 21 | * is authorized to write into this dmb. This access control is provided by the |
| 22 | * dibs fabric. |
| 23 | * |
| 24 | * Because the access to the dmb is based on access to physical memory, it is |
| 25 | * lossless and synchronous. The remote devices can directly access any offset |
| 26 | * of the dmb. |
| 27 | * |
| 28 | * Dibs fabrics, dibs devices and dmbs are identified by tokens and ids. |
| 29 | * Dibs fabric id is unique within the same hardware (with the exception of the |
| 30 | * dibs loopback fabric), dmb token is unique within the same fabric, dibs |
| 31 | * device gids are guaranteed to be unique within the same fabric and |
| 32 | * statistically likely to be globally unique. The exchange of these tokens and |
| 33 | * ids between the systems is not part of the dibs concept. |
| 34 | * |
| 35 | * The dibs layer provides an abstraction between dibs device drivers and dibs |
| 36 | * clients. |
| 37 | */ |
| 38 | |
| 39 | /* DMB - Direct Memory Buffer |
| 40 | * -------------------------- |
| 41 | * A dibs client provides a dmb as input buffer for a local receiving |
| 42 | * dibs device for exactly one (remote) sending dibs device. Only this |
| 43 | * sending device can send data into this dmb using move_data(). Sender |
| 44 | * and receiver can be the same device. A dmb belongs to exactly one client. |
| 45 | */ |
| 46 | struct dibs_dmb { |
| 47 | /* tok - Token for this dmb |
| 48 | * Used by remote and local devices and clients to address this dmb. |
| 49 | * Provided by dibs fabric. Unique per dibs fabric. |
| 50 | */ |
| 51 | u64 dmb_tok; |
| 52 | /* rgid - GID of designated remote sending device */ |
| 53 | uuid_t rgid; |
| 54 | /* cpu_addr - buffer address */ |
| 55 | void *cpu_addr; |
| 56 | /* len - buffer length */ |
| 57 | u32 dmb_len; |
| 58 | /* idx - Index of this DMB on this receiving device */ |
| 59 | u32 idx; |
| 60 | /* VLAN support (deprecated) |
| 61 | * In order to write into a vlan-tagged dmb, the remote device needs |
| 62 | * to belong to the this vlan |
| 63 | */ |
| 64 | u32 vlan_valid; |
| 65 | u32 vlan_id; |
| 66 | /* optional, used by device driver */ |
| 67 | dma_addr_t dma_addr; |
| 68 | }; |
| 69 | |
| 70 | /* DIBS events |
| 71 | * ----------- |
| 72 | * Dibs devices can optionally notify dibs clients about events that happened |
| 73 | * in the fabric or at the remote device or remote dmb. |
| 74 | */ |
| 75 | enum dibs_event_type { |
| 76 | /* Buffer event, e.g. a remote dmb was unregistered */ |
| 77 | DIBS_BUF_EVENT, |
| 78 | /* Device event, e.g. a remote dibs device was disabled */ |
| 79 | DIBS_DEV_EVENT, |
| 80 | /* Software event, a dibs client can send an event signal to a |
| 81 | * remote dibs device. |
| 82 | */ |
| 83 | DIBS_SW_EVENT, |
| 84 | DIBS_OTHER_TYPE }; |
| 85 | |
| 86 | enum dibs_event_subtype { |
| 87 | DIBS_BUF_UNREGISTERED, |
| 88 | DIBS_DEV_DISABLED, |
| 89 | DIBS_DEV_ERR_STATE, |
| 90 | DIBS_OTHER_SUBTYPE |
| 91 | }; |
| 92 | |
| 93 | struct dibs_event { |
| 94 | u32 type; |
| 95 | u32 subtype; |
| 96 | /* uuid_null if invalid */ |
| 97 | uuid_t gid; |
| 98 | /* zero if invalid */ |
| 99 | u64 buffer_tok; |
| 100 | u64 time; |
| 101 | /* additional data or zero */ |
| 102 | u64 data; |
| 103 | }; |
| 104 | |
| 105 | struct dibs_dev; |
| 106 | |
| 107 | /* DIBS client |
| 108 | * ----------- |
| 109 | */ |
| 110 | #define MAX_DIBS_CLIENTS 8 |
| 111 | #define NO_DIBS_CLIENT 0xff |
| 112 | /* All dibs clients have access to all dibs devices. |
| 113 | * A dibs client provides the following functions to be called by dibs layer or |
| 114 | * dibs device drivers: |
| 115 | */ |
| 116 | struct dibs_client_ops { |
| 117 | /** |
| 118 | * add_dev() - add a dibs device |
| 119 | * @dev: device that was added |
| 120 | * |
| 121 | * Will be called during dibs_register_client() for all existing |
| 122 | * dibs devices and whenever a new dibs device is registered. |
| 123 | * dev is usable until dibs_client.remove() is called. |
| 124 | * *dev is protected by device refcounting. |
| 125 | */ |
| 126 | void (*add_dev)(struct dibs_dev *dev); |
| 127 | /** |
| 128 | * del_dev() - remove a dibs device |
| 129 | * @dev: device to be removed |
| 130 | * |
| 131 | * Will be called whenever a dibs device is removed. |
| 132 | * Will be called during dibs_unregister_client() for all existing |
| 133 | * dibs devices and whenever a dibs device is unregistered. |
| 134 | * The device has already stopped initiative for this client: |
| 135 | * No new handlers will be started. |
| 136 | * The device is no longer usable by this client after this call. |
| 137 | */ |
| 138 | void (*del_dev)(struct dibs_dev *dev); |
| 139 | /** |
| 140 | * handle_irq() - Handle signaling for a DMB |
| 141 | * @dev: device that owns the dmb |
| 142 | * @idx: Index of the dmb that got signalled |
| 143 | * @dmbemask: signaling mask of the dmb |
| 144 | * |
| 145 | * Handle signaling for a dmb that was registered by this client |
| 146 | * for this device. |
| 147 | * The dibs device can coalesce multiple signaling triggers into a |
| 148 | * single call of handle_irq(). dmbemask can be used to indicate |
| 149 | * different kinds of triggers. |
| 150 | * |
| 151 | * Context: Called in IRQ context by dibs device driver |
| 152 | */ |
| 153 | void (*handle_irq)(struct dibs_dev *dev, unsigned int idx, |
| 154 | u16 dmbemask); |
| 155 | /** |
| 156 | * handle_event() - Handle control information sent by device |
| 157 | * @dev: device reporting the event |
| 158 | * @event: ism event structure |
| 159 | * |
| 160 | * * Context: Called in IRQ context by dibs device driver |
| 161 | */ |
| 162 | void (*handle_event)(struct dibs_dev *dev, |
| 163 | const struct dibs_event *event); |
| 164 | }; |
| 165 | |
| 166 | struct dibs_client { |
| 167 | /* client name for logging and debugging purposes */ |
| 168 | const char *name; |
| 169 | const struct dibs_client_ops *ops; |
| 170 | /* client index - provided and used by dibs layer */ |
| 171 | u8 id; |
| 172 | }; |
| 173 | |
| 174 | /* Functions to be called by dibs clients: |
| 175 | */ |
| 176 | /** |
| 177 | * dibs_register_client() - register a client with dibs layer |
| 178 | * @client: this client |
| 179 | * |
| 180 | * Will call client->ops->add_dev() for all existing dibs devices. |
| 181 | * Return: zero on success. |
| 182 | */ |
| 183 | int dibs_register_client(struct dibs_client *client); |
| 184 | /** |
| 185 | * dibs_unregister_client() - unregister a client with dibs layer |
| 186 | * @client: this client |
| 187 | * |
| 188 | * Will call client->ops->del_dev() for all existing dibs devices. |
| 189 | * Return: zero on success. |
| 190 | */ |
| 191 | int dibs_unregister_client(struct dibs_client *client); |
| 192 | |
| 193 | /* dibs clients can call dibs device ops. */ |
| 194 | |
| 195 | /* DIBS devices |
| 196 | * ------------ |
| 197 | */ |
| 198 | |
| 199 | /* Defined fabric id / CHID for all loopback devices: |
| 200 | * All dibs loopback devices report this fabric id. In this case devices with |
| 201 | * the same fabric id can NOT communicate via dibs. Only loopback devices with |
| 202 | * the same dibs device gid can communicate (=same device with itself). |
| 203 | */ |
| 204 | #define DIBS_LOOPBACK_FABRIC 0xFFFF |
| 205 | |
| 206 | /* A dibs device provides the following functions to be called by dibs clients. |
| 207 | * They are mandatory, unless marked 'optional'. |
| 208 | */ |
| 209 | struct dibs_dev_ops { |
| 210 | /** |
| 211 | * get_fabric_id() |
| 212 | * @dev: local dibs device |
| 213 | * |
| 214 | * Only devices on the same dibs fabric can communicate. Fabric_id is |
| 215 | * unique inside the same HW system. Use fabric_id for fast negative |
| 216 | * checks, but only query_remote_gid() can give a reliable positive |
| 217 | * answer: |
| 218 | * Different fabric_id: dibs is not possible |
| 219 | * Same fabric_id: dibs may be possible or not |
| 220 | * (e.g. different HW systems) |
| 221 | * EXCEPTION: DIBS_LOOPBACK_FABRIC denotes an ism_loopback device |
| 222 | * that can only communicate with itself. Use dibs_dev.gid |
| 223 | * or query_remote_gid()to determine whether sender and |
| 224 | * receiver use the same ism_loopback device. |
| 225 | * Return: 2 byte dibs fabric id |
| 226 | */ |
| 227 | u16 (*get_fabric_id)(struct dibs_dev *dev); |
| 228 | /** |
| 229 | * query_remote_gid() |
| 230 | * @dev: local dibs device |
| 231 | * @rgid: gid of remote dibs device |
| 232 | * @vid_valid: if zero, vid will be ignored; |
| 233 | * deprecated, ignored if device does not support vlan |
| 234 | * @vid: VLAN id; deprecated, ignored if device does not support vlan |
| 235 | * |
| 236 | * Query whether a remote dibs device is reachable via this local device |
| 237 | * and this vlan id. |
| 238 | * Return: 0 if remote gid is reachable. |
| 239 | */ |
| 240 | int (*query_remote_gid)(struct dibs_dev *dev, const uuid_t *rgid, |
| 241 | u32 vid_valid, u32 vid); |
| 242 | /** |
| 243 | * max_dmbs() |
| 244 | * Return: Max number of DMBs that can be registered for this kind of |
| 245 | * dibs_dev |
| 246 | */ |
| 247 | int (*max_dmbs)(void); |
| 248 | /** |
| 249 | * register_dmb() - allocate and register a dmb |
| 250 | * @dev: dibs device |
| 251 | * @dmb: dmb struct to be registered |
| 252 | * @client: dibs client |
| 253 | * @vid: VLAN id; deprecated, ignored if device does not support vlan |
| 254 | * |
| 255 | * The following fields of dmb must provide valid input: |
| 256 | * @rgid: gid of remote user device |
| 257 | * @dmb_len: buffer length |
| 258 | * @idx: Optionally:requested idx (if non-zero) |
| 259 | * @vlan_valid: if zero, vlan_id will be ignored; |
| 260 | * deprecated, ignored if device does not support vlan |
| 261 | * @vlan_id: deprecated, ignored if device does not support vlan |
| 262 | * Upon return in addition the following fields will be valid: |
| 263 | * @dmb_tok: for usage by remote and local devices and clients |
| 264 | * @cpu_addr: allocated buffer |
| 265 | * @idx: dmb index, unique per dibs device |
| 266 | * @dma_addr: to be used by device driver,if applicable |
| 267 | * |
| 268 | * Allocate a dmb buffer and register it with this device and for this |
| 269 | * client. |
| 270 | * Return: zero on success |
| 271 | */ |
| 272 | int (*register_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb, |
| 273 | struct dibs_client *client); |
| 274 | /** |
| 275 | * unregister_dmb() - unregister and free a dmb |
| 276 | * @dev: dibs device |
| 277 | * @dmb: dmb struct to be unregistered |
| 278 | * The following fields of dmb must provide valid input: |
| 279 | * @dmb_tok |
| 280 | * @cpu_addr |
| 281 | * @idx |
| 282 | * |
| 283 | * Free dmb.cpu_addr and unregister the dmb from this device. |
| 284 | * Return: zero on success |
| 285 | */ |
| 286 | int (*unregister_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb); |
| 287 | /** |
| 288 | * move_data() - write into a remote dmb |
| 289 | * @dev: Local sending dibs device |
| 290 | * @dmb_tok: Token of the remote dmb |
| 291 | * @idx: signaling index in dmbemask |
| 292 | * @sf: signaling flag; |
| 293 | * if true, idx will be turned on at target dmbemask mask |
| 294 | * and target device will be signaled. |
| 295 | * @offset: offset within target dmb |
| 296 | * @data: pointer to data to be sent |
| 297 | * @size: length of data to be sent, can be zero. |
| 298 | * |
| 299 | * Use dev to write data of size at offset into a remote dmb |
| 300 | * identified by dmb_tok. Data is moved synchronously, *data can |
| 301 | * be freed when this function returns. |
| 302 | * |
| 303 | * If signaling flag (sf) is true, bit number idx bit will be turned |
| 304 | * on in the dmbemask mask when handle_irq() is called at the remote |
| 305 | * dibs client that owns the target dmb. The target device may chose |
| 306 | * to coalesce the signaling triggers of multiple move_data() calls |
| 307 | * to the same target dmb into a single handle_irq() call. |
| 308 | * Return: zero on success |
| 309 | */ |
| 310 | int (*move_data)(struct dibs_dev *dev, u64 dmb_tok, unsigned int idx, |
| 311 | bool sf, unsigned int offset, void *data, |
| 312 | unsigned int size); |
| 313 | /** |
| 314 | * add_vlan_id() - add dibs device to vlan (optional, deprecated) |
| 315 | * @dev: dibs device |
| 316 | * @vlan_id: vlan id |
| 317 | * |
| 318 | * In order to write into a vlan-tagged dmb, the remote device needs |
| 319 | * to belong to the this vlan. A device can belong to more than 1 vlan. |
| 320 | * Any device can access an untagged dmb. |
| 321 | * Deprecated, only supported for backwards compatibility. |
| 322 | * Return: zero on success |
| 323 | */ |
| 324 | int (*add_vlan_id)(struct dibs_dev *dev, u64 vlan_id); |
| 325 | /** |
| 326 | * del_vlan_id() - remove dibs device from vlan (optional, deprecated) |
| 327 | * @dev: dibs device |
| 328 | * @vlan_id: vlan id |
| 329 | * Return: zero on success |
| 330 | */ |
| 331 | int (*del_vlan_id)(struct dibs_dev *dev, u64 vlan_id); |
| 332 | /** |
| 333 | * signal_event() - trigger an event at a remote dibs device (optional) |
| 334 | * @dev: local dibs device |
| 335 | * @rgid: gid of remote dibs device |
| 336 | * trigger_irq: zero: notification may be coalesced with other events |
| 337 | * non-zero: notify immediately |
| 338 | * @subtype: 4 byte event code, meaning is defined by dibs client |
| 339 | * @data: 8 bytes of additional information, |
| 340 | * meaning is defined by dibs client |
| 341 | * |
| 342 | * dibs devices can offer support for sending a control event of type |
| 343 | * EVENT_SWR to a remote dibs device. |
| 344 | * NOTE: handle_event() will be called for all registered dibs clients |
| 345 | * at the remote device. |
| 346 | * Return: zero on success |
| 347 | */ |
| 348 | int (*signal_event)(struct dibs_dev *dev, const uuid_t *rgid, |
| 349 | u32 trigger_irq, u32 event_code, u64 info); |
| 350 | /** |
| 351 | * support_mmapped_rdmb() - can this device provide memory mapped |
| 352 | * remote dmbs? (optional) |
| 353 | * @dev: dibs device |
| 354 | * |
| 355 | * A dibs device can provide a kernel address + length, that represent |
| 356 | * a remote target dmb (like MMIO). Alternatively to calling |
| 357 | * move_data(), a dibs client can write into such a ghost-send-buffer |
| 358 | * (= to this kernel address) and the data will automatically |
| 359 | * immediately appear in the target dmb, even without calling |
| 360 | * move_data(). |
| 361 | * |
| 362 | * Either all 3 function pointers for support_dmb_nocopy(), |
| 363 | * attach_dmb() and detach_dmb() are defined, or all of them must |
| 364 | * be NULL. |
| 365 | * |
| 366 | * Return: non-zero, if memory mapped remote dmbs are supported. |
| 367 | */ |
| 368 | int (*support_mmapped_rdmb)(struct dibs_dev *dev); |
| 369 | /** |
| 370 | * attach_dmb() - attach local memory to a remote dmb |
| 371 | * @dev: Local sending ism device |
| 372 | * @dmb: all other parameters are passed in the form of a |
| 373 | * dmb struct |
| 374 | * TODO: (THIS IS CONFUSING, should be changed) |
| 375 | * dmb_tok: (in) Token of the remote dmb, we want to attach to |
| 376 | * cpu_addr: (out) MMIO address |
| 377 | * dma_addr: (out) MMIO address (if applicable, invalid otherwise) |
| 378 | * dmb_len: (out) length of local MMIO region, |
| 379 | * equal to length of remote DMB. |
| 380 | * sba_idx: (out) index of remote dmb (NOT HELPFUL, should be removed) |
| 381 | * |
| 382 | * Provides a memory address to the sender that can be used to |
| 383 | * directly write into the remote dmb. |
| 384 | * Memory is available until detach_dmb is called |
| 385 | * |
| 386 | * Return: Zero upon success, Error code otherwise |
| 387 | */ |
| 388 | int (*attach_dmb)(struct dibs_dev *dev, struct dibs_dmb *dmb); |
| 389 | /** |
| 390 | * detach_dmb() - Detach the ghost buffer from a remote dmb |
| 391 | * @dev: ism device |
| 392 | * @token: dmb token of the remote dmb |
| 393 | * |
| 394 | * No need to free cpu_addr. |
| 395 | * |
| 396 | * Return: Zero upon success, Error code otherwise |
| 397 | */ |
| 398 | int (*detach_dmb)(struct dibs_dev *dev, u64 token); |
| 399 | }; |
| 400 | |
| 401 | struct dibs_dev { |
| 402 | struct list_head list; |
| 403 | struct device dev; |
| 404 | /* To be filled by device driver, before calling dibs_dev_add(): */ |
| 405 | const struct dibs_dev_ops *ops; |
| 406 | uuid_t gid; |
| 407 | /* priv pointer for device driver */ |
| 408 | void *drv_priv; |
| 409 | |
| 410 | /* priv pointer per client; for client usage only */ |
| 411 | void *priv[MAX_DIBS_CLIENTS]; |
| 412 | |
| 413 | /* get this lock before accessing any of the fields below */ |
| 414 | spinlock_t lock; |
| 415 | /* array of client ids indexed by dmb idx; |
| 416 | * can be used as indices into priv and subs arrays |
| 417 | */ |
| 418 | u8 *dmb_clientid_arr; |
| 419 | /* Sparse array of all ISM clients */ |
| 420 | struct dibs_client *subs[MAX_DIBS_CLIENTS]; |
| 421 | }; |
| 422 | |
| 423 | static inline void dibs_set_priv(struct dibs_dev *dev, |
| 424 | struct dibs_client *client, void *priv) |
| 425 | { |
| 426 | dev->priv[client->id] = priv; |
| 427 | } |
| 428 | |
| 429 | static inline void *dibs_get_priv(struct dibs_dev *dev, |
| 430 | struct dibs_client *client) |
| 431 | { |
| 432 | return dev->priv[client->id]; |
| 433 | } |
| 434 | |
| 435 | /* ------- End of client-only functions ----------- */ |
| 436 | |
| 437 | /* Functions to be called by dibs device drivers: |
| 438 | */ |
| 439 | /** |
| 440 | * dibs_dev_alloc() - allocate and reference device structure |
| 441 | * |
| 442 | * The following fields will be valid upon successful return: dev |
| 443 | * NOTE: Use put_device(dibs_get_dev(@dibs)) to give up your reference instead |
| 444 | * of freeing @dibs @dev directly once you have successfully called this |
| 445 | * function. |
| 446 | * Return: Pointer to dibs device structure |
| 447 | */ |
| 448 | struct dibs_dev *dibs_dev_alloc(void); |
| 449 | /** |
| 450 | * dibs_dev_add() - register with dibs layer and all clients |
| 451 | * @dibs: dibs device |
| 452 | * |
| 453 | * The following fields must be valid upon entry: dev, ops, drv_priv |
| 454 | * All fields will be valid upon successful return. |
| 455 | * Return: zero on success |
| 456 | */ |
| 457 | int dibs_dev_add(struct dibs_dev *dibs); |
| 458 | /** |
| 459 | * dibs_dev_del() - unregister from dibs layer and all clients |
| 460 | * @dibs: dibs device |
| 461 | */ |
| 462 | void dibs_dev_del(struct dibs_dev *dibs); |
| 463 | |
| 464 | #endif /* _DIBS_H */ |
| 465 | |