1 From 5b5567547d0088ec96160634c4e342bb06e52f19 Mon Sep 17 00:00:00 2001
2 From: Ioana Ciornei <ioana.ciornei@nxp.com>
3 Date: Wed, 14 Mar 2018 19:25:27 +0200
4 Subject: [PATCH] bus: fsl-mc: add fsl-mc userspace support
6 Adding userspace support for the MC (Management Complex) means exporting
7 an ioctl capable device file representing the root resource container.
9 This new functionality in the fsl-mc bus driver intends to provide
10 userspace applications an interface to interact with the MC firmware.
12 Commands that are composed in userspace are sent to the MC firmware
13 through the FSL_MC_SEND_MC_COMMAND ioctl. By default the implicit MC
14 I/O portal is used for this operation, but if the implicit one is busy,
15 a dynamic portal is allocated and then freed upon execution.
17 Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
19 Documentation/ioctl/ioctl-number.rst | 1 +
20 drivers/bus/fsl-mc/Kconfig | 7 ++
21 drivers/bus/fsl-mc/Makefile | 3 +
22 drivers/bus/fsl-mc/dprc-driver.c | 14 ++-
23 drivers/bus/fsl-mc/fsl-mc-private.h | 39 ++++++++
24 drivers/bus/fsl-mc/fsl-mc-uapi.c | 168 +++++++++++++++++++++++++++++++++++
25 include/uapi/linux/fsl_mc.h | 9 ++
26 7 files changed, 240 insertions(+), 1 deletion(-)
27 create mode 100644 drivers/bus/fsl-mc/fsl-mc-uapi.c
29 --- a/Documentation/ioctl/ioctl-number.rst
30 +++ b/Documentation/ioctl/ioctl-number.rst
31 @@ -180,6 +180,7 @@ Code Seq# Include File
32 'R' 00-1F linux/random.h conflict!
33 'R' 01 linux/rfkill.h conflict!
34 'R' C0-DF net/bluetooth/rfcomm.h
35 +'R' E0 uapi/linux/fsl_mc.h
36 'S' all linux/cdrom.h conflict!
37 'S' 80-81 scsi/scsi_ioctl.h conflict!
38 'S' 82-FF scsi/scsi.h conflict!
39 --- a/drivers/bus/fsl-mc/Kconfig
40 +++ b/drivers/bus/fsl-mc/Kconfig
41 @@ -14,3 +14,10 @@ config FSL_MC_BUS
42 architecture. The fsl-mc bus driver handles discovery of
43 DPAA2 objects (which are represented as Linux devices) and
44 binding objects to drivers.
46 +config FSL_MC_UAPI_SUPPORT
47 + bool "Management Complex (MC) userspace support"
48 + depends on FSL_MC_BUS
50 + Provides userspace support for creating/destroying/configuring
51 + DPAA2 objects in the Management Complex.
52 --- a/drivers/bus/fsl-mc/Makefile
53 +++ b/drivers/bus/fsl-mc/Makefile
54 @@ -16,3 +16,6 @@ mc-bus-driver-objs := fsl-mc-bus.o \
59 +# MC userspace support
60 +obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o
61 --- a/drivers/bus/fsl-mc/dprc-driver.c
62 +++ b/drivers/bus/fsl-mc/dprc-driver.c
63 @@ -647,6 +647,12 @@ static int dprc_probe(struct fsl_mc_devi
65 dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
66 msi_domain_set = true;
68 + error = fsl_mc_uapi_create_device_file(mc_bus);
70 + error = -EPROBE_DEFER;
71 + goto error_cleanup_msi_domain;
76 @@ -654,7 +660,7 @@ static int dprc_probe(struct fsl_mc_devi
79 dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error);
80 - goto error_cleanup_msi_domain;
81 + goto error_cleanup_uapi;
84 error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle,
85 @@ -706,6 +712,10 @@ static int dprc_probe(struct fsl_mc_devi
87 (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
90 + if (fsl_mc_is_root_dprc(&mc_dev->dev))
91 + fsl_mc_uapi_remove_device_file(mc_bus);
93 error_cleanup_msi_domain:
95 dev_set_msi_domain(&mc_dev->dev, NULL);
96 @@ -774,6 +784,8 @@ static int dprc_remove(struct fsl_mc_dev
97 if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
98 fsl_destroy_mc_io(mc_dev->mc_io);
101 + fsl_mc_uapi_remove_device_file(mc_bus);
104 dev_info(&mc_dev->dev, "DPRC device unbound from driver");
105 --- a/drivers/bus/fsl-mc/fsl-mc-private.h
106 +++ b/drivers/bus/fsl-mc/fsl-mc-private.h
109 #include <linux/fsl/mc.h>
110 #include <linux/mutex.h>
111 +#include <linux/ioctl.h>
112 +#include <linux/miscdevice.h>
115 * Data Path Management Complex (DPMNG) General API
116 @@ -505,6 +507,22 @@ struct fsl_mc_resource_pool {
120 + * struct fsl_mc_uapi - information associated with a device file
121 + * @misc: struct miscdevice linked to the root dprc
122 + * @device: newly created device in /dev
123 + * @mutex: mutex lock to serialize the open/release operations
124 + * @local_instance_in_use: local MC I/O instance in use or not
125 + * @static_mc_io: pointer to the static MC I/O object
127 +struct fsl_mc_uapi {
128 + struct miscdevice misc;
129 + struct device *device;
130 + struct mutex mutex; /* serialize open/release operations */
131 + u32 local_instance_in_use;
132 + struct fsl_mc_io *static_mc_io;
136 * struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
137 * @mc_dev: fsl-mc device for the bus device itself.
138 * @resource_pools: array of resource pools (one pool per resource type)
139 @@ -513,6 +531,7 @@ struct fsl_mc_resource_pool {
140 * @irq_resources: Pointer to array of IRQ objects for the IRQ pool
141 * @scan_mutex: Serializes bus scanning
142 * @dprc_attr: DPRC attributes
143 + * @uapi_misc: struct that abstracts the interaction with userspace
146 struct fsl_mc_device mc_dev;
147 @@ -520,6 +539,7 @@ struct fsl_mc_bus {
148 struct fsl_mc_device_irq *irq_resources;
149 struct mutex scan_mutex; /* serializes bus scanning */
150 struct dprc_attributes dprc_attr;
151 + struct fsl_mc_uapi uapi_misc;
154 #define to_fsl_mc_bus(_mc_dev) \
155 @@ -574,4 +594,23 @@ void fsl_destroy_mc_io(struct fsl_mc_io
157 bool fsl_mc_is_root_dprc(struct device *dev);
159 +#ifdef CONFIG_FSL_MC_UAPI_SUPPORT
161 +int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus);
163 +void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus);
167 +static inline int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
172 +static inline void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
178 #endif /* _FSL_MC_PRIVATE_H_ */
180 +++ b/drivers/bus/fsl-mc/fsl-mc-uapi.c
182 +// SPDX-License-Identifier: GPL-2.0
184 + * Management Complex (MC) userspace support
186 + * Copyright 2018 NXP
190 +#include <linux/slab.h>
191 +#include <linux/fs.h>
192 +#include <linux/uaccess.h>
193 +#include <linux/miscdevice.h>
195 +#include "fsl-mc-private.h"
197 +struct uapi_priv_data {
198 + struct fsl_mc_uapi *uapi;
199 + struct fsl_mc_io *mc_io;
202 +static int fsl_mc_uapi_send_command(unsigned long arg,
203 + struct fsl_mc_io *mc_io)
205 + struct fsl_mc_command mc_cmd;
208 + error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
212 + error = mc_send_command(mc_io, &mc_cmd);
216 + error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
223 +static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
225 + struct fsl_mc_device *root_mc_device;
226 + struct uapi_priv_data *priv_data;
227 + struct fsl_mc_io *dynamic_mc_io;
228 + struct fsl_mc_uapi *mc_uapi;
229 + struct fsl_mc_bus *mc_bus;
232 + priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
236 + mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
237 + mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
238 + root_mc_device = &mc_bus->mc_dev;
240 + mutex_lock(&mc_uapi->mutex);
242 + if (!mc_uapi->local_instance_in_use) {
243 + priv_data->mc_io = mc_uapi->static_mc_io;
244 + mc_uapi->local_instance_in_use = 1;
246 + error = fsl_mc_portal_allocate(root_mc_device, 0,
249 + dev_dbg(&root_mc_device->dev,
250 + "Could not allocate MC portal\n");
251 + goto error_portal_allocate;
254 + priv_data->mc_io = dynamic_mc_io;
256 + priv_data->uapi = mc_uapi;
257 + filep->private_data = priv_data;
259 + mutex_unlock(&mc_uapi->mutex);
263 +error_portal_allocate:
264 + mutex_unlock(&mc_uapi->mutex);
269 +static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
271 + struct uapi_priv_data *priv_data;
272 + struct fsl_mc_uapi *mc_uapi;
273 + struct fsl_mc_io *mc_io;
275 + priv_data = filep->private_data;
276 + mc_uapi = priv_data->uapi;
277 + mc_io = priv_data->mc_io;
279 + mutex_lock(&mc_uapi->mutex);
281 + if (mc_io == mc_uapi->static_mc_io)
282 + mc_uapi->local_instance_in_use = 0;
284 + fsl_mc_portal_free(mc_io);
286 + kfree(filep->private_data);
287 + filep->private_data = NULL;
289 + mutex_unlock(&mc_uapi->mutex);
294 +static long fsl_mc_uapi_dev_ioctl(struct file *file,
298 + struct uapi_priv_data *priv_data = file->private_data;
299 + struct fsl_mc_device *root_mc_device;
300 + struct fsl_mc_bus *mc_bus;
303 + mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
304 + root_mc_device = &mc_bus->mc_dev;
307 + case FSL_MC_SEND_MC_COMMAND:
308 + error = fsl_mc_uapi_send_command(arg, priv_data->mc_io);
311 + dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
318 +static const struct file_operations fsl_mc_uapi_dev_fops = {
319 + .owner = THIS_MODULE,
320 + .open = fsl_mc_uapi_dev_open,
321 + .release = fsl_mc_uapi_dev_release,
322 + .unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
325 +int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
327 + struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
328 + struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
331 + mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
332 + mc_uapi->misc.name = dev_name(&mc_dev->dev);
333 + mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
335 + error = misc_register(&mc_uapi->misc);
339 + mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
341 + mutex_init(&mc_uapi->mutex);
346 +void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
348 + misc_deregister(&mc_bus->uapi_misc.misc);
350 --- a/include/uapi/linux/fsl_mc.h
351 +++ b/include/uapi/linux/fsl_mc.h
353 * struct fsl_mc_command - Management Complex (MC) command structure
354 * @header: MC command header
355 * @params: MC command parameters
357 + * Used by FSL_MC_SEND_MC_COMMAND
359 struct fsl_mc_command {
361 __le64 params[MC_CMD_NUM_OF_PARAMS];
364 +#define FSL_MC_SEND_CMD_IOCTL_TYPE 'R'
365 +#define FSL_MC_SEND_CMD_IOCTL_SEQ 0xE0
367 +#define FSL_MC_SEND_MC_COMMAND \
368 + _IOWR(FSL_MC_SEND_CMD_IOCTL_TYPE, FSL_MC_SEND_CMD_IOCTL_SEQ, \
369 + struct fsl_mc_command)
371 #endif /* _UAPI_FSL_MC_H_ */