xref: /linux-6.15/include/linux/fwctl.h (revision 840cfb7c)
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