Merge 3.12-rc3 into char-misc-next
[deliverable/linux.git] / drivers / misc / mic / host / mic_fops.c
1 /*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
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, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC Host driver.
19 *
20 */
21 #include <linux/poll.h>
22
23 #include <linux/mic_common.h>
24 #include "../common/mic_dev.h"
25 #include "mic_device.h"
26 #include "mic_fops.h"
27 #include "mic_virtio.h"
28
29 int mic_open(struct inode *inode, struct file *f)
30 {
31 struct mic_vdev *mvdev;
32 struct mic_device *mdev = container_of(inode->i_cdev,
33 struct mic_device, cdev);
34
35 mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL);
36 if (!mvdev)
37 return -ENOMEM;
38
39 init_waitqueue_head(&mvdev->waitq);
40 INIT_LIST_HEAD(&mvdev->list);
41 mvdev->mdev = mdev;
42 mvdev->virtio_id = -1;
43
44 f->private_data = mvdev;
45 return 0;
46 }
47
48 int mic_release(struct inode *inode, struct file *f)
49 {
50 struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
51
52 if (-1 != mvdev->virtio_id)
53 mic_virtio_del_device(mvdev);
54 f->private_data = NULL;
55 kfree(mvdev);
56 return 0;
57 }
58
59 long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
60 {
61 struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
62 void __user *argp = (void __user *)arg;
63 int ret;
64
65 switch (cmd) {
66 case MIC_VIRTIO_ADD_DEVICE:
67 {
68 ret = mic_virtio_add_device(mvdev, argp);
69 if (ret < 0) {
70 dev_err(mic_dev(mvdev),
71 "%s %d errno ret %d\n",
72 __func__, __LINE__, ret);
73 return ret;
74 }
75 break;
76 }
77 case MIC_VIRTIO_COPY_DESC:
78 {
79 struct mic_copy_desc copy;
80
81 ret = mic_vdev_inited(mvdev);
82 if (ret)
83 return ret;
84
85 if (copy_from_user(&copy, argp, sizeof(copy)))
86 return -EFAULT;
87
88 dev_dbg(mic_dev(mvdev),
89 "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n",
90 __func__, __LINE__, copy.iovcnt, copy.vr_idx,
91 copy.update_used);
92
93 ret = mic_virtio_copy_desc(mvdev, &copy);
94 if (ret < 0) {
95 dev_err(mic_dev(mvdev),
96 "%s %d errno ret %d\n",
97 __func__, __LINE__, ret);
98 return ret;
99 }
100 if (copy_to_user(
101 &((struct mic_copy_desc __user *)argp)->out_len,
102 &copy.out_len, sizeof(copy.out_len))) {
103 dev_err(mic_dev(mvdev), "%s %d errno ret %d\n",
104 __func__, __LINE__, -EFAULT);
105 return -EFAULT;
106 }
107 break;
108 }
109 case MIC_VIRTIO_CONFIG_CHANGE:
110 {
111 ret = mic_vdev_inited(mvdev);
112 if (ret)
113 return ret;
114
115 ret = mic_virtio_config_change(mvdev, argp);
116 if (ret < 0) {
117 dev_err(mic_dev(mvdev),
118 "%s %d errno ret %d\n",
119 __func__, __LINE__, ret);
120 return ret;
121 }
122 break;
123 }
124 default:
125 return -ENOIOCTLCMD;
126 };
127 return 0;
128 }
129
130 /*
131 * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and
132 * not when previously enqueued buffers may be available. This means that
133 * in the card->host (TX) path, when userspace is unblocked by poll it
134 * must drain all available descriptors or it can stall.
135 */
136 unsigned int mic_poll(struct file *f, poll_table *wait)
137 {
138 struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
139 int mask = 0;
140
141 poll_wait(f, &mvdev->waitq, wait);
142
143 if (mic_vdev_inited(mvdev)) {
144 mask = POLLERR;
145 } else if (mvdev->poll_wake) {
146 mvdev->poll_wake = 0;
147 mask = POLLIN | POLLOUT;
148 }
149
150 return mask;
151 }
152
153 static inline int
154 mic_query_offset(struct mic_vdev *mvdev, unsigned long offset,
155 unsigned long *size, unsigned long *pa)
156 {
157 struct mic_device *mdev = mvdev->mdev;
158 unsigned long start = MIC_DP_SIZE;
159 int i;
160
161 /*
162 * MMAP interface is as follows:
163 * offset region
164 * 0x0 virtio device_page
165 * 0x1000 first vring
166 * 0x1000 + size of 1st vring second vring
167 * ....
168 */
169 if (!offset) {
170 *pa = virt_to_phys(mdev->dp);
171 *size = MIC_DP_SIZE;
172 return 0;
173 }
174
175 for (i = 0; i < mvdev->dd->num_vq; i++) {
176 struct mic_vringh *mvr = &mvdev->mvr[i];
177 if (offset == start) {
178 *pa = virt_to_phys(mvr->vring.va);
179 *size = mvr->vring.len;
180 return 0;
181 }
182 start += mvr->vring.len;
183 }
184 return -1;
185 }
186
187 /*
188 * Maps the device page and virtio rings to user space for readonly access.
189 */
190 int
191 mic_mmap(struct file *f, struct vm_area_struct *vma)
192 {
193 struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data;
194 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
195 unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size;
196 int i, err;
197
198 err = mic_vdev_inited(mvdev);
199 if (err)
200 return err;
201
202 if (vma->vm_flags & VM_WRITE)
203 return -EACCES;
204
205 while (size_rem) {
206 i = mic_query_offset(mvdev, offset, &size, &pa);
207 if (i < 0)
208 return -EINVAL;
209 err = remap_pfn_range(vma, vma->vm_start + offset,
210 pa >> PAGE_SHIFT, size, vma->vm_page_prot);
211 if (err)
212 return err;
213 dev_dbg(mic_dev(mvdev),
214 "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n",
215 __func__, __LINE__, mvdev->virtio_id, size, offset,
216 pa, vma->vm_start + offset);
217 size_rem -= size;
218 offset += size;
219 }
220 return 0;
221 }
This page took 0.040804 seconds and 5 git commands to generate.