]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - rpmsg/rpmsg.git/blob - drivers/rpmsg/rpmsg_pru.c
Merge branch 'rpmsg-linux-4.19.y' of git://git.ti.com/rpmsg/rpmsg into rpmsg-ti-linux...
[rpmsg/rpmsg.git] / drivers / rpmsg / rpmsg_pru.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PRU Remote Processor Messaging Driver
4  *
5  * Copyright (C) 2015-2019 Texas Instruments Incorporated - http://www.ti.com/
6  *      Jason Reeder <jreeder@ti.com>
7  *      Suman Anna <s-anna@ti.com>
8  */
10 #include <linux/kernel.h>
11 #include <linux/rpmsg.h>
12 #include <linux/slab.h>
13 #include <linux/fs.h>
14 #include <linux/init.h>
15 #include <linux/cdev.h>
16 #include <linux/module.h>
17 #include <linux/kfifo.h>
18 #include <linux/uaccess.h>
19 #include <linux/mutex.h>
20 #include <linux/poll.h>
21 #include <linux/rpmsg/virtio_rpmsg.h>
23 #define PRU_MAX_DEVICES                         (16)
24 /* Matches the definition in virtio_rpmsg_bus.c */
25 #define RPMSG_BUF_SIZE                          (512)
26 #define MAX_FIFO_MSG                            (32)
27 #define FIFO_MSG_SIZE                           RPMSG_BUF_SIZE
29 /**
30  * struct rpmsg_pru_dev - Structure that contains the per-device data
31  * @rpdev: rpmsg channel device that is associated with this rpmsg_pru device
32  * @dev: device
33  * @cdev: character device
34  * @locked: boolean used to determine whether or not the device file is in use
35  * @devt: dev_t structure for the rpmsg_pru device
36  * @msg_fifo: kernel fifo used to buffer the messages between userspace and PRU
37  * @msg_len: array storing the lengths of each message in the kernel fifo
38  * @msg_idx_rd: kernel fifo read index
39  * @msg_idx_wr: kernel fifo write index
40  * @wait_list: wait queue used to implement the poll operation of the character
41  *             device
42  *
43  * Each rpmsg_pru device provides an interface, using an rpmsg channel (rpdev),
44  * between a user space character device (cdev) and a PRU core. A kernel fifo
45  * (msg_fifo) is used to buffer the messages in the kernel that are
46  * being passed between the character device and the PRU.
47  */
48 struct rpmsg_pru_dev {
49         struct rpmsg_device *rpdev;
50         struct device *dev;
51         struct cdev cdev;
52         bool locked;
53         dev_t devt;
54         struct kfifo msg_fifo;
55         u32 msg_len[MAX_FIFO_MSG];
56         int msg_idx_rd;
57         int msg_idx_wr;
58         wait_queue_head_t wait_list;
59 };
61 static struct class *rpmsg_pru_class;
62 static dev_t rpmsg_pru_devt;
63 static DEFINE_MUTEX(rpmsg_pru_lock);
64 static DEFINE_IDR(rpmsg_pru_minors);
66 static int rpmsg_pru_open(struct inode *inode, struct file *filp)
67 {
68         struct rpmsg_pru_dev *prudev;
69         int ret = -EACCES;
71         prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev);
73         mutex_lock(&rpmsg_pru_lock);
74         if (!prudev->locked) {
75                 prudev->locked = true;
76                 filp->private_data = prudev;
77                 ret = 0;
78         }
79         mutex_unlock(&rpmsg_pru_lock);
81         if (ret)
82                 dev_err(prudev->dev, "Device already open\n");
84         return ret;
85 }
87 static int rpmsg_pru_release(struct inode *inode, struct file *filp)
88 {
89         struct rpmsg_pru_dev *prudev;
91         prudev = container_of(inode->i_cdev, struct rpmsg_pru_dev, cdev);
92         mutex_lock(&rpmsg_pru_lock);
93         prudev->locked = false;
94         mutex_unlock(&rpmsg_pru_lock);
95         return 0;
96 }
98 static ssize_t rpmsg_pru_read(struct file *filp, char __user *buf,
99                               size_t count, loff_t *f_pos)
101         int ret;
102         u32 length;
103         struct rpmsg_pru_dev *prudev;
105         prudev = filp->private_data;
107         if (kfifo_is_empty(&prudev->msg_fifo) &&
108             (filp->f_flags & O_NONBLOCK))
109                 return -EAGAIN;
111         ret = wait_event_interruptible(prudev->wait_list,
112                                        !kfifo_is_empty(&prudev->msg_fifo));
113         if (ret)
114                 return -EINTR;
116         ret = kfifo_to_user(&prudev->msg_fifo, buf,
117                             prudev->msg_len[prudev->msg_idx_rd], &length);
118         prudev->msg_idx_rd = (prudev->msg_idx_rd + 1) % MAX_FIFO_MSG;
120         return ret ? ret : length;
123 static ssize_t rpmsg_pru_write(struct file *filp, const char __user *buf,
124                                size_t count, loff_t *f_pos)
126         int ret;
127         struct rpmsg_pru_dev *prudev;
128         static char rpmsg_pru_buf[RPMSG_BUF_SIZE];
130         prudev = filp->private_data;
132         if (count > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) {
133                 dev_err(prudev->dev, "Data too large for RPMsg Buffer\n");
134                 return -EINVAL;
135         }
137         if (copy_from_user(rpmsg_pru_buf, buf, count)) {
138                 dev_err(prudev->dev, "Error copying buffer from user space");
139                 return -EFAULT;
140         }
142         ret = rpmsg_send(prudev->rpdev->ept, (void *)rpmsg_pru_buf, count);
143         if (ret)
144                 dev_err(prudev->dev, "rpmsg_send failed: %d\n", ret);
146         return ret ? ret : count;
149 static unsigned int rpmsg_pru_poll(struct file *filp,
150                                    struct poll_table_struct *wait)
152         int mask;
153         struct rpmsg_pru_dev *prudev;
155         prudev = filp->private_data;
157         poll_wait(filp, &prudev->wait_list, wait);
159         mask = POLLOUT | POLLWRNORM;
161         if (!kfifo_is_empty(&prudev->msg_fifo))
162                 mask |= POLLIN | POLLRDNORM;
164         return mask;
167 static const struct file_operations rpmsg_pru_fops = {
168         .owner = THIS_MODULE,
169         .open = rpmsg_pru_open,
170         .release = rpmsg_pru_release,
171         .read = rpmsg_pru_read,
172         .write = rpmsg_pru_write,
173         .poll = rpmsg_pru_poll,
174 };
176 static int rpmsg_pru_cb(struct rpmsg_device *rpdev, void *data, int len,
177                         void *priv, u32 src)
179         u32 length;
180         struct rpmsg_pru_dev *prudev;
182         prudev = dev_get_drvdata(&rpdev->dev);
184         if (kfifo_avail(&prudev->msg_fifo) < len) {
185                 dev_err(&rpdev->dev, "Not enough space on the FIFO\n");
186                 return -ENOSPC;
187         }
189         if ((prudev->msg_idx_wr + 1) % MAX_FIFO_MSG ==
190                 prudev->msg_idx_rd) {
191                 dev_err(&rpdev->dev, "Message length table is full\n");
192                 return -ENOSPC;
193         }
195         length = kfifo_in(&prudev->msg_fifo, data, len);
196         prudev->msg_len[prudev->msg_idx_wr] = length;
197         prudev->msg_idx_wr = (prudev->msg_idx_wr + 1) % MAX_FIFO_MSG;
199         wake_up_interruptible(&prudev->wait_list);
201         return 0;
204 static int rpmsg_pru_probe(struct rpmsg_device *rpdev)
206         int ret;
207         struct rpmsg_pru_dev *prudev;
208         int minor_got;
210         prudev = devm_kzalloc(&rpdev->dev, sizeof(*prudev), GFP_KERNEL);
211         if (!prudev)
212                 return -ENOMEM;
214         mutex_lock(&rpmsg_pru_lock);
215         minor_got = idr_alloc(&rpmsg_pru_minors, prudev, 0, PRU_MAX_DEVICES,
216                               GFP_KERNEL);
217         mutex_unlock(&rpmsg_pru_lock);
218         if (minor_got < 0) {
219                 ret = minor_got;
220                 dev_err(&rpdev->dev, "Failed to get a minor number for the rpmsg_pru device: %d\n",
221                         ret);
222                 goto fail_alloc_minor;
223         }
225         prudev->devt = MKDEV(MAJOR(rpmsg_pru_devt), minor_got);
227         cdev_init(&prudev->cdev, &rpmsg_pru_fops);
228         prudev->cdev.owner = THIS_MODULE;
229         ret = cdev_add(&prudev->cdev, prudev->devt, 1);
230         if (ret) {
231                 dev_err(&rpdev->dev, "Unable to add cdev for the rpmsg_pru device\n");
232                 goto fail_add_cdev;
233         }
235         prudev->dev = device_create(rpmsg_pru_class, &rpdev->dev, prudev->devt,
236                                     NULL, "rpmsg_pru%d", rpdev->dst);
237         if (IS_ERR(prudev->dev)) {
238                 dev_err(&rpdev->dev, "Unable to create the rpmsg_pru device\n");
239                 ret = PTR_ERR(prudev->dev);
240                 goto fail_create_device;
241         }
243         prudev->rpdev = rpdev;
245         ret = kfifo_alloc(&prudev->msg_fifo, MAX_FIFO_MSG * FIFO_MSG_SIZE,
246                           GFP_KERNEL);
247         if (ret) {
248                 dev_err(&rpdev->dev, "Unable to allocate fifo for the rpmsg_pru device\n");
249                 goto fail_alloc_fifo;
250         }
252         init_waitqueue_head(&prudev->wait_list);
254         dev_set_drvdata(&rpdev->dev, prudev);
256         dev_info(&rpdev->dev, "new rpmsg_pru device: /dev/rpmsg_pru%d",
257                  rpdev->dst);
259         return 0;
261 fail_alloc_fifo:
262         device_destroy(rpmsg_pru_class, prudev->devt);
263 fail_create_device:
264         cdev_del(&prudev->cdev);
265 fail_add_cdev:
266         mutex_lock(&rpmsg_pru_lock);
267         idr_remove(&rpmsg_pru_minors, minor_got);
268         mutex_unlock(&rpmsg_pru_lock);
269 fail_alloc_minor:
270         return ret;
273 static void rpmsg_pru_remove(struct rpmsg_device *rpdev)
275         struct rpmsg_pru_dev *prudev;
277         prudev = dev_get_drvdata(&rpdev->dev);
279         kfifo_free(&prudev->msg_fifo);
280         device_destroy(rpmsg_pru_class, prudev->devt);
281         cdev_del(&prudev->cdev);
282         mutex_lock(&rpmsg_pru_lock);
283         idr_remove(&rpmsg_pru_minors, MINOR(prudev->devt));
284         mutex_unlock(&rpmsg_pru_lock);
287 /* .name matches on RPMsg Channels and causes a probe */
288 static const struct rpmsg_device_id rpmsg_driver_pru_id_table[] = {
289         { .name = "rpmsg-pru" },
290         { },
291 };
292 MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_pru_id_table);
294 static struct rpmsg_driver rpmsg_pru_driver = {
295         .drv.name       = KBUILD_MODNAME,
296         .id_table       = rpmsg_driver_pru_id_table,
297         .probe          = rpmsg_pru_probe,
298         .callback       = rpmsg_pru_cb,
299         .remove         = rpmsg_pru_remove,
300 };
302 static int __init rpmsg_pru_init(void)
304         int ret;
306         rpmsg_pru_class = class_create(THIS_MODULE, "rpmsg_pru");
307         if (IS_ERR(rpmsg_pru_class)) {
308                 pr_err("Unable to create class\n");
309                 ret = PTR_ERR(rpmsg_pru_class);
310                 goto fail_create_class;
311         }
313         ret = alloc_chrdev_region(&rpmsg_pru_devt, 0, PRU_MAX_DEVICES,
314                                   "rpmsg_pru");
315         if (ret) {
316                 pr_err("Unable to allocate chrdev region\n");
317                 goto fail_alloc_region;
318         }
320         ret = register_rpmsg_driver(&rpmsg_pru_driver);
321         if (ret) {
322                 pr_err("Unable to register rpmsg driver");
323                 goto fail_register_rpmsg_driver;
324         }
326         return 0;
328 fail_register_rpmsg_driver:
329         unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
330 fail_alloc_region:
331         class_destroy(rpmsg_pru_class);
332 fail_create_class:
333         return ret;
336 static void __exit rpmsg_pru_exit(void)
338         unregister_rpmsg_driver(&rpmsg_pru_driver);
339         idr_destroy(&rpmsg_pru_minors);
340         mutex_destroy(&rpmsg_pru_lock);
341         class_destroy(rpmsg_pru_class);
342         unregister_chrdev_region(rpmsg_pru_devt, PRU_MAX_DEVICES);
345 module_init(rpmsg_pru_init);
346 module_exit(rpmsg_pru_exit);
348 MODULE_AUTHOR("Jason Reeder <jreeder@ti.com>");
349 MODULE_DESCRIPTION("PRU Remote Processor Messaging Driver");
350 MODULE_LICENSE("GPL v2");