| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES |
| */ |
| #ifndef __LINUX_FWCTL_H |
| #define __LINUX_FWCTL_H |
| #include <linux/device.h> |
| #include <linux/cdev.h> |
| #include <linux/cleanup.h> |
| #include <uapi/fwctl/fwctl.h> |
| |
| struct fwctl_device; |
| struct fwctl_uctx; |
| |
| /** |
| * struct fwctl_ops - Driver provided operations |
| * |
| * fwctl_unregister() will wait until all excuting ops are completed before it |
| * returns. Drivers should be mindful to not let their ops run for too long as |
| * it will block device hot unplug and module unloading. |
| */ |
| struct fwctl_ops { |
| /** |
| * @device_type: The drivers assigned device_type number. This is uABI. |
| */ |
| enum fwctl_device_type device_type; |
| /** |
| * @uctx_size: The size of the fwctl_uctx struct to allocate. The first |
| * bytes of this memory will be a fwctl_uctx. The driver can use the |
| * remaining bytes as its private memory. |
| */ |
| size_t uctx_size; |
| /** |
| * @open_uctx: Called when a file descriptor is opened before the uctx |
| * is ever used. |
| */ |
| int (*open_uctx)(struct fwctl_uctx *uctx); |
| /** |
| * @close_uctx: Called when the uctx is destroyed, usually when the FD |
| * is closed. |
| */ |
| void (*close_uctx)(struct fwctl_uctx *uctx); |
| /** |
| * @info: Implement FWCTL_INFO. Return a kmalloc() memory that is copied |
| * to out_device_data. On input length indicates the size of the user |
| * buffer on output it indicates the size of the memory. The driver can |
| * ignore length on input, the core code will handle everything. |
| */ |
| void *(*info)(struct fwctl_uctx *uctx, size_t *length); |
| /** |
| * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and |
| * return the response and set out_len. rpc_in can be returned as the |
| * response pointer. Otherwise the returned pointer is freed with |
| * kvfree(). |
| */ |
| void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope, |
| void *rpc_in, size_t in_len, size_t *out_len); |
| }; |
| |
| /** |
| * struct fwctl_device - Per-driver registration struct |
| * @dev: The sysfs (class/fwctl/fwctlXX) device |
| * |
| * Each driver instance will have one of these structs with the driver private |
| * data following immediately after. This struct is refcounted, it is freed by |
| * calling fwctl_put(). |
| */ |
| struct fwctl_device { |
| struct device dev; |
| /* private: */ |
| struct cdev cdev; |
| |
| /* Protect uctx_list */ |
| struct mutex uctx_list_lock; |
| struct list_head uctx_list; |
| /* |
| * Protect ops, held for write when ops becomes NULL during unregister, |
| * held for read whenever ops is loaded or an ops function is running. |
| */ |
| struct rw_semaphore registration_lock; |
| const struct fwctl_ops *ops; |
| }; |
| |
| struct fwctl_device *_fwctl_alloc_device(struct device *parent, |
| const struct fwctl_ops *ops, |
| size_t size); |
| /** |
| * fwctl_alloc_device - Allocate a fwctl |
| * @parent: Physical device that provides the FW interface |
| * @ops: Driver ops to register |
| * @drv_struct: 'struct driver_fwctl' that holds the struct fwctl_device |
| * @member: Name of the struct fwctl_device in @drv_struct |
| * |
| * This allocates and initializes the fwctl_device embedded in the drv_struct. |
| * Upon success the pointer must be freed via fwctl_put(). Returns a 'drv_struct |
| * \*' on success, NULL on error. |
| */ |
| #define fwctl_alloc_device(parent, ops, drv_struct, member) \ |
| ({ \ |
| static_assert(__same_type(struct fwctl_device, \ |
| ((drv_struct *)NULL)->member)); \ |
| static_assert(offsetof(drv_struct, member) == 0); \ |
| (drv_struct *)_fwctl_alloc_device(parent, ops, \ |
| sizeof(drv_struct)); \ |
| }) |
| |
| static inline struct fwctl_device *fwctl_get(struct fwctl_device *fwctl) |
| { |
| get_device(&fwctl->dev); |
| return fwctl; |
| } |
| static inline void fwctl_put(struct fwctl_device *fwctl) |
| { |
| put_device(&fwctl->dev); |
| } |
| DEFINE_FREE(fwctl, struct fwctl_device *, if (_T) fwctl_put(_T)); |
| |
| int fwctl_register(struct fwctl_device *fwctl); |
| void fwctl_unregister(struct fwctl_device *fwctl); |
| |
| /** |
| * struct fwctl_uctx - Per user FD context |
| * @fwctl: fwctl instance that owns the context |
| * |
| * Every FD opened by userspace will get a unique context allocation. Any driver |
| * private data will follow immediately after. |
| */ |
| struct fwctl_uctx { |
| struct fwctl_device *fwctl; |
| /* private: */ |
| /* Head at fwctl_device::uctx_list */ |
| struct list_head uctx_list_entry; |
| }; |
| |
| #endif |