Merge tag 'staging-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / staging / most / cdev / cdev.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cdev.c - Character device component for Mostcore
4  *
5  * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG
6  */
7
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 #include <linux/module.h>
10 #include <linux/sched.h>
11 #include <linux/fs.h>
12 #include <linux/slab.h>
13 #include <linux/device.h>
14 #include <linux/cdev.h>
15 #include <linux/poll.h>
16 #include <linux/kfifo.h>
17 #include <linux/uaccess.h>
18 #include <linux/idr.h>
19
20 #include "../most.h"
21
22 #define CHRDEV_REGION_SIZE 50
23
24 static struct cdev_component {
25         dev_t devno;
26         struct ida minor_id;
27         unsigned int major;
28         struct class *class;
29         struct most_component cc;
30 } comp;
31
32 struct comp_channel {
33         wait_queue_head_t wq;
34         spinlock_t unlink;      /* synchronization lock to unlink channels */
35         struct cdev cdev;
36         struct device *dev;
37         struct mutex io_mutex;
38         struct most_interface *iface;
39         struct most_channel_config *cfg;
40         unsigned int channel_id;
41         dev_t devno;
42         size_t mbo_offs;
43         DECLARE_KFIFO_PTR(fifo, typeof(struct mbo *));
44         int access_ref;
45         struct list_head list;
46 };
47
48 #define to_channel(d) container_of(d, struct comp_channel, cdev)
49 static struct list_head channel_list;
50 static spinlock_t ch_list_lock;
51
52 static inline bool ch_has_mbo(struct comp_channel *c)
53 {
54         return channel_has_mbo(c->iface, c->channel_id, &comp.cc) > 0;
55 }
56
57 static inline struct mbo *ch_get_mbo(struct comp_channel *c, struct mbo **mbo)
58 {
59         if (!kfifo_peek(&c->fifo, mbo)) {
60                 *mbo = most_get_mbo(c->iface, c->channel_id, &comp.cc);
61                 if (*mbo)
62                         kfifo_in(&c->fifo, mbo, 1);
63         }
64         return *mbo;
65 }
66
67 static struct comp_channel *get_channel(struct most_interface *iface, int id)
68 {
69         struct comp_channel *c, *tmp;
70         unsigned long flags;
71         int found_channel = 0;
72
73         spin_lock_irqsave(&ch_list_lock, flags);
74         list_for_each_entry_safe(c, tmp, &channel_list, list) {
75                 if ((c->iface == iface) && (c->channel_id == id)) {
76                         found_channel = 1;
77                         break;
78                 }
79         }
80         spin_unlock_irqrestore(&ch_list_lock, flags);
81         if (!found_channel)
82                 return NULL;
83         return c;
84 }
85
86 static void stop_channel(struct comp_channel *c)
87 {
88         struct mbo *mbo;
89
90         while (kfifo_out((struct kfifo *)&c->fifo, &mbo, 1))
91                 most_put_mbo(mbo);
92         most_stop_channel(c->iface, c->channel_id, &comp.cc);
93 }
94
95 static void destroy_cdev(struct comp_channel *c)
96 {
97         unsigned long flags;
98
99         device_destroy(comp.class, c->devno);
100         cdev_del(&c->cdev);
101         spin_lock_irqsave(&ch_list_lock, flags);
102         list_del(&c->list);
103         spin_unlock_irqrestore(&ch_list_lock, flags);
104 }
105
106 static void destroy_channel(struct comp_channel *c)
107 {
108         ida_simple_remove(&comp.minor_id, MINOR(c->devno));
109         kfifo_free(&c->fifo);
110         kfree(c);
111 }
112
113 /**
114  * comp_open - implements the syscall to open the device
115  * @inode: inode pointer
116  * @filp: file pointer
117  *
118  * This stores the channel pointer in the private data field of
119  * the file structure and activates the channel within the core.
120  */
121 static int comp_open(struct inode *inode, struct file *filp)
122 {
123         struct comp_channel *c;
124         int ret;
125
126         c = to_channel(inode->i_cdev);
127         filp->private_data = c;
128
129         if (((c->cfg->direction == MOST_CH_RX) &&
130              ((filp->f_flags & O_ACCMODE) != O_RDONLY)) ||
131              ((c->cfg->direction == MOST_CH_TX) &&
132                 ((filp->f_flags & O_ACCMODE) != O_WRONLY))) {
133                 pr_info("WARN: Access flags mismatch\n");
134                 return -EACCES;
135         }
136
137         mutex_lock(&c->io_mutex);
138         if (!c->dev) {
139                 pr_info("WARN: Device is destroyed\n");
140                 mutex_unlock(&c->io_mutex);
141                 return -ENODEV;
142         }
143
144         if (c->access_ref) {
145                 pr_info("WARN: Device is busy\n");
146                 mutex_unlock(&c->io_mutex);
147                 return -EBUSY;
148         }
149
150         c->mbo_offs = 0;
151         ret = most_start_channel(c->iface, c->channel_id, &comp.cc);
152         if (!ret)
153                 c->access_ref = 1;
154         mutex_unlock(&c->io_mutex);
155         return ret;
156 }
157
158 /**
159  * comp_close - implements the syscall to close the device
160  * @inode: inode pointer
161  * @filp: file pointer
162  *
163  * This stops the channel within the core.
164  */
165 static int comp_close(struct inode *inode, struct file *filp)
166 {
167         struct comp_channel *c = to_channel(inode->i_cdev);
168
169         mutex_lock(&c->io_mutex);
170         spin_lock(&c->unlink);
171         c->access_ref = 0;
172         spin_unlock(&c->unlink);
173         if (c->dev) {
174                 stop_channel(c);
175                 mutex_unlock(&c->io_mutex);
176         } else {
177                 mutex_unlock(&c->io_mutex);
178                 destroy_channel(c);
179         }
180         return 0;
181 }
182
183 /**
184  * comp_write - implements the syscall to write to the device
185  * @filp: file pointer
186  * @buf: pointer to user buffer
187  * @count: number of bytes to write
188  * @offset: offset from where to start writing
189  */
190 static ssize_t comp_write(struct file *filp, const char __user *buf,
191                           size_t count, loff_t *offset)
192 {
193         int ret;
194         size_t to_copy, left;
195         struct mbo *mbo = NULL;
196         struct comp_channel *c = filp->private_data;
197
198         mutex_lock(&c->io_mutex);
199         while (c->dev && !ch_get_mbo(c, &mbo)) {
200                 mutex_unlock(&c->io_mutex);
201
202                 if ((filp->f_flags & O_NONBLOCK))
203                         return -EAGAIN;
204                 if (wait_event_interruptible(c->wq, ch_has_mbo(c) || !c->dev))
205                         return -ERESTARTSYS;
206                 mutex_lock(&c->io_mutex);
207         }
208
209         if (unlikely(!c->dev)) {
210                 ret = -ENODEV;
211                 goto unlock;
212         }
213
214         to_copy = min(count, c->cfg->buffer_size - c->mbo_offs);
215         left = copy_from_user(mbo->virt_address + c->mbo_offs, buf, to_copy);
216         if (left == to_copy) {
217                 ret = -EFAULT;
218                 goto unlock;
219         }
220
221         c->mbo_offs += to_copy - left;
222         if (c->mbo_offs >= c->cfg->buffer_size ||
223             c->cfg->data_type == MOST_CH_CONTROL ||
224             c->cfg->data_type == MOST_CH_ASYNC) {
225                 kfifo_skip(&c->fifo);
226                 mbo->buffer_length = c->mbo_offs;
227                 c->mbo_offs = 0;
228                 most_submit_mbo(mbo);
229         }
230
231         ret = to_copy - left;
232 unlock:
233         mutex_unlock(&c->io_mutex);
234         return ret;
235 }
236
237 /**
238  * comp_read - implements the syscall to read from the device
239  * @filp: file pointer
240  * @buf: pointer to user buffer
241  * @count: number of bytes to read
242  * @offset: offset from where to start reading
243  */
244 static ssize_t
245 comp_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
246 {
247         size_t to_copy, not_copied, copied;
248         struct mbo *mbo = NULL;
249         struct comp_channel *c = filp->private_data;
250
251         mutex_lock(&c->io_mutex);
252         while (c->dev && !kfifo_peek(&c->fifo, &mbo)) {
253                 mutex_unlock(&c->io_mutex);
254                 if (filp->f_flags & O_NONBLOCK)
255                         return -EAGAIN;
256                 if (wait_event_interruptible(c->wq,
257                                              (!kfifo_is_empty(&c->fifo) ||
258                                               (!c->dev))))
259                         return -ERESTARTSYS;
260                 mutex_lock(&c->io_mutex);
261         }
262
263         /* make sure we don't submit to gone devices */
264         if (unlikely(!c->dev)) {
265                 mutex_unlock(&c->io_mutex);
266                 return -ENODEV;
267         }
268
269         to_copy = min_t(size_t,
270                         count,
271                         mbo->processed_length - c->mbo_offs);
272
273         not_copied = copy_to_user(buf,
274                                   mbo->virt_address + c->mbo_offs,
275                                   to_copy);
276
277         copied = to_copy - not_copied;
278
279         c->mbo_offs += copied;
280         if (c->mbo_offs >= mbo->processed_length) {
281                 kfifo_skip(&c->fifo);
282                 most_put_mbo(mbo);
283                 c->mbo_offs = 0;
284         }
285         mutex_unlock(&c->io_mutex);
286         return copied;
287 }
288
289 static __poll_t comp_poll(struct file *filp, poll_table *wait)
290 {
291         struct comp_channel *c = filp->private_data;
292         __poll_t mask = 0;
293
294         poll_wait(filp, &c->wq, wait);
295
296         mutex_lock(&c->io_mutex);
297         if (c->cfg->direction == MOST_CH_RX) {
298                 if (!c->dev || !kfifo_is_empty(&c->fifo))
299                         mask |= EPOLLIN | EPOLLRDNORM;
300         } else {
301                 if (!c->dev || !kfifo_is_empty(&c->fifo) || ch_has_mbo(c))
302                         mask |= EPOLLOUT | EPOLLWRNORM;
303         }
304         mutex_unlock(&c->io_mutex);
305         return mask;
306 }
307
308 /**
309  * Initialization of struct file_operations
310  */
311 static const struct file_operations channel_fops = {
312         .owner = THIS_MODULE,
313         .read = comp_read,
314         .write = comp_write,
315         .open = comp_open,
316         .release = comp_close,
317         .poll = comp_poll,
318 };
319
320 /**
321  * comp_disconnect_channel - disconnect a channel
322  * @iface: pointer to interface instance
323  * @channel_id: channel index
324  *
325  * This frees allocated memory and removes the cdev that represents this
326  * channel in user space.
327  */
328 static int comp_disconnect_channel(struct most_interface *iface, int channel_id)
329 {
330         struct comp_channel *c;
331
332         if (!iface) {
333                 pr_info("Bad interface pointer\n");
334                 return -EINVAL;
335         }
336
337         c = get_channel(iface, channel_id);
338         if (!c)
339                 return -ENXIO;
340
341         mutex_lock(&c->io_mutex);
342         spin_lock(&c->unlink);
343         c->dev = NULL;
344         spin_unlock(&c->unlink);
345         destroy_cdev(c);
346         if (c->access_ref) {
347                 stop_channel(c);
348                 wake_up_interruptible(&c->wq);
349                 mutex_unlock(&c->io_mutex);
350         } else {
351                 mutex_unlock(&c->io_mutex);
352                 destroy_channel(c);
353         }
354         return 0;
355 }
356
357 /**
358  * comp_rx_completion - completion handler for rx channels
359  * @mbo: pointer to buffer object that has completed
360  *
361  * This searches for the channel linked to this MBO and stores it in the local
362  * fifo buffer.
363  */
364 static int comp_rx_completion(struct mbo *mbo)
365 {
366         struct comp_channel *c;
367
368         if (!mbo)
369                 return -EINVAL;
370
371         c = get_channel(mbo->ifp, mbo->hdm_channel_id);
372         if (!c)
373                 return -ENXIO;
374
375         spin_lock(&c->unlink);
376         if (!c->access_ref || !c->dev) {
377                 spin_unlock(&c->unlink);
378                 return -ENODEV;
379         }
380         kfifo_in(&c->fifo, &mbo, 1);
381         spin_unlock(&c->unlink);
382 #ifdef DEBUG_MESG
383         if (kfifo_is_full(&c->fifo))
384                 pr_info("WARN: Fifo is full\n");
385 #endif
386         wake_up_interruptible(&c->wq);
387         return 0;
388 }
389
390 /**
391  * comp_tx_completion - completion handler for tx channels
392  * @iface: pointer to interface instance
393  * @channel_id: channel index/ID
394  *
395  * This wakes sleeping processes in the wait-queue.
396  */
397 static int comp_tx_completion(struct most_interface *iface, int channel_id)
398 {
399         struct comp_channel *c;
400
401         if (!iface) {
402                 pr_info("Bad interface pointer\n");
403                 return -EINVAL;
404         }
405         if ((channel_id < 0) || (channel_id >= iface->num_channels)) {
406                 pr_info("Channel ID out of range\n");
407                 return -EINVAL;
408         }
409
410         c = get_channel(iface, channel_id);
411         if (!c)
412                 return -ENXIO;
413         wake_up_interruptible(&c->wq);
414         return 0;
415 }
416
417 /**
418  * comp_probe - probe function of the driver module
419  * @iface: pointer to interface instance
420  * @channel_id: channel index/ID
421  * @cfg: pointer to actual channel configuration
422  * @name: name of the device to be created
423  *
424  * This allocates achannel object and creates the device node in /dev
425  *
426  * Returns 0 on success or error code otherwise.
427  */
428 static int comp_probe(struct most_interface *iface, int channel_id,
429                       struct most_channel_config *cfg, char *name, char *args)
430 {
431         struct comp_channel *c;
432         unsigned long cl_flags;
433         int retval;
434         int current_minor;
435
436         if ((!iface) || (!cfg) || (!name)) {
437                 pr_info("Probing component with bad arguments");
438                 return -EINVAL;
439         }
440         c = get_channel(iface, channel_id);
441         if (c)
442                 return -EEXIST;
443
444         current_minor = ida_simple_get(&comp.minor_id, 0, 0, GFP_KERNEL);
445         if (current_minor < 0)
446                 return current_minor;
447
448         c = kzalloc(sizeof(*c), GFP_KERNEL);
449         if (!c) {
450                 retval = -ENOMEM;
451                 goto err_remove_ida;
452         }
453
454         c->devno = MKDEV(comp.major, current_minor);
455         cdev_init(&c->cdev, &channel_fops);
456         c->cdev.owner = THIS_MODULE;
457         retval = cdev_add(&c->cdev, c->devno, 1);
458         if (retval < 0)
459                 goto err_free_c;
460         c->iface = iface;
461         c->cfg = cfg;
462         c->channel_id = channel_id;
463         c->access_ref = 0;
464         spin_lock_init(&c->unlink);
465         INIT_KFIFO(c->fifo);
466         retval = kfifo_alloc(&c->fifo, cfg->num_buffers, GFP_KERNEL);
467         if (retval)
468                 goto err_del_cdev_and_free_channel;
469         init_waitqueue_head(&c->wq);
470         mutex_init(&c->io_mutex);
471         spin_lock_irqsave(&ch_list_lock, cl_flags);
472         list_add_tail(&c->list, &channel_list);
473         spin_unlock_irqrestore(&ch_list_lock, cl_flags);
474         c->dev = device_create(comp.class, NULL, c->devno, NULL, "%s", name);
475
476         if (IS_ERR(c->dev)) {
477                 retval = PTR_ERR(c->dev);
478                 pr_info("failed to create new device node %s\n", name);
479                 goto err_free_kfifo_and_del_list;
480         }
481         kobject_uevent(&c->dev->kobj, KOBJ_ADD);
482         return 0;
483
484 err_free_kfifo_and_del_list:
485         kfifo_free(&c->fifo);
486         list_del(&c->list);
487 err_del_cdev_and_free_channel:
488         cdev_del(&c->cdev);
489 err_free_c:
490         kfree(c);
491 err_remove_ida:
492         ida_simple_remove(&comp.minor_id, current_minor);
493         return retval;
494 }
495
496 static struct cdev_component comp = {
497         .cc = {
498                 .mod = THIS_MODULE,
499                 .name = "cdev",
500                 .probe_channel = comp_probe,
501                 .disconnect_channel = comp_disconnect_channel,
502                 .rx_completion = comp_rx_completion,
503                 .tx_completion = comp_tx_completion,
504         },
505 };
506
507 static int __init mod_init(void)
508 {
509         int err;
510
511         pr_info("init()\n");
512
513         comp.class = class_create(THIS_MODULE, "most_cdev");
514         if (IS_ERR(comp.class)) {
515                 pr_info("No udev support.\n");
516                 return PTR_ERR(comp.class);
517         }
518
519         INIT_LIST_HEAD(&channel_list);
520         spin_lock_init(&ch_list_lock);
521         ida_init(&comp.minor_id);
522
523         err = alloc_chrdev_region(&comp.devno, 0, CHRDEV_REGION_SIZE, "cdev");
524         if (err < 0)
525                 goto dest_ida;
526         comp.major = MAJOR(comp.devno);
527         err = most_register_component(&comp.cc);
528         if (err)
529                 goto free_cdev;
530         err = most_register_configfs_subsys(&comp.cc);
531         if (err)
532                 goto deregister_comp;
533         return 0;
534
535 deregister_comp:
536         most_deregister_component(&comp.cc);
537 free_cdev:
538         unregister_chrdev_region(comp.devno, CHRDEV_REGION_SIZE);
539 dest_ida:
540         ida_destroy(&comp.minor_id);
541         class_destroy(comp.class);
542         return err;
543 }
544
545 static void __exit mod_exit(void)
546 {
547         struct comp_channel *c, *tmp;
548
549         pr_info("exit module\n");
550
551         most_deregister_configfs_subsys(&comp.cc);
552         most_deregister_component(&comp.cc);
553
554         list_for_each_entry_safe(c, tmp, &channel_list, list) {
555                 destroy_cdev(c);
556                 destroy_channel(c);
557         }
558         unregister_chrdev_region(comp.devno, CHRDEV_REGION_SIZE);
559         ida_destroy(&comp.minor_id);
560         class_destroy(comp.class);
561 }
562
563 module_init(mod_init);
564 module_exit(mod_exit);
565 MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>");
566 MODULE_LICENSE("GPL");
567 MODULE_DESCRIPTION("character device component for mostcore");