misc: mic: SCIF open close bind and listen APIs
[linux-2.6-block.git] / drivers / misc / mic / scif / scif_fd.c
1 /*
2  * Intel MIC Platform Software Stack (MPSS)
3  *
4  * Copyright(c) 2014 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  * Intel SCIF driver.
16  *
17  */
18 #include "scif_main.h"
19
20 static int scif_fdopen(struct inode *inode, struct file *f)
21 {
22         struct scif_endpt *priv = scif_open();
23
24         if (!priv)
25                 return -ENOMEM;
26         f->private_data = priv;
27         return 0;
28 }
29
30 static int scif_fdclose(struct inode *inode, struct file *f)
31 {
32         struct scif_endpt *priv = f->private_data;
33
34         return scif_close(priv);
35 }
36
37 static int scif_fdflush(struct file *f, fl_owner_t id)
38 {
39         struct scif_endpt *ep = f->private_data;
40
41         spin_lock(&ep->lock);
42         /*
43          * The listening endpoint stashes the open file information before
44          * waiting for incoming connections. The release callback would never be
45          * called if the application closed the endpoint, while waiting for
46          * incoming connections from a separate thread since the file descriptor
47          * reference count is bumped up in the accept IOCTL. Call the flush
48          * routine if the id matches the endpoint open file information so that
49          * the listening endpoint can be woken up and the fd released.
50          */
51         if (ep->files == id)
52                 __scif_flush(ep);
53         spin_unlock(&ep->lock);
54         return 0;
55 }
56
57 static __always_inline void scif_err_debug(int err, const char *str)
58 {
59         /*
60          * ENOTCONN is a common uninteresting error which is
61          * flooding debug messages to the console unnecessarily.
62          */
63         if (err < 0 && err != -ENOTCONN)
64                 dev_dbg(scif_info.mdev.this_device, "%s err %d\n", str, err);
65 }
66
67 static long scif_fdioctl(struct file *f, unsigned int cmd, unsigned long arg)
68 {
69         struct scif_endpt *priv = f->private_data;
70         void __user *argp = (void __user *)arg;
71         bool non_block = false;
72
73         non_block = !!(f->f_flags & O_NONBLOCK);
74
75         switch (cmd) {
76         case SCIF_BIND:
77         {
78                 int pn;
79
80                 if (copy_from_user(&pn, argp, sizeof(pn)))
81                         return -EFAULT;
82
83                 pn = scif_bind(priv, pn);
84                 if (pn < 0)
85                         return pn;
86
87                 if (copy_to_user(argp, &pn, sizeof(pn)))
88                         return -EFAULT;
89
90                 return 0;
91         }
92         case SCIF_LISTEN:
93                 return scif_listen(priv, arg);
94         }
95         return -EINVAL;
96 }
97
98 const struct file_operations scif_fops = {
99         .open = scif_fdopen,
100         .release = scif_fdclose,
101         .unlocked_ioctl = scif_fdioctl,
102         .flush = scif_fdflush,
103         .owner = THIS_MODULE,
104 };