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 * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and
52 * return the response and set out_len. rpc_in can be returned as the
53 * response pointer. Otherwise the returned pointer is freed with
54 * kvfree().
55 */
56 void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
57 void *rpc_in, size_t in_len, size_t *out_len);
58 };
59
60 /**
61 * struct fwctl_device - Per-driver registration struct
62 * @dev: The sysfs (class/fwctl/fwctlXX) device
63 *
64 * Each driver instance will have one of these structs with the driver private
65 * data following immediately after. This struct is refcounted, it is freed by
66 * calling fwctl_put().
67 */
68 struct fwctl_device {
69 struct device dev;
70 /* private: */
71 struct cdev cdev;
72
73 /* Protect uctx_list */
74 struct mutex uctx_list_lock;
75 struct list_head uctx_list;
76 /*
77 * Protect ops, held for write when ops becomes NULL during unregister,
78 * held for read whenever ops is loaded or an ops function is running.
79 */
80 struct rw_semaphore registration_lock;
81 const struct fwctl_ops *ops;
82 };
83
84 struct fwctl_device *_fwctl_alloc_device(struct device *parent,
85 const struct fwctl_ops *ops,
86 size_t size);
87 /**
88 * fwctl_alloc_device - Allocate a fwctl
89 * @parent: Physical device that provides the FW interface
90 * @ops: Driver ops to register
91 * @drv_struct: 'struct driver_fwctl' that holds the struct fwctl_device
92 * @member: Name of the struct fwctl_device in @drv_struct
93 *
94 * This allocates and initializes the fwctl_device embedded in the drv_struct.
95 * Upon success the pointer must be freed via fwctl_put(). Returns a 'drv_struct
96 * \*' on success, NULL on error.
97 */
98 #define fwctl_alloc_device(parent, ops, drv_struct, member) \
99 ({ \
100 static_assert(__same_type(struct fwctl_device, \
101 ((drv_struct *)NULL)->member)); \
102 static_assert(offsetof(drv_struct, member) == 0); \
103 (drv_struct *)_fwctl_alloc_device(parent, ops, \
104 sizeof(drv_struct)); \
105 })
106
fwctl_get(struct fwctl_device * fwctl)107 static inline struct fwctl_device *fwctl_get(struct fwctl_device *fwctl)
108 {
109 get_device(&fwctl->dev);
110 return fwctl;
111 }
fwctl_put(struct fwctl_device * fwctl)112 static inline void fwctl_put(struct fwctl_device *fwctl)
113 {
114 put_device(&fwctl->dev);
115 }
116 DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T));
117
118 int fwctl_register(struct fwctl_device *fwctl);
119 void fwctl_unregister(struct fwctl_device *fwctl);
120
121 /**
122 * struct fwctl_uctx - Per user FD context
123 * @fwctl: fwctl instance that owns the context
124 *
125 * Every FD opened by userspace will get a unique context allocation. Any driver
126 * private data will follow immediately after.
127 */
128 struct fwctl_uctx {
129 struct fwctl_device *fwctl;
130 /* private: */
131 /* Head at fwctl_device::uctx_list */
132 struct list_head uctx_list_entry;
133 };
134
135 #endif
136