xref: /linux-6.15/include/linux/fwctl.h (revision 8eea4e74)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES
4  */
5 #ifndef __LINUX_FWCTL_H
6 #define __LINUX_FWCTL_H
7 #include <linux/device.h>
8 #include <linux/cdev.h>
9 #include <linux/cleanup.h>
10 #include <uapi/fwctl/fwctl.h>
11 
12 struct fwctl_device;
13 struct fwctl_uctx;
14 
15 /**
16  * struct fwctl_ops - Driver provided operations
17  *
18  * fwctl_unregister() will wait until all excuting ops are completed before it
19  * returns. Drivers should be mindful to not let their ops run for too long as
20  * it will block device hot unplug and module unloading.
21  */
22 struct fwctl_ops {
23 	/**
24 	 * @device_type: The drivers assigned device_type number. This is uABI.
25 	 */
26 	enum fwctl_device_type device_type;
27 	/**
28 	 * @uctx_size: The size of the fwctl_uctx struct to allocate. The first
29 	 * bytes of this memory will be a fwctl_uctx. The driver can use the
30 	 * remaining bytes as its private memory.
31 	 */
32 	size_t uctx_size;
33 	/**
34 	 * @open_uctx: Called when a file descriptor is opened before the uctx
35 	 * is ever used.
36 	 */
37 	int (*open_uctx)(struct fwctl_uctx *uctx);
38 	/**
39 	 * @close_uctx: Called when the uctx is destroyed, usually when the FD
40 	 * is closed.
41 	 */
42 	void (*close_uctx)(struct fwctl_uctx *uctx);
43 	/**
44 	 * @info: Implement FWCTL_INFO. Return a kmalloc() memory that is copied
45 	 * to out_device_data. On input length indicates the size of the user
46 	 * buffer on output it indicates the size of the memory. The driver can
47 	 * ignore length on input, the core code will handle everything.
48 	 */
49 	void *(*info)(struct fwctl_uctx *uctx, size_t *length);
50 };
51 
52 /**
53  * struct fwctl_device - Per-driver registration struct
54  * @dev: The sysfs (class/fwctl/fwctlXX) device
55  *
56  * Each driver instance will have one of these structs with the driver private
57  * data following immediately after. This struct is refcounted, it is freed by
58  * calling fwctl_put().
59  */
60 struct fwctl_device {
61 	struct device dev;
62 	/* private: */
63 	struct cdev cdev;
64 
65 	/* Protect uctx_list */
66 	struct mutex uctx_list_lock;
67 	struct list_head uctx_list;
68 	/*
69 	 * Protect ops, held for write when ops becomes NULL during unregister,
70 	 * held for read whenever ops is loaded or an ops function is running.
71 	 */
72 	struct rw_semaphore registration_lock;
73 	const struct fwctl_ops *ops;
74 };
75 
76 struct fwctl_device *_fwctl_alloc_device(struct device *parent,
77 					 const struct fwctl_ops *ops,
78 					 size_t size);
79 /**
80  * fwctl_alloc_device - Allocate a fwctl
81  * @parent: Physical device that provides the FW interface
82  * @ops: Driver ops to register
83  * @drv_struct: 'struct driver_fwctl' that holds the struct fwctl_device
84  * @member: Name of the struct fwctl_device in @drv_struct
85  *
86  * This allocates and initializes the fwctl_device embedded in the drv_struct.
87  * Upon success the pointer must be freed via fwctl_put(). Returns a 'drv_struct
88  * \*' on success, NULL on error.
89  */
90 #define fwctl_alloc_device(parent, ops, drv_struct, member)               \
91 	({                                                                \
92 		static_assert(__same_type(struct fwctl_device,            \
93 					  ((drv_struct *)NULL)->member)); \
94 		static_assert(offsetof(drv_struct, member) == 0);         \
95 		(drv_struct *)_fwctl_alloc_device(parent, ops,            \
96 						  sizeof(drv_struct));    \
97 	})
98 
99 static inline struct fwctl_device *fwctl_get(struct fwctl_device *fwctl)
100 {
101 	get_device(&fwctl->dev);
102 	return fwctl;
103 }
104 static inline void fwctl_put(struct fwctl_device *fwctl)
105 {
106 	put_device(&fwctl->dev);
107 }
108 DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T));
109 
110 int fwctl_register(struct fwctl_device *fwctl);
111 void fwctl_unregister(struct fwctl_device *fwctl);
112 
113 /**
114  * struct fwctl_uctx - Per user FD context
115  * @fwctl: fwctl instance that owns the context
116  *
117  * Every FD opened by userspace will get a unique context allocation. Any driver
118  * private data will follow immediately after.
119  */
120 struct fwctl_uctx {
121 	struct fwctl_device *fwctl;
122 	/* private: */
123 	/* Head at fwctl_device::uctx_list */
124 	struct list_head uctx_list_entry;
125 };
126 
127 #endif
128