linux/drivers/misc/mic/scif/scif_fd.c
<<
>>
Prefs
   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
  20static 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
  30static 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
  37static int scif_fdmmap(struct file *f, struct vm_area_struct *vma)
  38{
  39        struct scif_endpt *priv = f->private_data;
  40
  41        return scif_mmap(vma, priv);
  42}
  43
  44static unsigned int scif_fdpoll(struct file *f, poll_table *wait)
  45{
  46        struct scif_endpt *priv = f->private_data;
  47
  48        return __scif_pollfd(f, wait, priv);
  49}
  50
  51static int scif_fdflush(struct file *f, fl_owner_t id)
  52{
  53        struct scif_endpt *ep = f->private_data;
  54
  55        spin_lock(&ep->lock);
  56        /*
  57         * The listening endpoint stashes the open file information before
  58         * waiting for incoming connections. The release callback would never be
  59         * called if the application closed the endpoint, while waiting for
  60         * incoming connections from a separate thread since the file descriptor
  61         * reference count is bumped up in the accept IOCTL. Call the flush
  62         * routine if the id matches the endpoint open file information so that
  63         * the listening endpoint can be woken up and the fd released.
  64         */
  65        if (ep->files == id)
  66                __scif_flush(ep);
  67        spin_unlock(&ep->lock);
  68        return 0;
  69}
  70
  71static __always_inline void scif_err_debug(int err, const char *str)
  72{
  73        /*
  74         * ENOTCONN is a common uninteresting error which is
  75         * flooding debug messages to the console unnecessarily.
  76         */
  77        if (err < 0 && err != -ENOTCONN)
  78                dev_dbg(scif_info.mdev.this_device, "%s err %d\n", str, err);
  79}
  80
  81static long scif_fdioctl(struct file *f, unsigned int cmd, unsigned long arg)
  82{
  83        struct scif_endpt *priv = f->private_data;
  84        void __user *argp = (void __user *)arg;
  85        int err = 0;
  86        struct scifioctl_msg request;
  87        bool non_block = false;
  88
  89        non_block = !!(f->f_flags & O_NONBLOCK);
  90
  91        switch (cmd) {
  92        case SCIF_BIND:
  93        {
  94                int pn;
  95
  96                if (copy_from_user(&pn, argp, sizeof(pn)))
  97                        return -EFAULT;
  98
  99                pn = scif_bind(priv, pn);
 100                if (pn < 0)
 101                        return pn;
 102
 103                if (copy_to_user(argp, &pn, sizeof(pn)))
 104                        return -EFAULT;
 105
 106                return 0;
 107        }
 108        case SCIF_LISTEN:
 109                return scif_listen(priv, arg);
 110        case SCIF_CONNECT:
 111        {
 112                struct scifioctl_connect req;
 113                struct scif_endpt *ep = (struct scif_endpt *)priv;
 114
 115                if (copy_from_user(&req, argp, sizeof(req)))
 116                        return -EFAULT;
 117
 118                err = __scif_connect(priv, &req.peer, non_block);
 119                if (err < 0)
 120                        return err;
 121
 122                req.self.node = ep->port.node;
 123                req.self.port = ep->port.port;
 124
 125                if (copy_to_user(argp, &req, sizeof(req)))
 126                        return -EFAULT;
 127
 128                return 0;
 129        }
 130        /*
 131         * Accept is done in two halves.  The request ioctl does the basic
 132         * functionality of accepting the request and returning the information
 133         * about it including the internal ID of the end point.  The register
 134         * is done with the internal ID on a new file descriptor opened by the
 135         * requesting process.
 136         */
 137        case SCIF_ACCEPTREQ:
 138        {
 139                struct scifioctl_accept request;
 140                scif_epd_t *ep = (scif_epd_t *)&request.endpt;
 141
 142                if (copy_from_user(&request, argp, sizeof(request)))
 143                        return -EFAULT;
 144
 145                err = scif_accept(priv, &request.peer, ep, request.flags);
 146                if (err < 0)
 147                        return err;
 148
 149                if (copy_to_user(argp, &request, sizeof(request))) {
 150                        scif_close(*ep);
 151                        return -EFAULT;
 152                }
 153                /*
 154                 * Add to the list of user mode eps where the second half
 155                 * of the accept is not yet completed.
 156                 */
 157                mutex_lock(&scif_info.eplock);
 158                list_add_tail(&((*ep)->miacceptlist), &scif_info.uaccept);
 159                list_add_tail(&((*ep)->liacceptlist), &priv->li_accept);
 160                (*ep)->listenep = priv;
 161                priv->acceptcnt++;
 162                mutex_unlock(&scif_info.eplock);
 163
 164                return 0;
 165        }
 166        case SCIF_ACCEPTREG:
 167        {
 168                struct scif_endpt *priv = f->private_data;
 169                struct scif_endpt *newep;
 170                struct scif_endpt *lisep;
 171                struct scif_endpt *fep = NULL;
 172                struct scif_endpt *tmpep;
 173                struct list_head *pos, *tmpq;
 174
 175                /* Finally replace the pointer to the accepted endpoint */
 176                if (copy_from_user(&newep, argp, sizeof(void *)))
 177                        return -EFAULT;
 178
 179                /* Remove form the user accept queue */
 180                mutex_lock(&scif_info.eplock);
 181                list_for_each_safe(pos, tmpq, &scif_info.uaccept) {
 182                        tmpep = list_entry(pos,
 183                                           struct scif_endpt, miacceptlist);
 184                        if (tmpep == newep) {
 185                                list_del(pos);
 186                                fep = tmpep;
 187                                break;
 188                        }
 189                }
 190
 191                if (!fep) {
 192                        mutex_unlock(&scif_info.eplock);
 193                        return -ENOENT;
 194                }
 195
 196                lisep = newep->listenep;
 197                list_for_each_safe(pos, tmpq, &lisep->li_accept) {
 198                        tmpep = list_entry(pos,
 199                                           struct scif_endpt, liacceptlist);
 200                        if (tmpep == newep) {
 201                                list_del(pos);
 202                                lisep->acceptcnt--;
 203                                break;
 204                        }
 205                }
 206
 207                mutex_unlock(&scif_info.eplock);
 208
 209                /* Free the resources automatically created from the open. */
 210                scif_anon_inode_fput(priv);
 211                scif_teardown_ep(priv);
 212                scif_add_epd_to_zombie_list(priv, !SCIF_EPLOCK_HELD);
 213                f->private_data = newep;
 214                return 0;
 215        }
 216        case SCIF_SEND:
 217        {
 218                struct scif_endpt *priv = f->private_data;
 219
 220                if (copy_from_user(&request, argp,
 221                                   sizeof(struct scifioctl_msg))) {
 222                        err = -EFAULT;
 223                        goto send_err;
 224                }
 225                err = scif_user_send(priv, (void __user *)request.msg,
 226                                     request.len, request.flags);
 227                if (err < 0)
 228                        goto send_err;
 229                if (copy_to_user(&
 230                                 ((struct scifioctl_msg __user *)argp)->out_len,
 231                                 &err, sizeof(err))) {
 232                        err = -EFAULT;
 233                        goto send_err;
 234                }
 235                err = 0;
 236send_err:
 237                scif_err_debug(err, "scif_send");
 238                return err;
 239        }
 240        case SCIF_RECV:
 241        {
 242                struct scif_endpt *priv = f->private_data;
 243
 244                if (copy_from_user(&request, argp,
 245                                   sizeof(struct scifioctl_msg))) {
 246                        err = -EFAULT;
 247                        goto recv_err;
 248                }
 249
 250                err = scif_user_recv(priv, (void __user *)request.msg,
 251                                     request.len, request.flags);
 252                if (err < 0)
 253                        goto recv_err;
 254
 255                if (copy_to_user(&
 256                                 ((struct scifioctl_msg __user *)argp)->out_len,
 257                        &err, sizeof(err))) {
 258                        err = -EFAULT;
 259                        goto recv_err;
 260                }
 261                err = 0;
 262recv_err:
 263                scif_err_debug(err, "scif_recv");
 264                return err;
 265        }
 266        case SCIF_GET_NODEIDS:
 267        {
 268                struct scifioctl_node_ids node_ids;
 269                int entries;
 270                u16 *nodes;
 271                void __user *unodes, *uself;
 272                u16 self;
 273
 274                if (copy_from_user(&node_ids, argp, sizeof(node_ids))) {
 275                        err = -EFAULT;
 276                        goto getnodes_err2;
 277                }
 278
 279                entries = min_t(int, scif_info.maxid, node_ids.len);
 280                nodes = kmalloc_array(entries, sizeof(u16), GFP_KERNEL);
 281                if (entries && !nodes) {
 282                        err = -ENOMEM;
 283                        goto getnodes_err2;
 284                }
 285                node_ids.len = scif_get_node_ids(nodes, entries, &self);
 286
 287                unodes = (void __user *)node_ids.nodes;
 288                if (copy_to_user(unodes, nodes, sizeof(u16) * entries)) {
 289                        err = -EFAULT;
 290                        goto getnodes_err1;
 291                }
 292
 293                uself = (void __user *)node_ids.self;
 294                if (copy_to_user(uself, &self, sizeof(u16))) {
 295                        err = -EFAULT;
 296                        goto getnodes_err1;
 297                }
 298
 299                if (copy_to_user(argp, &node_ids, sizeof(node_ids))) {
 300                        err = -EFAULT;
 301                        goto getnodes_err1;
 302                }
 303getnodes_err1:
 304                kfree(nodes);
 305getnodes_err2:
 306                return err;
 307        }
 308        case SCIF_REG:
 309        {
 310                struct scif_endpt *priv = f->private_data;
 311                struct scifioctl_reg reg;
 312                off_t ret;
 313
 314                if (copy_from_user(&reg, argp, sizeof(reg))) {
 315                        err = -EFAULT;
 316                        goto reg_err;
 317                }
 318                if (reg.flags & SCIF_MAP_KERNEL) {
 319                        err = -EINVAL;
 320                        goto reg_err;
 321                }
 322                ret = scif_register(priv, (void *)reg.addr, reg.len,
 323                                    reg.offset, reg.prot, reg.flags);
 324                if (ret < 0) {
 325                        err = (int)ret;
 326                        goto reg_err;
 327                }
 328
 329                if (copy_to_user(&((struct scifioctl_reg __user *)argp)
 330                                 ->out_offset, &ret, sizeof(reg.out_offset))) {
 331                        err = -EFAULT;
 332                        goto reg_err;
 333                }
 334                err = 0;
 335reg_err:
 336                scif_err_debug(err, "scif_register");
 337                return err;
 338        }
 339        case SCIF_UNREG:
 340        {
 341                struct scif_endpt *priv = f->private_data;
 342                struct scifioctl_unreg unreg;
 343
 344                if (copy_from_user(&unreg, argp, sizeof(unreg))) {
 345                        err = -EFAULT;
 346                        goto unreg_err;
 347                }
 348                err = scif_unregister(priv, unreg.offset, unreg.len);
 349unreg_err:
 350                scif_err_debug(err, "scif_unregister");
 351                return err;
 352        }
 353        case SCIF_READFROM:
 354        {
 355                struct scif_endpt *priv = f->private_data;
 356                struct scifioctl_copy copy;
 357
 358                if (copy_from_user(&copy, argp, sizeof(copy))) {
 359                        err = -EFAULT;
 360                        goto readfrom_err;
 361                }
 362                err = scif_readfrom(priv, copy.loffset, copy.len, copy.roffset,
 363                                    copy.flags);
 364readfrom_err:
 365                scif_err_debug(err, "scif_readfrom");
 366                return err;
 367        }
 368        case SCIF_WRITETO:
 369        {
 370                struct scif_endpt *priv = f->private_data;
 371                struct scifioctl_copy copy;
 372
 373                if (copy_from_user(&copy, argp, sizeof(copy))) {
 374                        err = -EFAULT;
 375                        goto writeto_err;
 376                }
 377                err = scif_writeto(priv, copy.loffset, copy.len, copy.roffset,
 378                                   copy.flags);
 379writeto_err:
 380                scif_err_debug(err, "scif_writeto");
 381                return err;
 382        }
 383        case SCIF_VREADFROM:
 384        {
 385                struct scif_endpt *priv = f->private_data;
 386                struct scifioctl_copy copy;
 387
 388                if (copy_from_user(&copy, argp, sizeof(copy))) {
 389                        err = -EFAULT;
 390                        goto vreadfrom_err;
 391                }
 392                err = scif_vreadfrom(priv, (void __force *)copy.addr, copy.len,
 393                                     copy.roffset, copy.flags);
 394vreadfrom_err:
 395                scif_err_debug(err, "scif_vreadfrom");
 396                return err;
 397        }
 398        case SCIF_VWRITETO:
 399        {
 400                struct scif_endpt *priv = f->private_data;
 401                struct scifioctl_copy copy;
 402
 403                if (copy_from_user(&copy, argp, sizeof(copy))) {
 404                        err = -EFAULT;
 405                        goto vwriteto_err;
 406                }
 407                err = scif_vwriteto(priv, (void __force *)copy.addr, copy.len,
 408                                    copy.roffset, copy.flags);
 409vwriteto_err:
 410                scif_err_debug(err, "scif_vwriteto");
 411                return err;
 412        }
 413        case SCIF_FENCE_MARK:
 414        {
 415                struct scif_endpt *priv = f->private_data;
 416                struct scifioctl_fence_mark mark;
 417                int tmp_mark = 0;
 418
 419                if (copy_from_user(&mark, argp, sizeof(mark))) {
 420                        err = -EFAULT;
 421                        goto fence_mark_err;
 422                }
 423                err = scif_fence_mark(priv, mark.flags, &tmp_mark);
 424                if (err)
 425                        goto fence_mark_err;
 426                if (copy_to_user((void __user *)mark.mark, &tmp_mark,
 427                                 sizeof(tmp_mark))) {
 428                        err = -EFAULT;
 429                        goto fence_mark_err;
 430                }
 431fence_mark_err:
 432                scif_err_debug(err, "scif_fence_mark");
 433                return err;
 434        }
 435        case SCIF_FENCE_WAIT:
 436        {
 437                struct scif_endpt *priv = f->private_data;
 438
 439                err = scif_fence_wait(priv, arg);
 440                scif_err_debug(err, "scif_fence_wait");
 441                return err;
 442        }
 443        case SCIF_FENCE_SIGNAL:
 444        {
 445                struct scif_endpt *priv = f->private_data;
 446                struct scifioctl_fence_signal signal;
 447
 448                if (copy_from_user(&signal, argp, sizeof(signal))) {
 449                        err = -EFAULT;
 450                        goto fence_signal_err;
 451                }
 452
 453                err = scif_fence_signal(priv, signal.loff, signal.lval,
 454                                        signal.roff, signal.rval, signal.flags);
 455fence_signal_err:
 456                scif_err_debug(err, "scif_fence_signal");
 457                return err;
 458        }
 459        }
 460        return -EINVAL;
 461}
 462
 463const struct file_operations scif_fops = {
 464        .open = scif_fdopen,
 465        .release = scif_fdclose,
 466        .unlocked_ioctl = scif_fdioctl,
 467        .mmap = scif_fdmmap,
 468        .poll = scif_fdpoll,
 469        .flush = scif_fdflush,
 470        .owner = THIS_MODULE,
 471};
 472