blob: de65ea05d2a33d30096a5b17ac1aaf0e0fc9cbb0 [file] [log] [blame]
Carl van Schaik2f4ca292018-06-12 01:46:33 +10001/*
2 * Driver for inter-cell links using the shared-buffer transport.
3 *
4 * Copyright (c) 2016 Cog Systems Pty Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10#include <linux/atomic.h>
11#include <linux/cdev.h>
12#include <linux/device.h>
13#include <linux/fs.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/io.h>
17#include <linux/ioctl.h>
18#include <linux/mm.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/of_irq.h>
23#include <linux/platform_device.h>
24#include <linux/poll.h>
25#include <linux/rwsem.h>
26#include <linux/spinlock.h>
27#include <linux/types.h>
28#include <linux/uaccess.h>
29#include <linux/sched.h>
30#include <linux/wait.h>
31#include <linux/version.h>
32#include <microvisor/microvisor.h>
33#include <uapi/linux/okl4-link-shbuf.h>
34
35static const char DEVICE_NAME[] = "okl4_link_shbuf";
36
37/* Created devices will appear as /dev/<DEV_PREFIX><name> */
38static const char DEV_PREFIX[] = "okl4-";
39
40static const struct of_device_id okl4_link_shbuf_match[] = {
41 {
42 .compatible = "okl,microvisor-link-shbuf",
43 },
44 {},
45};
46MODULE_DEVICE_TABLE(of, okl4_link_shbuf_match);
47
48static struct class *link_shbuf_class;
49static dev_t link_shbuf_dev;
50
51/* A lock used to protect access to link_shbuf_dev */
52static spinlock_t device_number_allocate;
53
54/* Sentinel values for indicating missing communication channels */
55static const u32 NO_OUTGOING_IRQ = 0;
56static const int NO_INCOMING_IRQ = -1;
57
58/* Private data for this driver */
59struct link_shbuf_data {
60
61 /* Outgoing vIRQ */
62 u32 virqline;
63
64 /* Incoming vIRQ */
65 int virq;
66 atomic64_t virq_payload;
67 bool virq_pending;
68 wait_queue_head_t virq_wq;
69
70 /* Shared memory region */
71 void *base;
72 fmode_t permissions;
73 struct resource buffer;
74
75 /* Device data */
76 dev_t devt;
77 struct device *dev;
78 struct cdev cdev;
79
80};
81
82static bool link_shbuf_data_invariant(const struct link_shbuf_data *priv)
83{
84 if (!priv)
85 return false;
86
87 if (!priv->base || (uintptr_t)priv->base % PAGE_SIZE != 0)
88 return false;
89
90 if (resource_size(&priv->buffer) == 0)
91 return false;
92
93 if (!priv->dev)
94 return false;
95
96 return true;
97}
98
99static bool link_shbuf_valid_access(size_t size, loff_t pos, size_t count)
100{
101 return pos < size && count <= size && size - count >= pos;
102}
103
104static ssize_t link_shbuf_read(struct file *file, char __user *buffer,
105 size_t count, loff_t *ppos)
106{
107 long remaining;
108 const struct link_shbuf_data *priv;
109
110 /* The file should have been opened with read access to reach here */
111 if (WARN_ON(!(file->f_mode & FMODE_READ)))
112 return -EINVAL;
113
114 priv = file->private_data;
115 if (WARN_ON(!link_shbuf_data_invariant(priv)))
116 return -EINVAL;
117
118 if (!link_shbuf_valid_access(resource_size(&priv->buffer), *ppos, count))
119 return -EINVAL;
120
121 remaining = copy_to_user(buffer, priv->base + *ppos, count);
122 *ppos += count - remaining;
123 return count - remaining;
124}
125
126static ssize_t link_shbuf_write(struct file *file, const char __user *buffer,
127 size_t count, loff_t *ppos)
128{
129 long remaining;
130 const struct link_shbuf_data *priv;
131
132 /* The file should have been opened with write access to reach here */
133 if (WARN_ON(!(file->f_mode & FMODE_WRITE)))
134 return -EINVAL;
135
136 priv = file->private_data;
137 if (WARN_ON(!link_shbuf_data_invariant(priv)))
138 return -EINVAL;
139
140 if (!link_shbuf_valid_access(resource_size(&priv->buffer), *ppos, count))
141 return -EINVAL;
142
143 remaining = copy_from_user(priv->base + *ppos, buffer, count);
144 *ppos += count - remaining;
145 return count - remaining;
146}
147
148static unsigned int link_shbuf_poll(struct file *file, poll_table *table)
149{
150 struct link_shbuf_data *priv;
151 unsigned int mask;
152
153 priv = file->private_data;
154 if (WARN_ON(!link_shbuf_data_invariant(priv)))
155 return POLLERR;
156
157 poll_wait(file, &priv->virq_wq, table);
158
159 /* The shared memory is always considered ready for reading and writing. */
160 mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;
161
162 if (priv->virq_pending)
163 mask |= POLLPRI;
164
165 return mask;
166}
167
168static long link_shbuf_ioctl_irq_tx(const struct link_shbuf_data *priv,
169 unsigned long arg)
170{
171 okl4_error_t err;
172 u64 payload;
173 const u64 __user *user_arg = (const u64 __user*)arg;
174
175 if (priv->virqline == NO_OUTGOING_IRQ)
176 return -EINVAL;
177
178#if defined(CONFIG_ARM) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0))
179 if (copy_from_user(&payload, user_arg, sizeof(payload)))
180 return -EFAULT;
181#else
182 if (get_user(payload, user_arg))
183 return -EFAULT;
184#endif
185
186 err = _okl4_sys_vinterrupt_raise(priv->virqline, payload);
187 if (WARN_ON(err != OKL4_OK))
188 return -EINVAL;
189
190 return 0;
191}
192
193static long link_shbuf_ioctl_irq_clr(struct link_shbuf_data *priv,
194 unsigned long arg)
195{
196 u64 payload;
197 u64 __user *user_arg = (u64 __user*)arg;
198
199 /*
200 * Check validity of the user pointer before clearing the interrupt to avoid
201 * races involved with having to undo the latter.
202 */
203 if (!access_ok(VERIFY_WRITE, user_arg, sizeof(*user_arg)))
204 return -EFAULT;
205
206 /*
207 * Note that the clearing of the pending flag can race with the setting of
208 * this flag in the IRQ handler. It is up to the user to coordinate these
209 * actions.
210 */
211 priv->virq_pending = false;
212 smp_rmb();
213 payload = atomic64_xchg(&priv->virq_payload, 0);
214
215 /* We've already checked that this access is OK, so no need for put_user. */
216 if (__put_user(payload, user_arg))
217 return -EFAULT;
218
219 return 0;
220}
221
222static long link_shbuf_ioctl(struct file *file, unsigned int request,
223 unsigned long arg)
224{
225 struct link_shbuf_data *priv;
226
227 priv = file->private_data;
228 if (WARN_ON(!link_shbuf_data_invariant(priv)))
229 return -EINVAL;
230
231 /* We only support two ioctls */
232 switch (request) {
233
234 case OKL4_LINK_SHBUF_IOCTL_IRQ_TX:
235 return link_shbuf_ioctl_irq_tx(priv, arg);
236
237 case OKL4_LINK_SHBUF_IOCTL_IRQ_CLR:
238 return link_shbuf_ioctl_irq_clr(priv, arg);
239
240 }
241
242 /*
243 * Handy for debugging when userspace is linking against ioctl headers from
244 * a different kernel revision.
245 */
246 dev_dbg(priv->dev, "ioctl request 0x%x received which did not match either "
247 "OKL4_LINK_SHBUF_IOCTL_IRQ_TX (0x%x) or OKL4_LINK_SHBUF_IOCTL_IRQ_CLR "
248 "(0x%x)\n", request, (unsigned)OKL4_LINK_SHBUF_IOCTL_IRQ_TX,
249 (unsigned)OKL4_LINK_SHBUF_IOCTL_IRQ_CLR);
250
251 return -EINVAL;
252}
253
254static int link_shbuf_mmap(struct file *file, struct vm_area_struct *vma)
255{
256 const struct link_shbuf_data *priv;
257 unsigned long offset, pfn, flags;
258 size_t size;
259 pgprot_t prot;
260
261 /* Our caller should have taken the MM semaphore. */
262 if (WARN_ON(!rwsem_is_locked(&vma->vm_mm->mmap_sem)))
263 return -EINVAL;
264
265 /*
266 * The file should have been opened with a superset of the mmap requested
267 * permissions.
268 */
269 flags = vma->vm_flags;
270 if (WARN_ON((flags & VM_READ) && !(file->f_mode & FMODE_READ)))
271 return -EINVAL;
272 if (WARN_ON((flags & VM_WRITE) && !(file->f_mode & FMODE_WRITE)))
273 return -EINVAL;
274 if (WARN_ON((flags & VM_EXEC) && !(file->f_mode & FMODE_EXEC)))
275 return -EINVAL;
276
277 /* Retrieve our private data. */
278 priv = file->private_data;
279 if (WARN_ON(!link_shbuf_data_invariant(priv)))
280 return -EINVAL;
281
282 /* Check the mmap request is within bounds. */
283 size = vma->vm_end - vma->vm_start;
284 offset = vma->vm_pgoff << PAGE_SHIFT;
285 if (!link_shbuf_valid_access(resource_size(&priv->buffer), offset, size))
286 return -EINVAL;
287
288 pfn = (priv->buffer.start + offset) >> PAGE_SHIFT;
289 prot = vm_get_page_prot(flags);
290
291 return remap_pfn_range(vma, vma->vm_start, pfn, size, prot);
292}
293
294static bool link_shbuf_access_ok(fmode_t allowed, fmode_t request)
295{
296 static const fmode_t ACCESS_MASK = FMODE_READ|FMODE_WRITE|FMODE_EXEC;
297 fmode_t relevant = request & ACCESS_MASK;
298 return (relevant & allowed) == relevant;
299}
300
301static int link_shbuf_open(struct inode *inode, struct file *file)
302{
303 struct cdev *cdev;
304 struct link_shbuf_data *priv;
305
306 /* Retrieve a pointer to our private data */
307 cdev = inode->i_cdev;
308 priv = container_of(cdev, struct link_shbuf_data, cdev);
309 if (WARN_ON(!link_shbuf_data_invariant(priv)))
310 return -EINVAL;
311
312 if (!link_shbuf_access_ok(priv->permissions, file->f_mode))
313 return -EACCES;
314
315 file->private_data = priv;
316
317 return 0;
318}
319
320static const struct file_operations link_shbuf_ops = {
321 .owner = THIS_MODULE,
322 .read = link_shbuf_read,
323 .write = link_shbuf_write,
324 .poll = link_shbuf_poll,
325 .unlocked_ioctl = link_shbuf_ioctl,
326#ifdef CONFIG_COMPAT
327 .compat_ioctl = link_shbuf_ioctl,
328#endif
329#ifdef CONFIG_MMU
330 .mmap = link_shbuf_mmap,
331#endif
332 .open = link_shbuf_open,
333};
334
335/*
336 * Interrupt handler.
337 *
338 * This function will be called when our link partner uses the ioctl on their
339 * shared memory device to send an outgoing interrupt.
340 */
341static irqreturn_t link_shbuf_irq_handler(int irq, void *data)
342{
343 u64 payload, old, new;
344 struct _okl4_sys_interrupt_get_payload_return _payload;
345
346 /* Retrieve a pointer to our private data. */
347 struct link_shbuf_data *priv = data;
348 if (WARN_ON(!link_shbuf_data_invariant(priv)))
349 return IRQ_NONE;
350
351 /*
352 * We should only ever be handling a single interrupt, and only if there
353 * was an incoming interrupt in the configuration.
354 */
355 if (WARN_ON(priv->virq < 0 || priv->virq != irq))
356 return IRQ_NONE;
357
358 _payload = _okl4_sys_interrupt_get_payload(irq);
359 payload = (u64)_payload.payload;
360
361 /*
362 * At this point, it is possible the pending flag is already set. It is up to
363 * the user to synchronise their transmission and acknowledgement of
364 * interrupts.
365 */
366
367 /* We open code atomic64_or which is not universally available. */
368 do {
369 old = atomic64_read(&priv->virq_payload);
370 new = old | payload;
371 } while (atomic64_cmpxchg(&priv->virq_payload, old, new) != old);
372 smp_wmb();
373 priv->virq_pending = true;
374
375 wake_up_interruptible(&priv->virq_wq);
376
377 return IRQ_HANDLED;
378}
379
380/*
381 * Allocate a unique device number for this device.
382 *
383 * Note that this function needs to lock its access to link_shbuf_dev as there
384 * may be multiple threads attempting to acquire a new device number.
385 */
386static int link_shbuf_allocate_device(dev_t *devt)
387{
388 int ret = 0;
389 dev_t next;
390
391 spin_lock(&device_number_allocate);
392
393 *devt = link_shbuf_dev;
394 next = MKDEV(MAJOR(link_shbuf_dev), MINOR(link_shbuf_dev) + 1);
395 /* Check for overflow */
396 if (MINOR(next) != MINOR(link_shbuf_dev) + 1)
397 ret = -ENOSPC;
398 else
399 link_shbuf_dev = next;
400
401 spin_unlock(&device_number_allocate);
402
403 return ret;
404}
405
406/*
407 * Discover and add a new shared-buffer link.
408 *
409 * In the following function, we are expecting to parse device tree entries
410 * looking like the following:
411 *
412 * hypervisor {
413 * ...
414 * interrupt-line@1d {
415 * compatible = "okl,microvisor-interrupt-line",
416 * "okl,microvisor-capability";
417 * phandle = <0x7>;
418 * reg = <0x1d>;
419 * label = "foo_virqline";
420 * };
421 * ;
422 *
423 * foo@41003000 {
424 * compatible = "okl,microvisor-link-shbuf",
425 * "okl,microvisor-shared-memory";
426 * phandle = <0xd>;
427 * reg = <0x0 0x41003000 0x2000>;
428 * label = "foo";
429 * okl,rwx = <0x6>;
430 * okl,interrupt-line = <0x7>;
431 * interrupts = <0x0 0x4 0x1>;
432 * interrupt-parent = <0x1>;
433 * };
434 */
435static int link_shbuf_probe(struct platform_device *pdev)
436{
437 int ret;
438 struct device_node *node, *virqline;
439 struct link_shbuf_data *priv;
440 const char *name;
441 u32 permissions;
442
443 node = pdev->dev.of_node;
444
445 if (!node)
446 return -ENODEV;
447
448 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
449 if (!priv)
450 return -ENOMEM;
451
452 /*
453 * Retrieve the outgoing vIRQ cap. Note, this is configurable and we
454 * anticipate that it may not exist.
455 */
456 virqline = of_parse_phandle(node, "okl,interrupt-line", 0);
457 if (!virqline) {
458 priv->virqline = NO_OUTGOING_IRQ;
459 } else {
460 ret = of_property_read_u32(virqline, "reg", &priv->virqline);
461 if (ret < 0 || priv->virqline == OKL4_KCAP_INVALID) {
462 of_node_put(virqline);
463 ret = -ENODEV;
464 goto err_free_dev;
465 }
466 }
467 of_node_put(virqline);
468
469 /* Retrieve the incoming vIRQ number. Again, this is configurable and we
470 * anticipate that it may not exist.
471 */
472 priv->virq = platform_get_irq(pdev, 0);
473 if (priv->virq < 0)
474 priv->virq = NO_INCOMING_IRQ;
475
476 /* If we have a valid incoming vIRQ, register to handle it. */
477 if (priv->virq >= 0) {
478 ret = devm_request_irq(&pdev->dev, priv->virq, link_shbuf_irq_handler,
479 0, dev_name(&pdev->dev), priv);
480 if (ret < 0) {
481 dev_err(&pdev->dev, "failed request for IRQ\n");
482 goto err_free_dev;
483 }
484 }
485
486 init_waitqueue_head(&priv->virq_wq);
487 priv->virq_pending = false;
488
489 /* Retrieve information about the shared memory region. */
490 ret = of_address_to_resource(node, 0, &priv->buffer);
491 if (ret < 0)
492 goto err_free_irq;
493 /*
494 * We expect the Elfweaver to have validated that we have a non-NULL,
495 * page-aligned region.
496 */
497 if (WARN_ON(priv->buffer.start == 0) ||
498 WARN_ON(resource_size(&priv->buffer) % PAGE_SIZE != 0))
499 goto err_free_irq;
500 if (!devm_request_mem_region(&pdev->dev, priv->buffer.start,
501 resource_size(&priv->buffer), dev_name(&pdev->dev))) {
502 ret = -ENODEV;
503 goto err_free_irq;
504 }
505 priv->base = devm_ioremap(&pdev->dev, priv->buffer.start,
506 resource_size(&priv->buffer));
507 if (!priv->base)
508 goto err_release_region;
509
510 /* Read the permissions of the shared memory region. */
511 ret = of_property_read_u32(node, "okl,rwx", &permissions);
512 if (ret < 0) {
513 dev_err(&pdev->dev, "failed to read shared memory permissions\n");
514 goto err_unmap_dev;
515 }
516 if (permissions & ~S_IRWXO) {
517 ret = -EINVAL;
518 goto err_unmap_dev;
519 }
520 priv->permissions = ((permissions & S_IROTH) ? FMODE_READ : 0) |
521 ((permissions & S_IWOTH) ? FMODE_WRITE : 0) |
522 ((permissions & S_IXOTH) ? FMODE_EXEC : 0);
523 if (WARN_ON(priv->permissions == 0)) {
524 ret = -EINVAL;
525 goto err_unmap_dev;
526 }
527
528 /* Retrieve the label of this device. This will be the "name" attribute of
529 * the corresponding "link" tag in the system's XML specification.
530 */
531 ret = of_property_read_string(node, "label", &name);
532 if (ret < 0) {
533 dev_err(&pdev->dev, "failed to read label\n");
534 goto err_unmap_dev;
535 }
536
537 cdev_init(&priv->cdev, &link_shbuf_ops);
538 ret = cdev_add(&priv->cdev, link_shbuf_dev, 1);
539 if (ret < 0) {
540 dev_err(&pdev->dev, "failed to add char dev region\n");
541 goto err_unmap_dev;
542 }
543
544 ret = link_shbuf_allocate_device(&priv->devt);
545 if (ret < 0) {
546 dev_err(&pdev->dev, "failed to allocate new device number\n");
547 goto err_unmap_dev;
548 }
549
550 /* We're now ready to create the device itself. */
551 BUG_ON(name == NULL);
552 priv->dev = device_create(link_shbuf_class, &pdev->dev, priv->devt,
553 priv, "%s%s", DEV_PREFIX, name);
554 if (IS_ERR(priv->dev)) {
555 dev_err(&pdev->dev, "failed to create device\n");
556 ret = PTR_ERR(priv->dev);
557 goto err_del_dev;
558 }
559
560 dev_set_drvdata(&pdev->dev, priv);
561
562 return 0;
563
564err_del_dev:
565 cdev_del(&priv->cdev);
566err_unmap_dev:
567 devm_iounmap(&pdev->dev, priv->base);
568err_release_region:
569 devm_release_mem_region(&pdev->dev, priv->buffer.start,
570 resource_size(&priv->buffer));
571err_free_irq:
572 if (priv->virq != NO_INCOMING_IRQ)
573 devm_free_irq(&pdev->dev, priv->virq, priv);
574err_free_dev:
575 devm_kfree(&pdev->dev, priv);
576 return ret;
577}
578
579static int link_shbuf_remove(struct platform_device *pdev)
580{
581 struct link_shbuf_data *priv;
582
583 priv = dev_get_drvdata(&pdev->dev);
584 WARN_ON(!link_shbuf_data_invariant(priv));
585
586 device_destroy(link_shbuf_class, priv->devt);
587
588 cdev_del(&priv->cdev);
589
590 /*
591 * None of the following is strictly required, as these are all managed
592 * resources, but we clean it up anyway for clarity.
593 */
594
595 devm_iounmap(&pdev->dev, priv->base);
596
597 devm_release_mem_region(&pdev->dev, priv->buffer.start,
598 resource_size(&priv->buffer));
599
600 if (priv->virq != NO_INCOMING_IRQ)
601 devm_free_irq(&pdev->dev, priv->virq, priv);
602
603 devm_kfree(&pdev->dev, priv);
604
605 return 0;
606}
607
608static struct platform_driver of_plat_link_shbuf_driver = {
609 .driver = {
610 .name = "okl4-shbuf",
611 .owner = THIS_MODULE,
612 .of_match_table = okl4_link_shbuf_match,
613 },
614 .probe = link_shbuf_probe,
615 .remove = link_shbuf_remove,
616};
617
618/* Maximum number of minor device numbers */
619enum {
620 MAX_MINOR = 1 << MINORBITS,
621};
622
623static int __init okl4_link_shbuf_init(void)
624{
625 int ret;
626
627 link_shbuf_class = class_create(THIS_MODULE, DEVICE_NAME);
628 if (IS_ERR(link_shbuf_class)) {
629 pr_err("failed to create class\n");
630 ret = PTR_ERR(link_shbuf_class);
631 return ret;
632 }
633
634 ret = alloc_chrdev_region(&link_shbuf_dev, 0, MAX_MINOR, DEVICE_NAME);
635 if (ret < 0) {
636 pr_err("failed to allocate char dev region\n");
637 goto err_destroy_class;
638 }
639
640 ret = platform_driver_register(&of_plat_link_shbuf_driver);
641 if (ret < 0) {
642 pr_err("failed to register driver\n");
643 goto err_unregister_dev_region;
644 }
645
646 spin_lock_init(&device_number_allocate);
647
648 return 0;
649
650err_unregister_dev_region:
651 unregister_chrdev_region(link_shbuf_dev, MAX_MINOR);
652err_destroy_class:
653 class_destroy(link_shbuf_class);
654 return ret;
655}
656module_init(okl4_link_shbuf_init);
657
658static void __exit okl4_link_shbuf_exit(void)
659{
660 platform_driver_unregister(&of_plat_link_shbuf_driver);
661 unregister_chrdev_region(link_shbuf_dev, MAX_MINOR);
662 class_destroy(link_shbuf_class);
663}
664module_exit(okl4_link_shbuf_exit);
665
666MODULE_DESCRIPTION("OKL4 shared buffer link driver");
667MODULE_AUTHOR("Cog Systems Pty Ltd");