Skip to content

Commit fb39e90

Browse files
committed
fwctl: FWCTL_INFO to return basic information about the device
Userspace will need to know some details about the fwctl interface being used to locate the correct userspace code to communicate with the kernel. Provide a simple device_type enum indicating what the kernel driver is. Allow the device to provide a device specific info struct that contains any additional information that the driver may need to provide to userspace. Link: https://patch.msgid.link/r/[email protected] Reviewed-by: Jonathan Cameron <[email protected]> Reviewed-by: Dave Jiang <[email protected]> Reviewed-by: Shannon Nelson <[email protected]> Tested-by: Dave Jiang <[email protected]> Tested-by: Shannon Nelson <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 0e79a47 commit fb39e90

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

drivers/fwctl/main.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,62 @@ struct fwctl_ucmd {
2727
u32 user_size;
2828
};
2929

30+
static int ucmd_respond(struct fwctl_ucmd *ucmd, size_t cmd_len)
31+
{
32+
if (copy_to_user(ucmd->ubuffer, ucmd->cmd,
33+
min_t(size_t, ucmd->user_size, cmd_len)))
34+
return -EFAULT;
35+
return 0;
36+
}
37+
38+
static int copy_to_user_zero_pad(void __user *to, const void *from,
39+
size_t from_len, size_t user_len)
40+
{
41+
size_t copy_len;
42+
43+
copy_len = min(from_len, user_len);
44+
if (copy_to_user(to, from, copy_len))
45+
return -EFAULT;
46+
if (copy_len < user_len) {
47+
if (clear_user(to + copy_len, user_len - copy_len))
48+
return -EFAULT;
49+
}
50+
return 0;
51+
}
52+
53+
static int fwctl_cmd_info(struct fwctl_ucmd *ucmd)
54+
{
55+
struct fwctl_device *fwctl = ucmd->uctx->fwctl;
56+
struct fwctl_info *cmd = ucmd->cmd;
57+
size_t driver_info_len = 0;
58+
59+
if (cmd->flags)
60+
return -EOPNOTSUPP;
61+
62+
if (!fwctl->ops->info && cmd->device_data_len) {
63+
if (clear_user(u64_to_user_ptr(cmd->out_device_data),
64+
cmd->device_data_len))
65+
return -EFAULT;
66+
} else if (cmd->device_data_len) {
67+
void *driver_info __free(kfree) =
68+
fwctl->ops->info(ucmd->uctx, &driver_info_len);
69+
if (IS_ERR(driver_info))
70+
return PTR_ERR(driver_info);
71+
72+
if (copy_to_user_zero_pad(u64_to_user_ptr(cmd->out_device_data),
73+
driver_info, driver_info_len,
74+
cmd->device_data_len))
75+
return -EFAULT;
76+
}
77+
78+
cmd->out_device_type = fwctl->ops->device_type;
79+
cmd->device_data_len = driver_info_len;
80+
return ucmd_respond(ucmd, sizeof(*cmd));
81+
}
82+
3083
/* On stack memory for the ioctl structs */
3184
union fwctl_ucmd_buffer {
85+
struct fwctl_info info;
3286
};
3387

3488
struct fwctl_ioctl_op {
@@ -48,6 +102,7 @@ struct fwctl_ioctl_op {
48102
.execute = _fn, \
49103
}
50104
static const struct fwctl_ioctl_op fwctl_ioctl_ops[] = {
105+
IOCTL_OP(FWCTL_INFO, fwctl_cmd_info, struct fwctl_info, out_device_data),
51106
};
52107

53108
static long fwctl_fops_ioctl(struct file *filp, unsigned int cmd,

include/linux/fwctl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/device.h>
88
#include <linux/cdev.h>
99
#include <linux/cleanup.h>
10+
#include <uapi/fwctl/fwctl.h>
1011

1112
struct fwctl_device;
1213
struct fwctl_uctx;
@@ -19,6 +20,10 @@ struct fwctl_uctx;
1920
* it will block device hot unplug and module unloading.
2021
*/
2122
struct fwctl_ops {
23+
/**
24+
* @device_type: The drivers assigned device_type number. This is uABI.
25+
*/
26+
enum fwctl_device_type device_type;
2227
/**
2328
* @uctx_size: The size of the fwctl_uctx struct to allocate. The first
2429
* bytes of this memory will be a fwctl_uctx. The driver can use the
@@ -35,6 +40,13 @@ struct fwctl_ops {
3540
* is closed.
3641
*/
3742
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);
3850
};
3951

4052
/**

include/uapi/fwctl/fwctl.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
#ifndef _UAPI_FWCTL_H
55
#define _UAPI_FWCTL_H
66

7+
#include <linux/types.h>
8+
#include <linux/ioctl.h>
9+
710
#define FWCTL_TYPE 0x9A
811

912
/**
@@ -33,6 +36,34 @@
3336
*/
3437
enum {
3538
FWCTL_CMD_BASE = 0,
39+
FWCTL_CMD_INFO = 0,
40+
};
41+
42+
enum fwctl_device_type {
43+
FWCTL_DEVICE_TYPE_ERROR = 0,
44+
};
45+
46+
/**
47+
* struct fwctl_info - ioctl(FWCTL_INFO)
48+
* @size: sizeof(struct fwctl_info)
49+
* @flags: Must be 0
50+
* @out_device_type: Returns the type of the device from enum fwctl_device_type
51+
* @device_data_len: On input the length of the out_device_data memory. On
52+
* output the size of the kernel's device_data which may be larger or
53+
* smaller than the input. Maybe 0 on input.
54+
* @out_device_data: Pointer to a memory of device_data_len bytes. Kernel will
55+
* fill the entire memory, zeroing as required.
56+
*
57+
* Returns basic information about this fwctl instance, particularly what driver
58+
* is being used to define the device_data format.
59+
*/
60+
struct fwctl_info {
61+
__u32 size;
62+
__u32 flags;
63+
__u32 out_device_type;
64+
__u32 device_data_len;
65+
__aligned_u64 out_device_data;
3666
};
67+
#define FWCTL_INFO _IO(FWCTL_TYPE, FWCTL_CMD_INFO)
3768

3869
#endif

0 commit comments

Comments
 (0)