Commit | Line | Data |
---|---|---|
12e364b9 KC |
1 | /* file.c |
2 | * | |
f6d0c1e6 | 3 | * Copyright (C) 2010 - 2013 UNISYS CORPORATION |
12e364b9 KC |
4 | * All rights reserved. |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or (at | |
9 | * your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
14 | * NON INFRINGEMENT. See the GNU General Public License for more | |
15 | * details. | |
16 | */ | |
17 | ||
18 | /* This contains the implementation that allows a usermode program to | |
19 | * communicate with the visorchipset driver using a device/file interface. | |
20 | */ | |
21 | ||
22 | #include "globals.h" | |
23 | #include "visorchannel.h" | |
24 | #include <linux/mm.h> | |
25 | #include <linux/fs.h> | |
26 | #include "uisutils.h" | |
bd5b9b32 | 27 | #include "file.h" |
12e364b9 KC |
28 | |
29 | #define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c | |
30 | ||
e8fe1ef1 | 31 | static struct cdev file_cdev; |
383df64e | 32 | static struct visorchannel **file_controlvm_channel; |
12e364b9 KC |
33 | |
34 | static int visorchipset_open(struct inode *inode, struct file *file); | |
35 | static int visorchipset_release(struct inode *inode, struct file *file); | |
36 | static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma); | |
cee158b5 FC |
37 | static long visorchipset_ioctl(struct file *file, unsigned int cmd, |
38 | unsigned long arg); | |
12e364b9 KC |
39 | |
40 | static const struct file_operations visorchipset_fops = { | |
41 | .owner = THIS_MODULE, | |
42 | .open = visorchipset_open, | |
43 | .read = NULL, | |
44 | .write = NULL, | |
12e364b9 | 45 | .unlocked_ioctl = visorchipset_ioctl, |
12e364b9 KC |
46 | .release = visorchipset_release, |
47 | .mmap = visorchipset_mmap, | |
48 | }; | |
49 | ||
383df64e BT |
50 | int |
51 | visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel) | |
12e364b9 | 52 | { |
73813128 | 53 | int rc = 0; |
12e364b9 | 54 | |
e8fe1ef1 | 55 | file_controlvm_channel = controlvm_channel; |
e8fe1ef1 BR |
56 | cdev_init(&file_cdev, &visorchipset_fops); |
57 | file_cdev.owner = THIS_MODULE; | |
a1191146 | 58 | if (MAJOR(major_dev) == 0) { |
2e71c9e4 | 59 | rc = alloc_chrdev_region(&major_dev, 0, 1, MYDRVNAME); |
12e364b9 | 60 | /* dynamic major device number registration required */ |
2e71c9e4 SM |
61 | if (rc < 0) |
62 | return rc; | |
12e364b9 KC |
63 | } else { |
64 | /* static major device number registration required */ | |
2e71c9e4 SM |
65 | rc = register_chrdev_region(major_dev, 1, MYDRVNAME); |
66 | if (rc < 0) | |
67 | return rc; | |
12e364b9 | 68 | } |
a1191146 | 69 | rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1); |
6bdb6101 SM |
70 | if (rc < 0) { |
71 | unregister_chrdev_region(major_dev, 1); | |
2e71c9e4 | 72 | return rc; |
6bdb6101 | 73 | } |
73813128 | 74 | return 0; |
12e364b9 KC |
75 | } |
76 | ||
77 | void | |
addceb12 | 78 | visorchipset_file_cleanup(dev_t major_dev) |
12e364b9 | 79 | { |
e8fe1ef1 BR |
80 | if (file_cdev.ops != NULL) |
81 | cdev_del(&file_cdev); | |
82 | file_cdev.ops = NULL; | |
8b82fa83 | 83 | unregister_chrdev_region(major_dev, 1); |
12e364b9 KC |
84 | } |
85 | ||
86 | static int | |
87 | visorchipset_open(struct inode *inode, struct file *file) | |
88 | { | |
89 | unsigned minor_number = iminor(inode); | |
12e364b9 | 90 | |
12e364b9 | 91 | if (minor_number != 0) |
11f8ac08 | 92 | return -ENODEV; |
12e364b9 | 93 | file->private_data = NULL; |
11f8ac08 | 94 | return 0; |
12e364b9 KC |
95 | } |
96 | ||
97 | static int | |
98 | visorchipset_release(struct inode *inode, struct file *file) | |
99 | { | |
22ad57ba | 100 | return 0; |
12e364b9 KC |
101 | } |
102 | ||
103 | static int | |
104 | visorchipset_mmap(struct file *file, struct vm_area_struct *vma) | |
105 | { | |
cc5ff7f5 | 106 | ulong physaddr = 0; |
12e364b9 KC |
107 | ulong offset = vma->vm_pgoff << PAGE_SHIFT; |
108 | GUEST_PHYSICAL_ADDRESS addr = 0; | |
109 | ||
110 | /* sv_enable_dfp(); */ | |
0aca7844 | 111 | if (offset & (PAGE_SIZE - 1)) |
12e364b9 | 112 | return -ENXIO; /* need aligned offsets */ |
0aca7844 | 113 | |
12e364b9 KC |
114 | switch (offset) { |
115 | case VISORCHIPSET_MMAP_CONTROLCHANOFFSET: | |
116 | vma->vm_flags |= VM_IO; | |
e8fe1ef1 | 117 | if (*file_controlvm_channel == NULL) { |
12e364b9 KC |
118 | return -ENXIO; |
119 | } | |
e8fe1ef1 | 120 | visorchannel_read(*file_controlvm_channel, |
d19642f6 BR |
121 | offsetof(struct spar_controlvm_channel_protocol, |
122 | gp_control_channel), | |
123 | &addr, sizeof(addr)); | |
12e364b9 | 124 | if (addr == 0) { |
12e364b9 KC |
125 | return -ENXIO; |
126 | } | |
cc5ff7f5 | 127 | physaddr = (ulong)addr; |
12e364b9 | 128 | if (remap_pfn_range(vma, vma->vm_start, |
cc5ff7f5 | 129 | physaddr >> PAGE_SHIFT, |
12e364b9 KC |
130 | vma->vm_end - vma->vm_start, |
131 | /*pgprot_noncached */ | |
132 | (vma->vm_page_prot))) { | |
12e364b9 KC |
133 | return -EAGAIN; |
134 | } | |
135 | break; | |
136 | default: | |
137 | return -ENOSYS; | |
138 | } | |
12e364b9 KC |
139 | return 0; |
140 | } | |
141 | ||
cee158b5 FC |
142 | static long visorchipset_ioctl(struct file *file, unsigned int cmd, |
143 | unsigned long arg) | |
12e364b9 | 144 | { |
ec03a7db BR |
145 | s64 adjustment; |
146 | s64 vrtc_offset; | |
5a72afb9 | 147 | |
12e364b9 KC |
148 | switch (cmd) { |
149 | case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET: | |
150 | /* get the physical rtc offset */ | |
e76446ea | 151 | vrtc_offset = issue_vmcall_query_guest_virtual_time_offset(); |
12e364b9 | 152 | if (copy_to_user |
22ad57ba | 153 | ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) { |
2ce6cbb6 | 154 | return -EFAULT; |
22ad57ba | 155 | } |
2ce6cbb6 | 156 | return SUCCESS; |
12e364b9 KC |
157 | case VMCALL_UPDATE_PHYSICAL_TIME: |
158 | if (copy_from_user | |
22ad57ba | 159 | (&adjustment, (void __user *)arg, sizeof(adjustment))) { |
2ce6cbb6 | 160 | return -EFAULT; |
22ad57ba | 161 | } |
2ce6cbb6 | 162 | return issue_vmcall_update_physical_time(adjustment); |
12e364b9 | 163 | default: |
2ce6cbb6 | 164 | return -EFAULT; |
12e364b9 | 165 | } |
12e364b9 | 166 | } |