This source file includes following definitions.
- ioctl_restart
- ioctl_status
- ioctl_start
- ioctl_stop
- ioctl_memcpy
- ioctl_doorbell
- ioctl_dtprop
- fsl_hv_ioctl
- fsl_hv_queue_doorbell
- fsl_hv_isr
- fsl_hv_state_change_thread
- fsl_hv_state_change_isr
- fsl_hv_poll
- fsl_hv_read
- fsl_hv_open
- fsl_hv_close
- fsl_hv_shutdown_isr
- get_parent_handle
- fsl_hv_failover_register
- fsl_hv_failover_unregister
- has_fsl_hypervisor
- fsl_hypervisor_init
- fsl_hypervisor_exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/types.h>
29 #include <linux/err.h>
30 #include <linux/fs.h>
31 #include <linux/miscdevice.h>
32 #include <linux/mm.h>
33 #include <linux/pagemap.h>
34 #include <linux/slab.h>
35 #include <linux/poll.h>
36 #include <linux/of.h>
37 #include <linux/of_irq.h>
38 #include <linux/reboot.h>
39 #include <linux/uaccess.h>
40 #include <linux/notifier.h>
41 #include <linux/interrupt.h>
42
43 #include <linux/io.h>
44 #include <asm/fsl_hcalls.h>
45
46 #include <linux/fsl_hypervisor.h>
47
48 static BLOCKING_NOTIFIER_HEAD(failover_subscribers);
49
50
51
52
53
54
55 static long ioctl_restart(struct fsl_hv_ioctl_restart __user *p)
56 {
57 struct fsl_hv_ioctl_restart param;
58
59
60 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_restart)))
61 return -EFAULT;
62
63 param.ret = fh_partition_restart(param.partition);
64
65 if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
66 return -EFAULT;
67
68 return 0;
69 }
70
71
72
73
74
75
76 static long ioctl_status(struct fsl_hv_ioctl_status __user *p)
77 {
78 struct fsl_hv_ioctl_status param;
79 u32 status;
80
81
82 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_status)))
83 return -EFAULT;
84
85 param.ret = fh_partition_get_status(param.partition, &status);
86 if (!param.ret)
87 param.status = status;
88
89 if (copy_to_user(p, ¶m, sizeof(struct fsl_hv_ioctl_status)))
90 return -EFAULT;
91
92 return 0;
93 }
94
95
96
97
98
99
100 static long ioctl_start(struct fsl_hv_ioctl_start __user *p)
101 {
102 struct fsl_hv_ioctl_start param;
103
104
105 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_start)))
106 return -EFAULT;
107
108 param.ret = fh_partition_start(param.partition, param.entry_point,
109 param.load);
110
111 if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
112 return -EFAULT;
113
114 return 0;
115 }
116
117
118
119
120
121
122 static long ioctl_stop(struct fsl_hv_ioctl_stop __user *p)
123 {
124 struct fsl_hv_ioctl_stop param;
125
126
127 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_stop)))
128 return -EFAULT;
129
130 param.ret = fh_partition_stop(param.partition);
131
132 if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
133 return -EFAULT;
134
135 return 0;
136 }
137
138
139
140
141
142
143
144
145
146
147 static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
148 {
149 struct fsl_hv_ioctl_memcpy param;
150
151 struct page **pages = NULL;
152 void *sg_list_unaligned = NULL;
153 struct fh_sg_list *sg_list = NULL;
154
155 unsigned int num_pages;
156 unsigned long lb_offset;
157
158 unsigned int i;
159 long ret = 0;
160 int num_pinned;
161 phys_addr_t remote_paddr;
162 uint32_t count;
163
164
165 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_memcpy)))
166 return -EFAULT;
167
168
169
170
171
172
173 if ((param.source == -1) == (param.target == -1))
174 return -EINVAL;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 lb_offset = param.local_vaddr & (PAGE_SIZE - 1);
218 if (param.count == 0 ||
219 param.count > U64_MAX - lb_offset - PAGE_SIZE + 1)
220 return -EINVAL;
221 num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
222
223
224
225
226
227
228
229 pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
230 if (!pages) {
231 pr_debug("fsl-hv: could not allocate page list\n");
232 return -ENOMEM;
233 }
234
235
236
237
238
239 sg_list_unaligned = kmalloc(num_pages * sizeof(struct fh_sg_list) +
240 sizeof(struct fh_sg_list) - 1, GFP_KERNEL);
241 if (!sg_list_unaligned) {
242 pr_debug("fsl-hv: could not allocate S/G list\n");
243 ret = -ENOMEM;
244 goto exit;
245 }
246 sg_list = PTR_ALIGN(sg_list_unaligned, sizeof(struct fh_sg_list));
247
248
249 num_pinned = get_user_pages_fast(param.local_vaddr - lb_offset,
250 num_pages, param.source != -1 ? FOLL_WRITE : 0, pages);
251
252 if (num_pinned != num_pages) {
253
254 pr_debug("fsl-hv: could not lock source buffer\n");
255 ret = (num_pinned < 0) ? num_pinned : -EFAULT;
256 goto exit;
257 }
258
259
260
261
262
263 if (param.source == -1) {
264 sg_list[0].source = page_to_phys(pages[0]) + lb_offset;
265 sg_list[0].target = param.remote_paddr;
266 } else {
267 sg_list[0].source = param.remote_paddr;
268 sg_list[0].target = page_to_phys(pages[0]) + lb_offset;
269 }
270 sg_list[0].size = min_t(uint64_t, param.count, PAGE_SIZE - lb_offset);
271
272 remote_paddr = param.remote_paddr + sg_list[0].size;
273 count = param.count - sg_list[0].size;
274
275 for (i = 1; i < num_pages; i++) {
276 if (param.source == -1) {
277
278 sg_list[i].source = page_to_phys(pages[i]);
279 sg_list[i].target = remote_paddr;
280 } else {
281
282 sg_list[i].source = remote_paddr;
283 sg_list[i].target = page_to_phys(pages[i]);
284 }
285 sg_list[i].size = min_t(uint64_t, count, PAGE_SIZE);
286
287 remote_paddr += sg_list[i].size;
288 count -= sg_list[i].size;
289 }
290
291 param.ret = fh_partition_memcpy(param.source, param.target,
292 virt_to_phys(sg_list), num_pages);
293
294 exit:
295 if (pages) {
296 for (i = 0; i < num_pages; i++)
297 if (pages[i])
298 put_page(pages[i]);
299 }
300
301 kfree(sg_list_unaligned);
302 kfree(pages);
303
304 if (!ret)
305 if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
306 return -EFAULT;
307
308 return ret;
309 }
310
311
312
313
314
315
316 static long ioctl_doorbell(struct fsl_hv_ioctl_doorbell __user *p)
317 {
318 struct fsl_hv_ioctl_doorbell param;
319
320
321 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_doorbell)))
322 return -EFAULT;
323
324 param.ret = ev_doorbell_send(param.doorbell);
325
326 if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
327 return -EFAULT;
328
329 return 0;
330 }
331
332 static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
333 {
334 struct fsl_hv_ioctl_prop param;
335 char __user *upath, *upropname;
336 void __user *upropval;
337 char *path, *propname;
338 void *propval;
339 int ret = 0;
340
341
342 if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_prop)))
343 return -EFAULT;
344
345 upath = (char __user *)(uintptr_t)param.path;
346 upropname = (char __user *)(uintptr_t)param.propname;
347 upropval = (void __user *)(uintptr_t)param.propval;
348
349 path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN);
350 if (IS_ERR(path))
351 return PTR_ERR(path);
352
353 propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN);
354 if (IS_ERR(propname)) {
355 ret = PTR_ERR(propname);
356 goto err_free_path;
357 }
358
359 if (param.proplen > FH_DTPROP_MAX_PROPLEN) {
360 ret = -EINVAL;
361 goto err_free_propname;
362 }
363
364 propval = kmalloc(param.proplen, GFP_KERNEL);
365 if (!propval) {
366 ret = -ENOMEM;
367 goto err_free_propname;
368 }
369
370 if (set) {
371 if (copy_from_user(propval, upropval, param.proplen)) {
372 ret = -EFAULT;
373 goto err_free_propval;
374 }
375
376 param.ret = fh_partition_set_dtprop(param.handle,
377 virt_to_phys(path),
378 virt_to_phys(propname),
379 virt_to_phys(propval),
380 param.proplen);
381 } else {
382 param.ret = fh_partition_get_dtprop(param.handle,
383 virt_to_phys(path),
384 virt_to_phys(propname),
385 virt_to_phys(propval),
386 ¶m.proplen);
387
388 if (param.ret == 0) {
389 if (copy_to_user(upropval, propval, param.proplen) ||
390 put_user(param.proplen, &p->proplen)) {
391 ret = -EFAULT;
392 goto err_free_propval;
393 }
394 }
395 }
396
397 if (put_user(param.ret, &p->ret))
398 ret = -EFAULT;
399
400 err_free_propval:
401 kfree(propval);
402 err_free_propname:
403 kfree(propname);
404 err_free_path:
405 kfree(path);
406
407 return ret;
408 }
409
410
411
412
413 static long fsl_hv_ioctl(struct file *file, unsigned int cmd,
414 unsigned long argaddr)
415 {
416 void __user *arg = (void __user *)argaddr;
417 long ret;
418
419 switch (cmd) {
420 case FSL_HV_IOCTL_PARTITION_RESTART:
421 ret = ioctl_restart(arg);
422 break;
423 case FSL_HV_IOCTL_PARTITION_GET_STATUS:
424 ret = ioctl_status(arg);
425 break;
426 case FSL_HV_IOCTL_PARTITION_START:
427 ret = ioctl_start(arg);
428 break;
429 case FSL_HV_IOCTL_PARTITION_STOP:
430 ret = ioctl_stop(arg);
431 break;
432 case FSL_HV_IOCTL_MEMCPY:
433 ret = ioctl_memcpy(arg);
434 break;
435 case FSL_HV_IOCTL_DOORBELL:
436 ret = ioctl_doorbell(arg);
437 break;
438 case FSL_HV_IOCTL_GETPROP:
439 ret = ioctl_dtprop(arg, 0);
440 break;
441 case FSL_HV_IOCTL_SETPROP:
442 ret = ioctl_dtprop(arg, 1);
443 break;
444 default:
445 pr_debug("fsl-hv: bad ioctl dir=%u type=%u cmd=%u size=%u\n",
446 _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd),
447 _IOC_SIZE(cmd));
448 return -ENOTTY;
449 }
450
451 return ret;
452 }
453
454
455 static struct list_head db_list;
456
457
458 static DEFINE_SPINLOCK(db_list_lock);
459
460
461 #define QSIZE 16
462
463
464 #define nextp(x) (((x) + 1) & (QSIZE - 1))
465
466
467 struct doorbell_queue {
468 struct list_head list;
469 spinlock_t lock;
470 wait_queue_head_t wait;
471 unsigned int head;
472 unsigned int tail;
473 uint32_t q[QSIZE];
474 };
475
476
477 struct list_head isr_list;
478
479
480 struct doorbell_isr {
481 struct list_head list;
482 unsigned int irq;
483 uint32_t doorbell;
484 uint32_t partition;
485 };
486
487
488
489
490 static void fsl_hv_queue_doorbell(uint32_t doorbell)
491 {
492 struct doorbell_queue *dbq;
493 unsigned long flags;
494
495
496 spin_lock_irqsave(&db_list_lock, flags);
497
498 list_for_each_entry(dbq, &db_list, list) {
499 if (dbq->head != nextp(dbq->tail)) {
500 dbq->q[dbq->tail] = doorbell;
501
502
503
504
505 smp_wmb();
506 dbq->tail = nextp(dbq->tail);
507 wake_up_interruptible(&dbq->wait);
508 }
509 }
510
511 spin_unlock_irqrestore(&db_list_lock, flags);
512 }
513
514
515
516
517
518
519
520
521 static irqreturn_t fsl_hv_isr(int irq, void *data)
522 {
523 fsl_hv_queue_doorbell((uintptr_t) data);
524
525 return IRQ_HANDLED;
526 }
527
528
529
530
531
532
533
534
535
536
537
538 static irqreturn_t fsl_hv_state_change_thread(int irq, void *data)
539 {
540 struct doorbell_isr *dbisr = data;
541
542 blocking_notifier_call_chain(&failover_subscribers, dbisr->partition,
543 NULL);
544
545 return IRQ_HANDLED;
546 }
547
548
549
550
551 static irqreturn_t fsl_hv_state_change_isr(int irq, void *data)
552 {
553 unsigned int status;
554 struct doorbell_isr *dbisr = data;
555 int ret;
556
557
558 fsl_hv_queue_doorbell(dbisr->doorbell);
559
560
561 ret = fh_partition_get_status(dbisr->partition, &status);
562 if (!ret && (status == FH_PARTITION_STOPPED))
563 return IRQ_WAKE_THREAD;
564
565 return IRQ_HANDLED;
566 }
567
568
569
570
571 static __poll_t fsl_hv_poll(struct file *filp, struct poll_table_struct *p)
572 {
573 struct doorbell_queue *dbq = filp->private_data;
574 unsigned long flags;
575 __poll_t mask;
576
577 spin_lock_irqsave(&dbq->lock, flags);
578
579 poll_wait(filp, &dbq->wait, p);
580 mask = (dbq->head == dbq->tail) ? 0 : (EPOLLIN | EPOLLRDNORM);
581
582 spin_unlock_irqrestore(&dbq->lock, flags);
583
584 return mask;
585 }
586
587
588
589
590
591
592
593
594 static ssize_t fsl_hv_read(struct file *filp, char __user *buf, size_t len,
595 loff_t *off)
596 {
597 struct doorbell_queue *dbq = filp->private_data;
598 uint32_t __user *p = (uint32_t __user *) buf;
599 unsigned long flags;
600 ssize_t count = 0;
601
602
603 while (len >= sizeof(uint32_t)) {
604 uint32_t dbell;
605
606 spin_lock_irqsave(&dbq->lock, flags);
607
608
609
610
611
612
613 if (dbq->head == dbq->tail) {
614 spin_unlock_irqrestore(&dbq->lock, flags);
615 if (count)
616 break;
617 if (filp->f_flags & O_NONBLOCK)
618 return -EAGAIN;
619 if (wait_event_interruptible(dbq->wait,
620 dbq->head != dbq->tail))
621 return -ERESTARTSYS;
622 continue;
623 }
624
625
626
627
628
629
630
631
632
633 smp_rmb();
634
635
636
637
638 dbell = dbq->q[dbq->head];
639 dbq->head = nextp(dbq->head);
640
641 spin_unlock_irqrestore(&dbq->lock, flags);
642
643 if (put_user(dbell, p))
644 return -EFAULT;
645 p++;
646 count += sizeof(uint32_t);
647 len -= sizeof(uint32_t);
648 }
649
650 return count;
651 }
652
653
654
655
656
657
658
659 static int fsl_hv_open(struct inode *inode, struct file *filp)
660 {
661 struct doorbell_queue *dbq;
662 unsigned long flags;
663 int ret = 0;
664
665 dbq = kzalloc(sizeof(struct doorbell_queue), GFP_KERNEL);
666 if (!dbq) {
667 pr_err("fsl-hv: out of memory\n");
668 return -ENOMEM;
669 }
670
671 spin_lock_init(&dbq->lock);
672 init_waitqueue_head(&dbq->wait);
673
674 spin_lock_irqsave(&db_list_lock, flags);
675 list_add(&dbq->list, &db_list);
676 spin_unlock_irqrestore(&db_list_lock, flags);
677
678 filp->private_data = dbq;
679
680 return ret;
681 }
682
683
684
685
686 static int fsl_hv_close(struct inode *inode, struct file *filp)
687 {
688 struct doorbell_queue *dbq = filp->private_data;
689 unsigned long flags;
690
691 int ret = 0;
692
693 spin_lock_irqsave(&db_list_lock, flags);
694 list_del(&dbq->list);
695 spin_unlock_irqrestore(&db_list_lock, flags);
696
697 kfree(dbq);
698
699 return ret;
700 }
701
702 static const struct file_operations fsl_hv_fops = {
703 .owner = THIS_MODULE,
704 .open = fsl_hv_open,
705 .release = fsl_hv_close,
706 .poll = fsl_hv_poll,
707 .read = fsl_hv_read,
708 .unlocked_ioctl = fsl_hv_ioctl,
709 .compat_ioctl = fsl_hv_ioctl,
710 };
711
712 static struct miscdevice fsl_hv_misc_dev = {
713 MISC_DYNAMIC_MINOR,
714 "fsl-hv",
715 &fsl_hv_fops
716 };
717
718 static irqreturn_t fsl_hv_shutdown_isr(int irq, void *data)
719 {
720 orderly_poweroff(false);
721
722 return IRQ_HANDLED;
723 }
724
725
726
727
728
729
730 static int get_parent_handle(struct device_node *np)
731 {
732 struct device_node *parent;
733 const uint32_t *prop;
734 uint32_t handle;
735 int len;
736
737 parent = of_get_parent(np);
738 if (!parent)
739
740 return -ENODEV;
741
742
743
744
745
746 prop = of_get_property(parent, "hv-handle", &len);
747 if (!prop)
748 prop = of_get_property(parent, "reg", &len);
749
750 if (!prop || (len != sizeof(uint32_t))) {
751
752 of_node_put(parent);
753 return -ENODEV;
754 }
755
756 handle = be32_to_cpup(prop);
757 of_node_put(parent);
758
759 return handle;
760 }
761
762
763
764
765
766
767
768 int fsl_hv_failover_register(struct notifier_block *nb)
769 {
770 return blocking_notifier_chain_register(&failover_subscribers, nb);
771 }
772 EXPORT_SYMBOL(fsl_hv_failover_register);
773
774
775
776
777 int fsl_hv_failover_unregister(struct notifier_block *nb)
778 {
779 return blocking_notifier_chain_unregister(&failover_subscribers, nb);
780 }
781 EXPORT_SYMBOL(fsl_hv_failover_unregister);
782
783
784
785
786
787
788
789
790
791
792
793
794 static int has_fsl_hypervisor(void)
795 {
796 struct device_node *node;
797 int ret;
798
799 node = of_find_node_by_path("/hypervisor");
800 if (!node)
801 return 0;
802
803 ret = of_find_property(node, "fsl,hv-version", NULL) != NULL;
804
805 of_node_put(node);
806
807 return ret;
808 }
809
810
811
812
813
814
815
816
817
818 static int __init fsl_hypervisor_init(void)
819 {
820 struct device_node *np;
821 struct doorbell_isr *dbisr, *n;
822 int ret;
823
824 pr_info("Freescale hypervisor management driver\n");
825
826 if (!has_fsl_hypervisor()) {
827 pr_info("fsl-hv: no hypervisor found\n");
828 return -ENODEV;
829 }
830
831 ret = misc_register(&fsl_hv_misc_dev);
832 if (ret) {
833 pr_err("fsl-hv: cannot register device\n");
834 return ret;
835 }
836
837 INIT_LIST_HEAD(&db_list);
838 INIT_LIST_HEAD(&isr_list);
839
840 for_each_compatible_node(np, NULL, "epapr,hv-receive-doorbell") {
841 unsigned int irq;
842 const uint32_t *handle;
843
844 handle = of_get_property(np, "interrupts", NULL);
845 irq = irq_of_parse_and_map(np, 0);
846 if (!handle || (irq == NO_IRQ)) {
847 pr_err("fsl-hv: no 'interrupts' property in %pOF node\n",
848 np);
849 continue;
850 }
851
852 dbisr = kzalloc(sizeof(*dbisr), GFP_KERNEL);
853 if (!dbisr)
854 goto out_of_memory;
855
856 dbisr->irq = irq;
857 dbisr->doorbell = be32_to_cpup(handle);
858
859 if (of_device_is_compatible(np, "fsl,hv-shutdown-doorbell")) {
860
861 ret = request_irq(irq, fsl_hv_shutdown_isr, 0,
862 np->name, NULL);
863 } else if (of_device_is_compatible(np,
864 "fsl,hv-state-change-doorbell")) {
865
866
867
868
869
870
871
872
873 dbisr->partition = ret = get_parent_handle(np);
874 if (ret < 0) {
875 pr_err("fsl-hv: node %pOF has missing or "
876 "malformed parent\n", np);
877 kfree(dbisr);
878 continue;
879 }
880 ret = request_threaded_irq(irq, fsl_hv_state_change_isr,
881 fsl_hv_state_change_thread,
882 0, np->name, dbisr);
883 } else
884 ret = request_irq(irq, fsl_hv_isr, 0, np->name, dbisr);
885
886 if (ret < 0) {
887 pr_err("fsl-hv: could not request irq %u for node %pOF\n",
888 irq, np);
889 kfree(dbisr);
890 continue;
891 }
892
893 list_add(&dbisr->list, &isr_list);
894
895 pr_info("fsl-hv: registered handler for doorbell %u\n",
896 dbisr->doorbell);
897 }
898
899 return 0;
900
901 out_of_memory:
902 list_for_each_entry_safe(dbisr, n, &isr_list, list) {
903 free_irq(dbisr->irq, dbisr);
904 list_del(&dbisr->list);
905 kfree(dbisr);
906 }
907
908 misc_deregister(&fsl_hv_misc_dev);
909
910 return -ENOMEM;
911 }
912
913
914
915
916
917
918 static void __exit fsl_hypervisor_exit(void)
919 {
920 struct doorbell_isr *dbisr, *n;
921
922 list_for_each_entry_safe(dbisr, n, &isr_list, list) {
923 free_irq(dbisr->irq, dbisr);
924 list_del(&dbisr->list);
925 kfree(dbisr);
926 }
927
928 misc_deregister(&fsl_hv_misc_dev);
929 }
930
931 module_init(fsl_hypervisor_init);
932 module_exit(fsl_hypervisor_exit);
933
934 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
935 MODULE_DESCRIPTION("Freescale hypervisor management driver");
936 MODULE_LICENSE("GPL v2");