diff options
author | Gary King <gking@nvidia.com> | 2010-05-17 18:47:23 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-17 19:19:58 -0700 |
commit | 896916cf949138437cbcf4ef2a34b59ddd677679 (patch) | |
tree | 96d82a2ed3832ec019e90cb427f0c66c9c55f702 /arch/arm/mach-tegra/nvrpc_user.c | |
parent | 6d7843e49f9ae2e3574fdaaa1b8e64475d41295e (diff) |
[ARM/tegra] add nvrpc interface to NvRmTransport APIs
Change-Id: I5ba8e15ff8b4ad49909d61222be6df8eb66d8867
Diffstat (limited to 'arch/arm/mach-tegra/nvrpc_user.c')
-rw-r--r-- | arch/arm/mach-tegra/nvrpc_user.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/nvrpc_user.c b/arch/arm/mach-tegra/nvrpc_user.c new file mode 100644 index 000000000000..7a9b4b7132f8 --- /dev/null +++ b/arch/arm/mach-tegra/nvrpc_user.c @@ -0,0 +1,629 @@ +/* + * arch/arm/mach-tegra/nvrpc_user.c + * + * User-land access to NvRm transport APIs + * + * Copyright (c) 2008-2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#define NV_DEBUG 0 + +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <mach/nvrm_linux.h> +#include <mach/nvrpc.h> +#include "nvcommon.h" +#include "nvassert.h" +#include "nvos.h" +#include "nvrm_transport.h" +#include "nvrm_xpc.h" + +#define DEVICE_NAME "nvrpc" +#define NVRPC_MAX_LOCAL_STACK 256 +#define nvrpc_stack_kzalloc(stackbuf, size, gfp) \ + ((size) > sizeof((stackbuf)) ? kzalloc((size),(gfp)) : (stackbuf)) +#define nvrpc_stack_kfree(stackbuf, buf) \ + do { \ + if ((buf) && (buf)!=(stackbuf)) \ + kfree(buf); \ + } while (0); + +static int nvrpc_open(struct inode *inode, struct file *file); +static int nvrpc_close(struct inode *inode, struct file *file); +static long nvrpc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +//Ioctl functions +static int nvrpc_ioctl_open(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_get_port_name(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_close(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_wait_for_connect(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_connect(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_set_queue_depth(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_send_msg(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_send_msg_lp0(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_recv_msg(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_init(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_acquire(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_release(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_get_msg(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_send_msg(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_destroy(struct file *filp, + unsigned int cmd, void __user *arg); +static int nvrpc_ioctl_xpc_create(struct file *filp, + unsigned int cmd, void __user *arg); +// local function +static int nvrpc_make_error_code(NvError e); + +static const struct file_operations nvrpc_fops = +{ + .owner = THIS_MODULE, + .open = nvrpc_open, + .release = nvrpc_close, + .unlocked_ioctl = nvrpc_unlocked_ioctl, +}; + +static struct miscdevice nvrpc_dev = +{ + .name = DEVICE_NAME, + .fops = &nvrpc_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + +static DEFINE_MUTEX(nvrpc_device_lock); + +int nvrpc_open(struct inode *inode, struct file *file) +{ + NvError e = NvSuccess; + static NvBool init_done = NV_FALSE; + + mutex_lock(&nvrpc_device_lock); + if (init_done == NV_FALSE) { + e = NvRmTransportInit(s_hRmGlobal); + init_done = NV_TRUE; + } + mutex_unlock(&nvrpc_device_lock); + + if (e == NvSuccess) + return 0; + else + return -ENODEV; +} + +int nvrpc_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static int nvrpc_make_error_code(NvError e) +{ + int error = 0; + if (error != NvSuccess) { + if (e == NvError_InvalidAddress) + error = -EFAULT; + else if (e == NvError_BadParameter) + error = -EINVAL; + else + error = -EIO; + } + return error; +} + +static int nvrpc_ioctl_open(struct file *filp, + unsigned int cmd, void __user *arg) +{ + NvError e = NvSuccess; + int error; + struct nvrpc_open_params op; + char *p_name = NULL; + NvOsSemaphoreHandle recv_sem = NULL; + NvU32 port_name[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)]; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + + if (op.port_name_size) { + p_name = nvrpc_stack_kzalloc(port_name, + op.port_name_size, GFP_KERNEL); + if (!p_name) { + error = -ENOMEM; + goto fail; + } + error = copy_from_user(p_name, (const void*)op.port_name, + op.port_name_size); + if (error) + goto fail; + if (p_name[op.port_name_size - 1] != 0) { + error = -EINVAL; + goto fail; + } + } + if (op.sem) { + NvOsSemaphoreHandle sem = (NvOsSemaphoreHandle) op.sem; + e = NvOsSemaphoreUnmarshal(sem, &recv_sem); + if (e != NvSuccess) + goto fail; + } + op.ret_val = NvRmTransportOpen(s_hRmGlobal, p_name, recv_sem, + (void *)&op.transport_handle); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + nvrpc_stack_kfree(port_name, p_name); + if (recv_sem) + NvOsSemaphoreDestroy(recv_sem); + if (e != NvSuccess) + error = nvrpc_make_error_code(e); + return error; +} + +static int nvrpc_ioctl_get_port_name(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + + struct nvrpc_open_params op; + NvS8 *p_name = NULL; + NvU32 port_name[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)]; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + if (op.port_name_size && op.port_name) { + p_name = nvrpc_stack_kzalloc(port_name, + op.port_name_size, GFP_KERNEL); + if (!p_name) { + error = -ENOMEM; + goto fail; + } + } + NvRmTransportGetPortName((NvRmTransportHandle)op.transport_handle, + p_name, op.port_name_size); + + if (op.port_name_size && p_name) { + error = copy_to_user((void*)op.port_name, + p_name, op.port_name_size * sizeof(NvU8)); + } + +fail: + nvrpc_stack_kfree(port_name, p_name); + return error; +} + +static int nvrpc_ioctl_close(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + NvRmTransportClose((void*)op.handle); + +fail: + return error; +} + +static int nvrpc_ioctl_wait_for_connect(struct file *filp, + unsigned int cmd, void __user *arg) +{ + NvError e = NvSuccess; + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmTransportWaitForConnect( + (void *)op.handle, op.param); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + if (e != NvSuccess) + error = nvrpc_make_error_code(e); + return error; +} + +static int nvrpc_ioctl_connect(struct file *filp, + unsigned int cmd, void __user *arg) +{ + NvError e = NvSuccess; + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmTransportConnect( + (void *)op.handle, op.param); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + if (e != NvSuccess) + error = nvrpc_make_error_code(e); + return error; +} + +static int nvrpc_ioctl_set_queue_depth(struct file *filp, + unsigned int cmd, void __user *arg) +{ + NvError e = NvSuccess; + int error; + struct nvrpc_set_queue_depth_params op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmTransportSetQueueDepth( + (NvRmTransportHandle)op.transport_handle, + op.max_queue_depth, + op.max_message_size); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + if (e != NvSuccess) + error = nvrpc_make_error_code(e); + return error; +} + +static int nvrpc_ioctl_send_msg(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_msg_params op; + void* msg_buffer = NULL; + NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)]; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + if (op.msg_buffer && op.max_message_size) { + msg_buffer = nvrpc_stack_kzalloc(buffer, + op.max_message_size, + GFP_KERNEL); + if (!msg_buffer) { + error = -ENOMEM; + goto fail; + } + error = copy_from_user(msg_buffer, + (void*)op.msg_buffer, + op.max_message_size); + if (error) + goto fail; + } + + op.ret_val = NvRmTransportSendMsg( + (NvRmTransportHandle)op.transport_handle, + msg_buffer, op.max_message_size, op.params); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + nvrpc_stack_kfree(buffer, msg_buffer); + return error; +} + +static int nvrpc_ioctl_send_msg_lp0(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_msg_params op; + void* msg_buffer = NULL; + NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)]; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + if (op.msg_buffer && op.max_message_size) { + msg_buffer = nvrpc_stack_kzalloc(buffer, + op.max_message_size, GFP_KERNEL); + if (!msg_buffer) { + error = -ENOMEM; + goto fail; + } + error = copy_from_user(msg_buffer, (void*)op.msg_buffer, + op.max_message_size); + if (error) + goto fail; + } + op.ret_val = NvRmTransportSendMsgInLP0( + (NvRmTransportHandle)op.transport_handle, + msg_buffer, op.max_message_size); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + nvrpc_stack_kfree(buffer, msg_buffer); + return error; +} + +static int nvrpc_ioctl_recv_msg(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_msg_params op; + void* msg_buffer = NULL; + NvU32 buffer[NVRPC_MAX_LOCAL_STACK/sizeof(NvU32)]; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + if (op.msg_buffer && op.max_message_size) { + msg_buffer = nvrpc_stack_kzalloc(buffer, + op.max_message_size, GFP_KERNEL); + if (!msg_buffer) { + error = -ENOMEM; + goto fail; + } + } else { + error = -EINVAL; + goto fail; + } + op.ret_val = NvRmTransportRecvMsg( + (NvRmTransportHandle)op.transport_handle, + msg_buffer, op.max_message_size, &op.params); + error = copy_to_user(arg, &op, sizeof(op)); + if (op.msg_buffer && msg_buffer) { + error = copy_to_user((void*)op.msg_buffer, + msg_buffer, op.max_message_size); + if (error) + goto fail; + } + +fail: + nvrpc_stack_kfree(buffer, msg_buffer); + return error; +} + +static int nvrpc_ioctl_xpc_init(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmXpcInitArbSemaSystem((void *)op.handle); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_acquire(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + NvRmXpcModuleAcquire(op.param); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_release(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + NvRmXpcModuleRelease(op.param); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_get_msg(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmPrivXpcGetMessage( + (NvRmPrivXpcMessageHandle)op.handle); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_send_msg(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmPrivXpcSendMessage( + (NvRmPrivXpcMessageHandle)op.handle, op.param); + error = copy_to_user(arg, &op, sizeof(op)); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_destroy(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + NvRmPrivXpcDestroy((NvRmPrivXpcMessageHandle)op.handle); + +fail: + return error; +} + +static int nvrpc_ioctl_xpc_create(struct file *filp, + unsigned int cmd, void __user *arg) +{ + int error; + struct nvrpc_handle_param op; + + error = copy_from_user(&op, arg, sizeof(op)); + if (error) + goto fail; + op.ret_val = NvRmPrivXpcCreate((NvRmDeviceHandle)op.handle, + (void*)&op.param); + error = copy_to_user(&op, arg, sizeof(op)); + +fail: + return error; +} + + +static long nvrpc_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int err = 0; + void __user *uarg = (void __user *)arg; + + if (_IOC_TYPE(cmd) != NVRPC_IOC_MAGIC) + return -ENOTTY; + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd)); + if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd)); + + if (err) + return -EFAULT; + + switch (cmd) { + case NVRPC_IOCTL_OPEN: + err = nvrpc_ioctl_open(file, cmd, uarg); + break; + + case NVRPC_IOCTL_GET_PORTNAME: + err = nvrpc_ioctl_get_port_name(file, cmd, uarg); + break; + + case NVRPC_IOCTL_CLOSE: + err = nvrpc_ioctl_close(file, cmd, uarg); + break; + + case NVRPC_IOCTL_INIT: + case NVRPC_IOCTL_DEINIT: + break; + + case NVRPC_IOCTL_WAIT_FOR_CONNECT: + err = nvrpc_ioctl_wait_for_connect(file, cmd, uarg); + break; + + case NVRPC_IOCTL_CONNECT: + err = nvrpc_ioctl_connect(file, cmd, uarg); + break; + + case NVRPC_IOCTL_SET_QUEUE_DEPTH: + err = nvrpc_ioctl_set_queue_depth(file, cmd, uarg); + break; + + case NVRPC_IOCTL_SEND_MSG: + err = nvrpc_ioctl_send_msg(file, cmd, uarg); + break; + + case NVRPC_IOCTL_SEND_MSG_LP0: + err = nvrpc_ioctl_send_msg_lp0(file, cmd, uarg); + break; + + case NVRPC_IOCTL_RECV_MSG: + err = nvrpc_ioctl_recv_msg(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_INIT: + err = nvrpc_ioctl_xpc_init(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_ACQUIRE: + err = nvrpc_ioctl_xpc_acquire(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_RELEASE: + err = nvrpc_ioctl_xpc_release(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_GET_MSG: + err = nvrpc_ioctl_xpc_get_msg(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_SEND_MSG: + err = nvrpc_ioctl_xpc_send_msg(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_DESTROY: + err = nvrpc_ioctl_xpc_destroy(file, cmd, uarg); + break; + + case NVRPC_IOCTL_XPC_CREATE: + err = nvrpc_ioctl_xpc_create(file, cmd, uarg); + break; + + default: + return -ENOTTY; + } + return err; +} + +static int __init nvrpc_init(void) +{ + int ret = 0; + + ret = misc_register(&nvrpc_dev); + if (ret) { + pr_err("%s misc register FAILED\n", __func__); + } + return ret; +} + +static void __exit nvrpc_deinit(void) +{ + misc_deregister(&nvrpc_dev); +} + +module_init(nvrpc_init); +module_exit(nvrpc_deinit); |