diff options
Diffstat (limited to 'drivers/staging/nmf-cm/cmld.c')
-rw-r--r-- | drivers/staging/nmf-cm/cmld.c | 450 |
1 files changed, 152 insertions, 298 deletions
diff --git a/drivers/staging/nmf-cm/cmld.c b/drivers/staging/nmf-cm/cmld.c index 17af63ac407..ef9753de7a4 100644 --- a/drivers/staging/nmf-cm/cmld.c +++ b/drivers/staging/nmf-cm/cmld.c @@ -14,9 +14,9 @@ #include <linux/cdev.h> #include <linux/io.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/slab.h> #include <linux/uaccess.h> +#include <linux/sched.h> #include <cm/inc/cm_def.h> #include <cm/engine/api/cm_engine.h> @@ -29,7 +29,7 @@ #include "cm_service.h" #include "cm_dma.h" -#define CMDRIVER_PATCH_VERSION 121 +#define CMDRIVER_PATCH_VERSION 117 #define O_FLUSH 0x1000000 static int cmld_major; @@ -233,6 +233,111 @@ static void freeProcessPriv(struct kref *ref) OSAL_Free(entry); } +/** Driver's open method + * Allocates per-process resources: private data, wait queue, + * memory area descriptors linked list, message queue. + * + * \return POSIX error code + */ +static int cmld_open(struct inode *inode, struct file *file) +{ + struct cm_process_priv *procPriv = getProcessPriv(); + + if (IS_ERR(procPriv)) + return PTR_ERR(procPriv); + + if (iminor(inode) == 0) + file->private_data = procPriv; + else { + struct cm_channel_priv *channelPriv = (struct cm_channel_priv*)OSAL_Alloc(sizeof(*channelPriv)); + if (channelPriv == NULL) { + kref_put(&procPriv->ref, freeProcessPriv); + return -ENOMEM; + } + + channelPriv->proc = procPriv; + channelPriv->state = CHANNEL_OPEN; + + /* Initialize wait_queue, lists and mutexes */ + init_waitqueue_head(&channelPriv->waitq); + plist_head_init(&channelPriv->messageQueue); + INIT_LIST_HEAD(&channelPriv->skelList); + spin_lock_init(&channelPriv->bh_lock); + mutex_init(&channelPriv->msgQueueLock); + mutex_init(&channelPriv->skelListLock); + + tasklet_disable(&cmld_service_tasklet); + mutex_lock(&channel_lock); + list_add(&channelPriv->entry, &channel_list); + mutex_unlock(&channel_lock); + tasklet_enable(&cmld_service_tasklet); + + file->private_data = channelPriv; // store channel private struct in file descriptor + } + return 0; +} + +/** Driver's release method. + * Frees any per-process pending resource: components, bindings, memory areas. + * + * \return POSIX error code + */ +static int cmld_release(struct inode *inode, struct file *file) +{ + struct cm_process_priv* procPriv; + + /* The driver must guarantee that all related resources are released. + Thus all these checks below are necessary to release all remaining + resources still linked to this 'client', in case of abnormal process + exit. + => These are error cases ! + In the usual case, nothing should be done except the free of + the cmPriv itself + */ + + if (iminor(inode) != 0) { + struct cm_channel_priv* channelPriv; + channelPriv = file->private_data; + procPriv = channelPriv->proc; + + /* We don't need to synchronize here by using the skelListLock: + the list is only accessed during ioctl() and we can't be here + if an ioctl() is on-going */ + if (list_empty(&channelPriv->skelList)) { + /* There is no pending MPC->HOST binding + => we can quietly delete the channel */ + tasklet_disable(&cmld_service_tasklet); + mutex_lock(&channel_lock); + list_del(&channelPriv->entry); + mutex_unlock(&channel_lock); + tasklet_enable(&cmld_service_tasklet); + + /* Free all remaining messages if any */ + freeMessages(channelPriv); + + /* Free the per-channel descriptor */ + OSAL_Free(channelPriv); + } else { + /* Uh: there are still some MPC->HOST binding but we don't have the + required info to unbind them. + => we must keep all skel structures because possibly used in OSAL_PostDfc + (incoming callback msg) */ + /* We flag the channel as closed to discard any new msg that will never be read anyway */ + channelPriv->state = CHANNEL_CLOSED; + + /* Already Free all remaining messages if any, + they will never be read anyway */ + freeMessages(channelPriv); + } + } else + procPriv = file->private_data; + + kref_put(&procPriv->ref, freeProcessPriv); + file->private_data = NULL; + + return 0; +} + /** Reads Component Manager messages destinated to this process. * The message is composed by three fields: * 1) mpc2host handle (distinguishes interfaces) @@ -242,16 +347,19 @@ static void freeProcessPriv(struct kref *ref) * \note cfr GetEvent() * \return POSIX error code */ -static ssize_t cmld_channel_read(struct file *file, char *buf, size_t count, loff_t *ppos) +static ssize_t cmld_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int err = 0; - struct cm_channel_priv* channelPriv = file->private_data; + struct cm_channel_priv* channelPriv = (struct cm_channel_priv*)(file->private_data); int msgSize = 0; struct plist_head* messageQueue; struct osal_msg* msg; t_os_message *os_msg = (t_os_message *)buf; int block = !(file->f_flags & O_NONBLOCK); + if (iminor(file->f_dentry->d_inode) == 0) + return -ENOSYS; + messageQueue = &channelPriv->messageQueue; if (mutex_lock_killable(&channelPriv->msgQueueLock)) @@ -263,7 +371,7 @@ wait: if (block == 0) return -EAGAIN; /* Wait until there is a message to ferry up */ - if (wait_event_killable(channelPriv->waitq, ((!plist_head_empty(messageQueue)) || (file->f_flags & O_FLUSH)))) + if (wait_event_interruptible(channelPriv->waitq, ((!plist_head_empty(messageQueue)) || (file->f_flags & O_FLUSH)))) return -ERESTARTSYS; if (file->f_flags & O_FLUSH) { file->f_flags &= ~O_FLUSH; @@ -351,21 +459,19 @@ out: * * \return POSIX error code */ -static int cmld_channel_flush(struct file *file, fl_owner_t id) +static int cmld_flush(struct file *file, fl_owner_t id) { - struct cm_channel_priv* channelPriv = file->private_data; - file->f_flags |= O_FLUSH; - wake_up(&channelPriv->waitq); + if (iminor(file->f_dentry->d_inode) != 0) { + struct cm_channel_priv* channelPriv = (struct cm_channel_priv*)(file->private_data); + file->f_flags |= O_FLUSH; + wake_up_interruptible(&channelPriv->waitq); + } return 0; } -static long cmld_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long cmld_channel_ctl(struct file *file, unsigned int cmd, unsigned long arg) { struct cm_channel_priv *channelPriv = file->private_data; -#ifdef CONFIG_DEBUG_FS - if (wait_event_killable(dump_waitq, (!cmld_dump_ongoing))) - return -ERESTARTSYS; -#endif switch(cmd) { /* @@ -374,7 +480,7 @@ static long cmld_channel_ioctl(struct file *file, unsigned int cmd, unsigned lon case CM_BINDCOMPONENTTOCMCORE: return cmld_BindComponentToCMCore(channelPriv, (CM_BindComponentToCMCore_t *)arg); case CM_FLUSHCHANNEL: - return cmld_channel_flush(file, 0); + return cmld_flush(file, 0); default: pr_err("CM(%s): unsupported command %i\n", __func__, cmd); return -EINVAL; @@ -382,18 +488,9 @@ static long cmld_channel_ioctl(struct file *file, unsigned int cmd, unsigned lon return 0; } -static long cmld_control_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long cmld_control_ctl(struct file *file, unsigned int cmd, unsigned long arg) { struct cm_process_priv* procPriv = file->private_data; -#ifdef CONFIG_DEBUG_FS - if (cmd == CM_PRIV_DEBUGFS_DUMP_DONE) { - cmld_dump_ongoing = false; - wake_up(&dump_waitq); - return 0; - } else if (wait_event_killable(dump_waitq, (!cmld_dump_ongoing))) - return -ERESTARTSYS; -#endif - switch(cmd) { /* * All wrapped CM SYSCALL @@ -598,6 +695,7 @@ static long cmld_control_ioctl(struct file *file, unsigned int cmd, unsigned lon cmld_user_has_debugfs = true; #endif return 0; + case CM_PRIV_DEBUGFS_DUMP_DONE: case CM_PRIV_DEBUGFS_WAIT_DUMP: return 0; default: @@ -608,6 +706,29 @@ static long cmld_control_ioctl(struct file *file, unsigned int cmd, unsigned lon return 0; } +/** Driver's ioctl method + * Implements user/kernel crossing for SYSCALL API. + * + * \return POSIX error code + */ +static long cmld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ +#ifdef CONFIG_DEBUG_FS + if (cmd == CM_PRIV_DEBUGFS_DUMP_DONE) { + cmld_dump_ongoing = false; + wake_up_interruptible(&dump_waitq); + return 0; + } else if (wait_event_interruptible(dump_waitq, (!cmld_dump_ongoing))) + return -ERESTARTSYS; +#endif + + if (iminor(filp->f_dentry->d_inode) == 0) { + return cmld_control_ctl(filp, cmd, arg); + } else { + return cmld_channel_ctl(filp, cmd, arg); + } +} + /** VMA open callback function */ static void cmld_vma_open(struct vm_area_struct* vma) { @@ -634,7 +755,7 @@ static struct vm_operations_struct cmld_remap_vm_ops = { * * \return POSIX error code */ -static int cmld_control_mmap(struct file *file, struct vm_area_struct *vma) +static int cmld_mmap(struct file* file, struct vm_area_struct* vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct list_head* listHead; @@ -706,278 +827,6 @@ static int cmld_control_mmap(struct file *file, struct vm_area_struct *vma) return 0; } -/* Driver's release method for /dev/cm_channel */ -static int cmld_channel_release(struct inode *inode, struct file *file) -{ - struct cm_channel_priv* channelPriv = file->private_data; - struct cm_process_priv* procPriv = channelPriv->proc; - - /* - * The driver must guarantee that all related resources are released. - * Thus all these checks below are necessary to release all remaining - * resources still linked to this 'client', in case of abnormal process - * exit. - * => These are error cases ! - * In the usual case, nothing should be done except the free of - * the cmPriv itself - */ - - /* We don't need to synchronize here by using the skelListLock: - the list is only accessed during ioctl() and we can't be here - if an ioctl() is on-going */ - if (list_empty(&channelPriv->skelList)) { - /* There is no pending MPC->HOST binding - => we can quietly delete the channel */ - tasklet_disable(&cmld_service_tasklet); - mutex_lock(&channel_lock); - list_del(&channelPriv->entry); - mutex_unlock(&channel_lock); - tasklet_enable(&cmld_service_tasklet); - - /* Free all remaining messages if any */ - freeMessages(channelPriv); - - /* Free the per-channel descriptor */ - OSAL_Free(channelPriv); - } else { - /* - * Uh: there are still some MPC->HOST binding but we don't have - * the required info to unbind them. - * => we must keep all skel structures because possibly used in - * OSAL_PostDfc (incoming callback msg). We flag the channel as - * closed to discard any new msg that will never be read anyway - */ - channelPriv->state = CHANNEL_CLOSED; - - /* Already Free all remaining messages if any, - they will never be read anyway */ - freeMessages(channelPriv); - } - - kref_put(&procPriv->ref, freeProcessPriv); - file->private_data = NULL; - - return 0; -} - -/* Driver's release method for /dev/cm_control */ -static int cmld_control_release(struct inode *inode, struct file *file) -{ - struct cm_process_priv* procPriv = file->private_data; - - kref_put(&procPriv->ref, freeProcessPriv); - file->private_data = NULL; - - return 0; -} - -static struct file_operations cmld_control_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = cmld_control_ioctl, - .mmap = cmld_control_mmap, - .release = cmld_control_release, -}; - -static int cmld_control_open(struct file *file) -{ - struct cm_process_priv *procPriv = getProcessPriv(); - if (IS_ERR(procPriv)) - return PTR_ERR(procPriv); - file->private_data = procPriv; - file->f_op = &cmld_control_fops; - return 0; -} - -static struct file_operations cmld_channel_fops = { - .owner = THIS_MODULE, - .read = cmld_channel_read, - .unlocked_ioctl = cmld_channel_ioctl, - .flush = cmld_channel_flush, - .release = cmld_channel_release, -}; - -static int cmld_channel_open(struct file *file) -{ - struct cm_process_priv *procPriv = getProcessPriv(); - struct cm_channel_priv *channelPriv; - - if (IS_ERR(procPriv)) - return PTR_ERR(procPriv); - - channelPriv = (struct cm_channel_priv*)OSAL_Alloc(sizeof(*channelPriv)); - if (channelPriv == NULL) { - kref_put(&procPriv->ref, freeProcessPriv); - return -ENOMEM; - } - - channelPriv->proc = procPriv; - channelPriv->state = CHANNEL_OPEN; - - /* Initialize wait_queue, lists and mutexes */ - init_waitqueue_head(&channelPriv->waitq); - plist_head_init(&channelPriv->messageQueue); - INIT_LIST_HEAD(&channelPriv->skelList); - spin_lock_init(&channelPriv->bh_lock); - mutex_init(&channelPriv->msgQueueLock); - mutex_init(&channelPriv->skelListLock); - - tasklet_disable(&cmld_service_tasklet); - mutex_lock(&channel_lock); - list_add(&channelPriv->entry, &channel_list); - mutex_unlock(&channel_lock); - tasklet_enable(&cmld_service_tasklet); - - file->private_data = channelPriv; - file->f_op = &cmld_channel_fops; - return 0; -} - -static ssize_t cmld_sxa_trace_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct mpcConfig *mpc = file->private_data; - size_t written = 0; - struct t_nmf_trace trace; - t_cm_trace_type traceType; - struct mmdsp_trace mmdsp_tr = { - .media = TB_MEDIA_FILE, - .receiver_dev = TB_DEV_PC, - .sender_dev = TB_DEV_TRACEBOX, - .unused = TB_TRACEBOX, - .receiver_obj = DEFAULT_RECEIVERR_OBJ, - .sender_obj = DEFAULT_SENDER_OBJ, - .transaction_id = 0, - .message_id = TB_TRACE_MSG, - .master_id = mpc->coreId+1, - .channel_id = 0, - .ost_version = OST_VERSION, - .entity = ENTITY, - .protocol_id = PROTOCOL_ID, - .btrace_hdr_flag = 0, - .btrace_hdr_subcategory = 0, - }; - - while ((count - written) >= sizeof(mmdsp_tr)) { - traceType = CM_ENGINE_GetNextTrace(mpc->coreId, &trace); - - switch (traceType) { - case CM_MPC_TRACE_READ_OVERRUN: - mmdsp_tr.size = - cpu_to_be16(offsetof(struct mmdsp_trace, - ost_version) - -offsetof(struct mmdsp_trace, - receiver_obj)); - mmdsp_tr.message_id = TB_TRACE_EXCEPTION_MSG; - mmdsp_tr.ost_master_id = TB_EXCEPTION_LONG_OVRF_PACKET; - if (copy_to_user(&buf[written], &mmdsp_tr, - offsetof(struct mmdsp_trace, - ost_version))) - return -EFAULT; - written += offsetof(struct mmdsp_trace, ost_version); - if ((count - written) < sizeof(mmdsp_tr)) - break; - case CM_MPC_TRACE_READ: { - u16 param_nr = (u16)trace.paramOpt; - u16 handle_valid = (u16)(trace.paramOpt >> 16); - u32 to_write = offsetof(struct mmdsp_trace, - parent_handle); - mmdsp_tr.transaction_id = trace.revision%256; - mmdsp_tr.message_id = TB_TRACE_MSG; - mmdsp_tr.ost_master_id = OST_MASTERID; - mmdsp_tr.timestamp = cpu_to_be64(trace.timeStamp); - mmdsp_tr.timestamp2 = cpu_to_be64(trace.timeStamp); - mmdsp_tr.component_id = cpu_to_be32(trace.componentId); - mmdsp_tr.trace_id = cpu_to_be32(trace.traceId); - mmdsp_tr.btrace_hdr_category = (trace.traceId>>16)&0xFF; - mmdsp_tr.btrace_hdr_size = BTRACE_HEADER_SIZE - + sizeof(trace.params[0]) * param_nr; - if (handle_valid) { - mmdsp_tr.parent_handle = trace.parentHandle; - mmdsp_tr.component_handle = - trace.componentHandle; - to_write += sizeof(trace.parentHandle) - + sizeof(trace.componentHandle); - mmdsp_tr.btrace_hdr_size += - sizeof(trace.parentHandle) - + sizeof(trace.componentHandle); - } - mmdsp_tr.size = - cpu_to_be16(to_write - + (sizeof(trace.params[0])*param_nr) - - offsetof(struct mmdsp_trace, - receiver_obj)); - mmdsp_tr.length = to_write - + (sizeof(trace.params[0])*param_nr) - - offsetof(struct mmdsp_trace, - timestamp2); - if (copy_to_user(&buf[written], &mmdsp_tr, to_write)) - return -EFAULT; - written += to_write; - /* write param */ - to_write = sizeof(trace.params[0]) * param_nr; - if (copy_to_user(&buf[written], trace.params, to_write)) - return -EFAULT; - written += to_write; - break; - } - case CM_MPC_TRACE_NONE: - default: - if ((file->f_flags & O_NONBLOCK) || written) - return written; - spin_lock_bh(&mpc->trace_reader_lock); - mpc->trace_reader = current; - spin_unlock_bh(&mpc->trace_reader_lock); - schedule_timeout_killable(msecs_to_jiffies(200)); - spin_lock_bh(&mpc->trace_reader_lock); - mpc->trace_reader = NULL; - spin_unlock_bh(&mpc->trace_reader_lock); - if (signal_pending(current)) - return -ERESTARTSYS; - } - } - return written; -} - -/* Driver's release method for /dev/cm_sxa_trace */ -static int cmld_sxa_trace_release(struct inode *inode, struct file *file) -{ - struct mpcConfig *mpc = file->private_data; - atomic_dec(&mpc->trace_read_count); - return 0; -} - -static struct file_operations cmld_sxa_trace_fops = { - .owner = THIS_MODULE, - .read = cmld_sxa_trace_read, - .release = cmld_sxa_trace_release, -}; - -static int cmld_sxa_trace_open(struct file *file, struct mpcConfig *mpc) -{ - if (atomic_add_unless(&mpc->trace_read_count, 1, 1) == 0) - return -EBUSY; - - file->private_data = mpc; - file->f_op = &cmld_sxa_trace_fops; - return 0; -} - -/* driver open() call: specific */ -static int cmld_open(struct inode *inode, struct file *file) -{ - switch (iminor(inode)) { - case 0: - return cmld_control_open(file); - case 1: - return cmld_channel_open(file); - case 2: - return cmld_sxa_trace_open(file, &osalEnv.mpc[SIA]); - case 3: - return cmld_sxa_trace_open(file, &osalEnv.mpc[SVA]); - default: - return -ENOSYS; - } -} - /** MPC Events tasklet * The parameter is used to know from which interrupts we're comming * and which core to pass to CM_ProcessMpcEvent(): @@ -1033,7 +882,12 @@ static irqreturn_t panic_handler(int irq, void *idx) */ static struct file_operations cmld_fops = { .owner = THIS_MODULE, + .read = cmld_read, + .unlocked_ioctl = cmld_ioctl, + .mmap = cmld_mmap, .open = cmld_open, + .flush = cmld_flush, + .release = cmld_release, }; /** |