* Copyright 2010-2017 Intel Corporation.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed Knights Ferry,
* and the Intel product codenamed Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
* Intel offers no warranty of any kind regarding the code. This code is
* licensed on an "AS IS" basis and Intel is not obligated to provide
* any support, assistance, installation, training, or other services
* of any kind. Intel is also not obligated to provide any updates,
* enhancements or extensions. Intel specifically disclaims any warranty
* of merchantability, non-infringement, fitness for any particular
* purpose, and any other warranty.
* Further, Intel disclaims all liability of any kind, including but
* not limited to liability for infringement of any proprietary rights,
* relating to the use of the code, even if Intel is notified of the
* possibility of such liability. Except as expressly stated in an Intel
* license agreement provided with this code and agreed upon with Intel,
* no license, express or implied, by estoppel or otherwise, to any
* intellectual property rights is granted herein.
scif_fdopen(struct file
*f
)
struct mic_priv
*priv
= (struct mic_priv
*)
kmalloc(sizeof(struct mic_priv
), GFP_KERNEL
);
* Not a valid errno as defined in scif.h but should be?
if (!(priv
->epd
= __scif_open())) {
((f
)->private_data
) = priv
;
scif_fdclose(struct file
*f
)
struct mic_priv
*priv
= ((f
)->private_data
);
/* Only actually request of tear down of end point if file reference
* count is greater than 1. This accounts for the fork() issue.
if (atomic64_read(&f
->f_count
) == 0) {
err
= __scif_close(priv
->epd
);
micscif_mmap(struct file
*f
, struct vm_area_struct
*vma
)
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
return scif_mmap(vma
, priv
->epd
);
micscif_poll(struct file
*f
, poll_table
*wait
)
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
return __scif_pollfd(f
, wait
, (struct endpt
*)priv
->epd
);
micscif_flush(struct file
*f
, fl_owner_t id
)
priv
= (struct mic_priv
*)f
->private_data
;
dev
= f
->f_path
.dentry
->d_inode
->i_rdev
;
if (MINOR(dev
) != 1) // SCIF MINOR
/* Handles fork issue, making suer an endpoint only closes when the original
* thread that created it tries to close it, or when there are no more
static __always_inline
void
scif_err_debug(int err
, const char *str
)
* ENOTCONN is a common uninteresting error which is
* flooding debug messages to the console unnecessarily.
if (err
< 0 && err
!= -ENOTCONN
)
pr_debug("%s err %d\n", str
, err
);
scif_process_ioctl(struct file
*f
, unsigned int cmd
, uint64_t arg
)
struct mic_priv
*priv
= ((f
)->private_data
);
void __user
*argp
= (void __user
*)arg
;
struct scifioctl_msg request
;
non_block
= !!(f
->f_flags
& O_NONBLOCK
);
if (copy_from_user(&pn
, argp
, sizeof(pn
))) {
if ((pn
= __scif_bind(priv
->epd
, pn
)) < 0) {
if (copy_to_user(argp
, &pn
, sizeof(pn
))) {
return __scif_listen(priv
->epd
, arg
);
struct scifioctl_connect req
;
struct endpt
*ep
= (struct endpt
*)priv
->epd
;
if (copy_from_user(&req
, argp
, sizeof(struct scifioctl_connect
))) {
if ((err
= __scif_connect(priv
->epd
, &req
.peer
, non_block
)) < 0) {
req
.self
.node
= ep
->port
.node
;
req
.self
.port
= ep
->port
.port
;
if (copy_to_user(argp
, &req
, sizeof(struct scifioctl_connect
))) {
// Accept is done in two halves. Thes request ioctl does the basic functility of accepting
// the request and returning the information about it including the internal ID of the
// end point. The register is done with the internID on a new file desciptor opened by the
struct scifioctl_accept request
;
scif_epd_t
*ep
= (scif_epd_t
*)&request
.endpt
;
if (copy_from_user(&request
, argp
, sizeof(struct scifioctl_accept
))) {
if ((err
= __scif_accept(priv
->epd
, &request
.peer
, ep
, request
.flags
)) < 0) {
if (copy_to_user(argp
, &request
, sizeof(struct scifioctl_accept
))) {
// Add to the list of user mode eps where the second half of the accept
spin_lock_irqsave(&ms_info
.mi_eplock
, sflags
);
list_add_tail(&((*ep
)->miacceptlist
), &ms_info
.mi_uaccept
);
list_add_tail(&((*ep
)->liacceptlist
), &priv
->epd
->li_accept
);
(*ep
)->listenep
= priv
->epd
;
spin_unlock_irqrestore(&ms_info
.mi_eplock
, sflags
);
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct endpt
*fep
= NULL
;
struct list_head
*pos
, *tmpq
;
// Finally replace the pointer to the accepted endpoint
if (copy_from_user(&newep
, argp
, sizeof(void *)))
// Remove form the user accept queue
spin_lock_irqsave(&ms_info
.mi_eplock
, sflags
);
list_for_each_safe(pos
, tmpq
, &ms_info
.mi_uaccept
) {
tmpep
= list_entry(pos
, struct endpt
, miacceptlist
);
spin_unlock_irqrestore(&ms_info
.mi_eplock
, sflags
);
list_for_each_safe(pos
, tmpq
, &lisep
->li_accept
) {
tmpep
= list_entry(pos
, struct endpt
, liacceptlist
);
spin_unlock_irqrestore(&ms_info
.mi_eplock
, sflags
);
// Free the resources automatically created from the open.
micscif_teardown_ep(priv
->epd
);
micscif_add_epd_to_zombie_list(priv
->epd
, !MI_EPLOCK_HELD
);
ep
= (struct endpt
*)priv
->epd
;
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
if (copy_from_user(&request
, argp
,
sizeof(struct scifioctl_msg
))) {
if ((err
= scif_user_send(priv
->epd
, request
.msg
,
request
.len
, request
.flags
)) < 0)
if (copy_to_user(&((struct scifioctl_msg
*)argp
)->out_len
,
scif_err_debug(err
, "scif_send");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
if (copy_from_user(&request
, argp
,
sizeof(struct scifioctl_msg
))) {
if ((err
= scif_user_recv(priv
->epd
, request
.msg
,
request
.len
, request
.flags
)) < 0)
if (copy_to_user(&((struct scifioctl_msg
*)argp
)->out_len
,
scif_err_debug(err
, "scif_recv");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_reg reg
;
if (copy_from_user(®
, argp
, sizeof(reg
))) {
if (reg
.flags
& SCIF_MAP_KERNEL
) {
if ((ret
= __scif_register(priv
->epd
, reg
.addr
, reg
.len
,
reg
.offset
, reg
.prot
, reg
.flags
)) < 0) {
if (copy_to_user(&((struct scifioctl_reg
*)argp
)->out_offset
,
&ret
, sizeof(reg
.out_offset
))) {
scif_err_debug(err
, "scif_register");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_unreg unreg
;
if (copy_from_user(&unreg
, argp
, sizeof(unreg
))) {
err
= __scif_unregister(priv
->epd
, unreg
.offset
, unreg
.len
);
scif_err_debug(err
, "scif_unregister");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_copy copy
;
if (copy_from_user(©
, argp
, sizeof(copy
))) {
err
= __scif_readfrom(priv
->epd
,
scif_err_debug(err
, "scif_readfrom");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_copy copy
;
if (copy_from_user(©
, argp
, sizeof(copy
))) {
err
= __scif_writeto(priv
->epd
,
scif_err_debug(err
, "scif_writeto");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_copy copy
;
if (copy_from_user(©
, argp
, sizeof(copy
))) {
err
= __scif_vreadfrom(priv
->epd
,
scif_err_debug(err
, "scif_vreadfrom");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_copy copy
;
if (copy_from_user(©
, argp
, sizeof(copy
))) {
err
= __scif_vwriteto(priv
->epd
,
scif_err_debug(err
, "scif_vwriteto");
struct scifioctl_nodeIDs nodeIDs
;
if (copy_from_user(&nodeIDs
, argp
, sizeof(nodeIDs
))) {
entries
= SCIF_MIN(MAX_BOARD_SUPPORTED
, nodeIDs
.len
);
nodes
= kmalloc(sizeof(uint16_t) * entries
, GFP_KERNEL
);
if ( (entries
!= 0) && (!nodes
) ){
nodeIDs
.len
= scif_get_nodeIDs(nodes
, entries
, &self
);
if (copy_to_user(nodeIDs
.nodes
,
nodes
, sizeof(uint16_t) * entries
)) {
if (copy_to_user(nodeIDs
.self
,
&self
, sizeof(uint16_t))) {
if (copy_to_user(argp
, &nodeIDs
, sizeof(nodeIDs
))) {
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_fence_mark mark
;
if (copy_from_user(&mark
, argp
, sizeof(mark
))) {
if ((err
= __scif_fence_mark(priv
->epd
,
if (copy_to_user(mark
.mark
, &tmp_mark
, sizeof(tmp_mark
))) {
scif_err_debug(err
, "scif_fence_mark");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
err
= __scif_fence_wait(priv
->epd
, arg
);
scif_err_debug(err
, "scif_fence_wait");
struct mic_priv
*priv
= (struct mic_priv
*)((f
)->private_data
);
struct scifioctl_fence_signal signal
;
if (copy_from_user(&signal
, argp
, sizeof(signal
))) {
err
= __scif_fence_signal(priv
->epd
, signal
.loff
,
signal
.lval
, signal
.roff
, signal
.rval
, signal
.flags
);
scif_err_debug(err
, "scif_fence_signal");