Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / micscif / micscif_fd.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36#include "mic/micscif.h"
37
38struct mic_priv {
39 scif_epd_t epd;
40};
41
42
43int
44scif_fdopen(struct file *f)
45{
46 struct mic_priv *priv = (struct mic_priv *)
47 kmalloc(sizeof(struct mic_priv), GFP_KERNEL);
48 /*
49 * Not a valid errno as defined in scif.h but should be?
50 */
51 if (!priv)
52 return -ENOMEM;
53
54 /* SCIF device */
55 if (!(priv->epd = __scif_open())) {
56 kfree(priv);
57 return -ENOMEM;
58 }
59
60 ((f)->private_data) = priv;
61 return 0;
62}
63
64int
65scif_fdclose(struct file *f)
66{
67 struct mic_priv *priv = ((f)->private_data);
68 int err = 0;
69
70 /* Only actually request of tear down of end point if file reference
71 * count is greater than 1. This accounts for the fork() issue.
72 */
73 if (atomic64_read(&f->f_count) == 0) {
74 err = __scif_close(priv->epd);
75 kfree(priv);
76 }
77 return err;
78}
79
80int
81micscif_mmap(struct file *f, struct vm_area_struct *vma)
82{
83 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
84 return scif_mmap(vma, priv->epd);
85}
86
87unsigned int
88micscif_poll(struct file *f, poll_table *wait)
89{
90 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
91 return __scif_pollfd(f, wait, (struct endpt *)priv->epd);
92}
93
94int
95micscif_flush(struct file *f, fl_owner_t id)
96{
97 struct mic_priv *priv;
98 dev_t dev;
99 struct endpt *ep;
100
101 priv = (struct mic_priv *)f->private_data;
102 dev = f->f_path.dentry->d_inode->i_rdev;
103 if (MINOR(dev) != 1) // SCIF MINOR
104 return 0;
105
106 ep = priv->epd;
107
108 /* Handles fork issue, making suer an endpoint only closes when the original
109 * thread that created it tries to close it, or when there are no more
110 * references to it.
111 */
112 if (ep->files == id)
113 __scif_flush(ep);
114
115 return 0;
116}
117
118
119static __always_inline void
120scif_err_debug(int err, const char *str)
121{
122 /*
123 * ENOTCONN is a common uninteresting error which is
124 * flooding debug messages to the console unnecessarily.
125 */
126 if (err < 0 && err != -ENOTCONN)
127 pr_debug("%s err %d\n", str, err);
128}
129
130
131
132int
133scif_process_ioctl(struct file *f, unsigned int cmd, uint64_t arg)
134{
135 struct mic_priv *priv = ((f)->private_data);
136 void __user *argp = (void __user *)arg;
137 int err = 0;
138 struct scifioctl_msg request;
139 bool non_block = false;
140
141 non_block = !!(f->f_flags & O_NONBLOCK);
142
143 switch (cmd) {
144 case SCIF_BIND:
145 {
146 int pn;
147
148 if (copy_from_user(&pn, argp, sizeof(pn))) {
149 return -EFAULT;
150 }
151
152 if ((pn = __scif_bind(priv->epd, pn)) < 0) {
153 return pn;
154 }
155
156 if (copy_to_user(argp, &pn, sizeof(pn))) {
157 return -EFAULT;
158 }
159
160 return 0;
161 }
162 case SCIF_LISTEN:
163 return __scif_listen(priv->epd, arg);
164 case SCIF_CONNECT:
165 {
166 struct scifioctl_connect req;
167 struct endpt *ep = (struct endpt *)priv->epd;
168
169 if (copy_from_user(&req, argp, sizeof(struct scifioctl_connect))) {
170 return -EFAULT;
171 }
172
173 if ((err = __scif_connect(priv->epd, &req.peer, non_block)) < 0) {
174 return err;
175 }
176
177 req.self.node = ep->port.node;
178 req.self.port = ep->port.port;
179
180 if (copy_to_user(argp, &req, sizeof(struct scifioctl_connect))) {
181 return -EFAULT;
182 }
183
184
185 return 0;
186 }
187 // Accept is done in two halves. Thes request ioctl does the basic functility of accepting
188 // the request and returning the information about it including the internal ID of the
189 // end point. The register is done with the internID on a new file desciptor opened by the
190 // requesting process.
191 case SCIF_ACCEPTREQ:
192 {
193 struct scifioctl_accept request;
194 unsigned long sflags;
195 scif_epd_t *ep = (scif_epd_t *)&request.endpt;
196
197 if (copy_from_user(&request, argp, sizeof(struct scifioctl_accept))) {
198 return -EFAULT;
199 }
200
201 if ((err = __scif_accept(priv->epd, &request.peer, ep, request.flags)) < 0) {
202 return err;
203 }
204
205 if (copy_to_user(argp, &request, sizeof(struct scifioctl_accept))) {
206 scif_close(*ep);
207 return -EFAULT;
208 }
209
210 // Add to the list of user mode eps where the second half of the accept
211 // is not yet completed.
212 spin_lock_irqsave(&ms_info.mi_eplock, sflags);
213 list_add_tail(&((*ep)->miacceptlist), &ms_info.mi_uaccept);
214 list_add_tail(&((*ep)->liacceptlist), &priv->epd->li_accept);
215 (*ep)->listenep = priv->epd;
216 priv->epd->acceptcnt++;
217 spin_unlock_irqrestore(&ms_info.mi_eplock, sflags);
218
219 return 0;
220 }
221 case SCIF_ACCEPTREG:
222 {
223 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
224 struct endpt *newep;
225 struct endpt *lisep;
226 struct endpt *ep;
227 struct endpt *fep = NULL;
228 struct endpt *tmpep;
229 struct list_head *pos, *tmpq;
230 unsigned long sflags;
231
232 // Finally replace the pointer to the accepted endpoint
233 if (copy_from_user(&newep, argp, sizeof(void *)))
234 return -EFAULT;
235
236 // Remove form the user accept queue
237 spin_lock_irqsave(&ms_info.mi_eplock, sflags);
238 list_for_each_safe(pos, tmpq, &ms_info.mi_uaccept) {
239 tmpep = list_entry(pos, struct endpt, miacceptlist);
240 if (tmpep == newep) {
241 list_del(pos);
242 fep = tmpep;
243 break;
244 }
245 }
246
247 if (fep == NULL) {
248 spin_unlock_irqrestore(&ms_info.mi_eplock, sflags);
249 return -ENOENT;
250 }
251
252 lisep = newep->listenep;
253 list_for_each_safe(pos, tmpq, &lisep->li_accept) {
254 tmpep = list_entry(pos, struct endpt, liacceptlist);
255 if (tmpep == newep) {
256 list_del(pos);
257 lisep->acceptcnt--;
258 break;
259 }
260 }
261
262 spin_unlock_irqrestore(&ms_info.mi_eplock, sflags);
263
264 // Free the resources automatically created from the open.
265 micscif_teardown_ep(priv->epd);
266 micscif_add_epd_to_zombie_list(priv->epd, !MI_EPLOCK_HELD);
267 priv->epd = newep;
268 ep = (struct endpt *)priv->epd;
269 ep = ep;
270 return 0;
271 }
272 case SCIF_SEND:
273 {
274 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
275
276 if (copy_from_user(&request, argp,
277 sizeof(struct scifioctl_msg))) {
278 err = -EFAULT;
279 goto send_err;
280 }
281
282 if ((err = scif_user_send(priv->epd, request.msg,
283 request.len, request.flags)) < 0)
284 goto send_err;
285
286 if (copy_to_user(&((struct scifioctl_msg*)argp)->out_len,
287 &err, sizeof(err))) {
288 err = -EFAULT;
289 goto send_err;
290 }
291 err = 0;
292send_err:
293 scif_err_debug(err, "scif_send");
294 return err;
295 }
296 case SCIF_RECV:
297 {
298 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
299
300 if (copy_from_user(&request, argp,
301 sizeof(struct scifioctl_msg))) {
302 err = -EFAULT;
303 goto recv_err;
304 }
305
306 if ((err = scif_user_recv(priv->epd, request.msg,
307 request.len, request.flags)) < 0)
308 goto recv_err;
309
310 if (copy_to_user(&((struct scifioctl_msg*)argp)->out_len,
311 &err, sizeof(err))) {
312 err = -EFAULT;
313 goto recv_err;
314 }
315 err = 0;
316recv_err:
317 scif_err_debug(err, "scif_recv");
318 return err;
319 }
320 case SCIF_REG:
321 {
322 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
323 struct scifioctl_reg reg;
324 off_t ret;
325
326 if (copy_from_user(&reg, argp, sizeof(reg))) {
327 err = -EFAULT;
328 goto reg_err;
329 }
330 if (reg.flags & SCIF_MAP_KERNEL) {
331 err = -EINVAL;
332 goto reg_err;
333 }
334 if ((ret = __scif_register(priv->epd, reg.addr, reg.len,
335 reg.offset, reg.prot, reg.flags)) < 0) {
336 err = (int)ret;
337 goto reg_err;
338 }
339
340 if (copy_to_user(&((struct scifioctl_reg*)argp)->out_offset,
341 &ret, sizeof(reg.out_offset))) {
342 err = -EFAULT;
343 goto reg_err;
344 }
345 err = 0;
346reg_err:
347 scif_err_debug(err, "scif_register");
348 return err;
349 }
350 case SCIF_UNREG:
351 {
352 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
353 struct scifioctl_unreg unreg;
354
355 if (copy_from_user(&unreg, argp, sizeof(unreg))) {
356 err = -EFAULT;
357 goto unreg_err;
358 }
359 err = __scif_unregister(priv->epd, unreg.offset, unreg.len);
360unreg_err:
361 scif_err_debug(err, "scif_unregister");
362 return err;
363 }
364 case SCIF_READFROM:
365 {
366 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
367 struct scifioctl_copy copy;
368
369 if (copy_from_user(&copy, argp, sizeof(copy))) {
370 err = -EFAULT;
371 goto readfrom_err;
372 }
373 err = __scif_readfrom(priv->epd,
374 copy.loffset,
375 copy.len,
376 copy.roffset,
377 copy.flags);
378readfrom_err:
379 scif_err_debug(err, "scif_readfrom");
380 return err;
381 }
382 case SCIF_WRITETO:
383 {
384 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
385 struct scifioctl_copy copy;
386
387 if (copy_from_user(&copy, argp, sizeof(copy))) {
388 err = -EFAULT;
389 goto writeto_err;
390 }
391 err = __scif_writeto(priv->epd,
392 copy.loffset,
393 copy.len,
394 copy.roffset,
395 copy.flags);
396writeto_err:
397 scif_err_debug(err, "scif_writeto");
398 return err;
399 }
400 case SCIF_VREADFROM:
401 {
402 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
403 struct scifioctl_copy copy;
404
405 if (copy_from_user(&copy, argp, sizeof(copy))) {
406 err = -EFAULT;
407 goto vreadfrom_err;
408 }
409 err = __scif_vreadfrom(priv->epd,
410 copy.addr,
411 copy.len,
412 copy.roffset,
413 copy.flags);
414vreadfrom_err:
415 scif_err_debug(err, "scif_vreadfrom");
416 return err;
417 }
418 case SCIF_VWRITETO:
419 {
420 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
421 struct scifioctl_copy copy;
422
423 if (copy_from_user(&copy, argp, sizeof(copy))) {
424 err = -EFAULT;
425 goto vwriteto_err;
426 }
427 err = __scif_vwriteto(priv->epd,
428 copy.addr,
429 copy.len,
430 copy.roffset,
431 copy.flags);
432vwriteto_err:
433 scif_err_debug(err, "scif_vwriteto");
434 return err;
435 }
436 case SCIF_GET_NODEIDS:
437 {
438 struct scifioctl_nodeIDs nodeIDs;
439 int entries;
440 uint16_t *nodes;
441 uint16_t self;
442
443 if (copy_from_user(&nodeIDs, argp, sizeof(nodeIDs))) {
444 err = -EFAULT;
445 goto getnodes_err2;
446 }
447
448 entries = SCIF_MIN(MAX_BOARD_SUPPORTED, nodeIDs.len);
449
450 nodes = kmalloc(sizeof(uint16_t) * entries, GFP_KERNEL);
451 if ( (entries != 0) && (!nodes) ){
452 err = -ENOMEM;
453 goto getnodes_err2;
454 }
455 nodeIDs.len = scif_get_nodeIDs(nodes, entries, &self);
456
457 if (copy_to_user(nodeIDs.nodes,
458 nodes, sizeof(uint16_t) * entries)) {
459 err = -EFAULT;
460 goto getnodes_err1;
461 }
462
463 if (copy_to_user(nodeIDs.self,
464 &self, sizeof(uint16_t))) {
465 err = -EFAULT;
466 goto getnodes_err1;
467 }
468
469 if (copy_to_user(argp, &nodeIDs, sizeof(nodeIDs))) {
470 err = -EFAULT;
471 goto getnodes_err1;
472 }
473getnodes_err1:
474 kfree(nodes);
475getnodes_err2:
476 return err;
477 }
478 case SCIF_FENCE_MARK:
479 {
480 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
481 struct scifioctl_fence_mark mark;
482 int tmp_mark = 0;
483
484 if (copy_from_user(&mark, argp, sizeof(mark))) {
485 err = -EFAULT;
486 goto fence_mark_err;
487 }
488 if ((err = __scif_fence_mark(priv->epd,
489 mark.flags, &tmp_mark)))
490 goto fence_mark_err;
491 if (copy_to_user(mark.mark, &tmp_mark, sizeof(tmp_mark))) {
492 err = -EFAULT;
493 goto fence_mark_err;
494 }
495fence_mark_err:
496 scif_err_debug(err, "scif_fence_mark");
497 return err;
498 }
499 case SCIF_FENCE_WAIT:
500 {
501 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
502 err = __scif_fence_wait(priv->epd, arg);
503 scif_err_debug(err, "scif_fence_wait");
504 return err;
505 }
506 case SCIF_FENCE_SIGNAL:
507 {
508 struct mic_priv *priv = (struct mic_priv *)((f)->private_data);
509 struct scifioctl_fence_signal signal;
510
511 if (copy_from_user(&signal, argp, sizeof(signal))) {
512 err = -EFAULT;
513 goto fence_signal_err;
514 }
515
516 err = __scif_fence_signal(priv->epd, signal.loff,
517 signal.lval, signal.roff, signal.rval, signal.flags);
518fence_signal_err:
519 scif_err_debug(err, "scif_fence_signal");
520 return err;
521 }
522 case SCIF_GET_VERSION:
523 {
524 return SCIF_VERSION;
525 }
526 }
527 return -EINVAL;
528}