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(®, 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(©, 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(©, 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(©, 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(©, 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