12e4986cfSJason Gunthorpe /* SPDX-License-Identifier: GPL-2.0-only */
22e4986cfSJason Gunthorpe /*
32e4986cfSJason Gunthorpe * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES
42e4986cfSJason Gunthorpe */
52e4986cfSJason Gunthorpe #ifndef __LINUX_FWCTL_H
62e4986cfSJason Gunthorpe #define __LINUX_FWCTL_H
72e4986cfSJason Gunthorpe #include <linux/device.h>
82e4986cfSJason Gunthorpe #include <linux/cdev.h>
92e4986cfSJason Gunthorpe #include <linux/cleanup.h>
10fb39e909SJason Gunthorpe #include <uapi/fwctl/fwctl.h>
112e4986cfSJason Gunthorpe
122e4986cfSJason Gunthorpe struct fwctl_device;
132e4986cfSJason Gunthorpe struct fwctl_uctx;
142e4986cfSJason Gunthorpe
150e79a47fSJason Gunthorpe /**
160e79a47fSJason Gunthorpe * struct fwctl_ops - Driver provided operations
170e79a47fSJason Gunthorpe *
180e79a47fSJason Gunthorpe * fwctl_unregister() will wait until all excuting ops are completed before it
190e79a47fSJason Gunthorpe * returns. Drivers should be mindful to not let their ops run for too long as
200e79a47fSJason Gunthorpe * it will block device hot unplug and module unloading.
210e79a47fSJason Gunthorpe */
222e4986cfSJason Gunthorpe struct fwctl_ops {
230e79a47fSJason Gunthorpe /**
24fb39e909SJason Gunthorpe * @device_type: The drivers assigned device_type number. This is uABI.
25fb39e909SJason Gunthorpe */
26fb39e909SJason Gunthorpe enum fwctl_device_type device_type;
27fb39e909SJason Gunthorpe /**
280e79a47fSJason Gunthorpe * @uctx_size: The size of the fwctl_uctx struct to allocate. The first
290e79a47fSJason Gunthorpe * bytes of this memory will be a fwctl_uctx. The driver can use the
300e79a47fSJason Gunthorpe * remaining bytes as its private memory.
310e79a47fSJason Gunthorpe */
320e79a47fSJason Gunthorpe size_t uctx_size;
330e79a47fSJason Gunthorpe /**
340e79a47fSJason Gunthorpe * @open_uctx: Called when a file descriptor is opened before the uctx
350e79a47fSJason Gunthorpe * is ever used.
360e79a47fSJason Gunthorpe */
370e79a47fSJason Gunthorpe int (*open_uctx)(struct fwctl_uctx *uctx);
380e79a47fSJason Gunthorpe /**
390e79a47fSJason Gunthorpe * @close_uctx: Called when the uctx is destroyed, usually when the FD
400e79a47fSJason Gunthorpe * is closed.
410e79a47fSJason Gunthorpe */
420e79a47fSJason Gunthorpe void (*close_uctx)(struct fwctl_uctx *uctx);
43fb39e909SJason Gunthorpe /**
44fb39e909SJason Gunthorpe * @info: Implement FWCTL_INFO. Return a kmalloc() memory that is copied
45fb39e909SJason Gunthorpe * to out_device_data. On input length indicates the size of the user
46fb39e909SJason Gunthorpe * buffer on output it indicates the size of the memory. The driver can
47fb39e909SJason Gunthorpe * ignore length on input, the core code will handle everything.
48fb39e909SJason Gunthorpe */
49fb39e909SJason Gunthorpe void *(*info)(struct fwctl_uctx *uctx, size_t *length);
50*840cfb7cSJason Gunthorpe /**
51*840cfb7cSJason Gunthorpe * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and
52*840cfb7cSJason Gunthorpe * return the response and set out_len. rpc_in can be returned as the
53*840cfb7cSJason Gunthorpe * response pointer. Otherwise the returned pointer is freed with
54*840cfb7cSJason Gunthorpe * kvfree().
55*840cfb7cSJason Gunthorpe */
56*840cfb7cSJason Gunthorpe void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
57*840cfb7cSJason Gunthorpe void *rpc_in, size_t in_len, size_t *out_len);
582e4986cfSJason Gunthorpe };
592e4986cfSJason Gunthorpe
602e4986cfSJason Gunthorpe /**
612e4986cfSJason Gunthorpe * struct fwctl_device - Per-driver registration struct
622e4986cfSJason Gunthorpe * @dev: The sysfs (class/fwctl/fwctlXX) device
632e4986cfSJason Gunthorpe *
642e4986cfSJason Gunthorpe * Each driver instance will have one of these structs with the driver private
652e4986cfSJason Gunthorpe * data following immediately after. This struct is refcounted, it is freed by
662e4986cfSJason Gunthorpe * calling fwctl_put().
672e4986cfSJason Gunthorpe */
682e4986cfSJason Gunthorpe struct fwctl_device {
692e4986cfSJason Gunthorpe struct device dev;
702e4986cfSJason Gunthorpe /* private: */
712e4986cfSJason Gunthorpe struct cdev cdev;
720e79a47fSJason Gunthorpe
730e79a47fSJason Gunthorpe /* Protect uctx_list */
740e79a47fSJason Gunthorpe struct mutex uctx_list_lock;
750e79a47fSJason Gunthorpe struct list_head uctx_list;
760e79a47fSJason Gunthorpe /*
770e79a47fSJason Gunthorpe * Protect ops, held for write when ops becomes NULL during unregister,
780e79a47fSJason Gunthorpe * held for read whenever ops is loaded or an ops function is running.
790e79a47fSJason Gunthorpe */
800e79a47fSJason Gunthorpe struct rw_semaphore registration_lock;
812e4986cfSJason Gunthorpe const struct fwctl_ops *ops;
822e4986cfSJason Gunthorpe };
832e4986cfSJason Gunthorpe
842e4986cfSJason Gunthorpe struct fwctl_device *_fwctl_alloc_device(struct device *parent,
852e4986cfSJason Gunthorpe const struct fwctl_ops *ops,
862e4986cfSJason Gunthorpe size_t size);
872e4986cfSJason Gunthorpe /**
882e4986cfSJason Gunthorpe * fwctl_alloc_device - Allocate a fwctl
892e4986cfSJason Gunthorpe * @parent: Physical device that provides the FW interface
902e4986cfSJason Gunthorpe * @ops: Driver ops to register
912e4986cfSJason Gunthorpe * @drv_struct: 'struct driver_fwctl' that holds the struct fwctl_device
922e4986cfSJason Gunthorpe * @member: Name of the struct fwctl_device in @drv_struct
932e4986cfSJason Gunthorpe *
942e4986cfSJason Gunthorpe * This allocates and initializes the fwctl_device embedded in the drv_struct.
952e4986cfSJason Gunthorpe * Upon success the pointer must be freed via fwctl_put(). Returns a 'drv_struct
962e4986cfSJason Gunthorpe * \*' on success, NULL on error.
972e4986cfSJason Gunthorpe */
982e4986cfSJason Gunthorpe #define fwctl_alloc_device(parent, ops, drv_struct, member) \
992e4986cfSJason Gunthorpe ({ \
1002e4986cfSJason Gunthorpe static_assert(__same_type(struct fwctl_device, \
1012e4986cfSJason Gunthorpe ((drv_struct *)NULL)->member)); \
1022e4986cfSJason Gunthorpe static_assert(offsetof(drv_struct, member) == 0); \
1032e4986cfSJason Gunthorpe (drv_struct *)_fwctl_alloc_device(parent, ops, \
1042e4986cfSJason Gunthorpe sizeof(drv_struct)); \
1052e4986cfSJason Gunthorpe })
1062e4986cfSJason Gunthorpe
fwctl_get(struct fwctl_device * fwctl)1072e4986cfSJason Gunthorpe static inline struct fwctl_device *fwctl_get(struct fwctl_device *fwctl)
1082e4986cfSJason Gunthorpe {
1092e4986cfSJason Gunthorpe get_device(&fwctl->dev);
1102e4986cfSJason Gunthorpe return fwctl;
1112e4986cfSJason Gunthorpe }
fwctl_put(struct fwctl_device * fwctl)1122e4986cfSJason Gunthorpe static inline void fwctl_put(struct fwctl_device *fwctl)
1132e4986cfSJason Gunthorpe {
1142e4986cfSJason Gunthorpe put_device(&fwctl->dev);
1152e4986cfSJason Gunthorpe }
1162e4986cfSJason Gunthorpe DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T));
1172e4986cfSJason Gunthorpe
1182e4986cfSJason Gunthorpe int fwctl_register(struct fwctl_device *fwctl);
1192e4986cfSJason Gunthorpe void fwctl_unregister(struct fwctl_device *fwctl);
1202e4986cfSJason Gunthorpe
1210e79a47fSJason Gunthorpe /**
1220e79a47fSJason Gunthorpe * struct fwctl_uctx - Per user FD context
1230e79a47fSJason Gunthorpe * @fwctl: fwctl instance that owns the context
1240e79a47fSJason Gunthorpe *
1250e79a47fSJason Gunthorpe * Every FD opened by userspace will get a unique context allocation. Any driver
1260e79a47fSJason Gunthorpe * private data will follow immediately after.
1270e79a47fSJason Gunthorpe */
1280e79a47fSJason Gunthorpe struct fwctl_uctx {
1290e79a47fSJason Gunthorpe struct fwctl_device *fwctl;
1300e79a47fSJason Gunthorpe /* private: */
1310e79a47fSJason Gunthorpe /* Head at fwctl_device::uctx_list */
1320e79a47fSJason Gunthorpe struct list_head uctx_list_entry;
1330e79a47fSJason Gunthorpe };
1340e79a47fSJason Gunthorpe
1352e4986cfSJason Gunthorpe #endif
136