summaryrefslogtreecommitdiff
path: root/drivers/staging/nmf-cm/cmld.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/nmf-cm/cmld.c')
-rw-r--r--drivers/staging/nmf-cm/cmld.c448
1 files changed, 297 insertions, 151 deletions
diff --git a/drivers/staging/nmf-cm/cmld.c b/drivers/staging/nmf-cm/cmld.c
index ef9753de7a4..53e07cd3137 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 117
+#define CMDRIVER_PATCH_VERSION 122
#define O_FLUSH 0x1000000
static int cmld_major;
@@ -233,111 +233,6 @@ 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)
@@ -347,19 +242,16 @@ static int cmld_release(struct inode *inode, struct file *file)
* \note cfr GetEvent()
* \return POSIX error code
*/
-static ssize_t cmld_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+static ssize_t cmld_channel_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
int err = 0;
- struct cm_channel_priv* channelPriv = (struct cm_channel_priv*)(file->private_data);
+ struct cm_channel_priv* channelPriv = 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))
@@ -459,19 +351,21 @@ out:
*
* \return POSIX error code
*/
-static int cmld_flush(struct file *file, fl_owner_t id)
+static int cmld_channel_flush(struct file *file, fl_owner_t id)
{
- 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);
- }
+ struct cm_channel_priv* channelPriv = file->private_data;
+ file->f_flags |= O_FLUSH;
+ wake_up(&channelPriv->waitq);
return 0;
}
-static long cmld_channel_ctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long cmld_channel_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct cm_channel_priv *channelPriv = file->private_data;
+#ifdef CONFIG_DEBUG_FS
+ if (wait_event_interruptible(dump_waitq, (!cmld_dump_ongoing)))
+ return -ERESTARTSYS;
+#endif
switch(cmd) {
/*
@@ -480,7 +374,7 @@ static long cmld_channel_ctl(struct file *file, unsigned int cmd, unsigned long
case CM_BINDCOMPONENTTOCMCORE:
return cmld_BindComponentToCMCore(channelPriv, (CM_BindComponentToCMCore_t *)arg);
case CM_FLUSHCHANNEL:
- return cmld_flush(file, 0);
+ return cmld_channel_flush(file, 0);
default:
pr_err("CM(%s): unsupported command %i\n", __func__, cmd);
return -EINVAL;
@@ -488,9 +382,18 @@ static long cmld_channel_ctl(struct file *file, unsigned int cmd, unsigned long
return 0;
}
-static long cmld_control_ctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long cmld_control_ioctl(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_interruptible(dump_waitq, (!cmld_dump_ongoing)))
+ return -ERESTARTSYS;
+#endif
+
switch(cmd) {
/*
* All wrapped CM SYSCALL
@@ -695,7 +598,6 @@ static long cmld_control_ctl(struct file *file, unsigned int cmd, unsigned long
cmld_user_has_debugfs = true;
#endif
return 0;
- case CM_PRIV_DEBUGFS_DUMP_DONE:
case CM_PRIV_DEBUGFS_WAIT_DUMP:
return 0;
default:
@@ -706,29 +608,6 @@ static long cmld_control_ctl(struct file *file, unsigned int cmd, unsigned long
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) {
@@ -755,7 +634,7 @@ static struct vm_operations_struct cmld_remap_vm_ops = {
*
* \return POSIX error code
*/
-static int cmld_mmap(struct file* file, struct vm_area_struct* vma)
+static int cmld_control_mmap(struct file *file, struct vm_area_struct *vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
struct list_head* listHead;
@@ -827,6 +706,278 @@ static int cmld_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():
@@ -882,12 +1033,7 @@ 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,
};
/**