]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00291658 PXP: allow PXP device users to submit multiple tasks before start PXP
authorFancy Fang <B47543@freescale.com>
Wed, 11 Dec 2013 06:22:35 +0000 (14:22 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 20 Aug 2014 08:06:48 +0000 (10:06 +0200)
After the commit "ffcad666548417ef21937e0a755d85ab922313a9" pushed,
adding this support in PXP device driver is also necessary. This
change allows users to submit more than one PXP tasks followd by
only one wait for finished ioctl. It means that users can wait for
more than one tasks done by calling one PXP_IOC_WAIT4CMPLT ioctl.

Signed-off-by: Fancy Fang <B47543@freescale.com>
drivers/dma/pxp/pxp_device.c
include/linux/pxp_dma.h

index d05b06df0c9026d7da38810a2468c4a518711123..efe1eeb41e6e6141801904f3c8c7576cba82ae45 100644 (file)
@@ -51,7 +51,6 @@ struct memalloc_record {
 };
 
 struct pxp_chan_info {
-       int chan_id;
        struct dma_chan *dma_chan;
        struct list_head list;
 };
@@ -104,11 +103,14 @@ static void pxp_dma_done(void *arg)
        struct dma_chan *chan = tx_desc->txd.chan;
        struct pxp_channel *pxp_chan = to_pxp_channel(chan);
        int chan_id = pxp_chan->dma_chan.chan_id;
+       unsigned long flags;
 
        pr_debug("DMA Done ISR, chan_id %d\n", chan_id);
 
-       irq_info[chan_id].irq_pending++;
+       spin_lock_irqsave(&(irq_info[chan_id].lock), flags);
+       irq_info[chan_id].irq_pending--;
        irq_info[chan_id].hist_status = tx_desc->hist_status;
+       spin_unlock_irqrestore(&(irq_info[chan_id].lock), flags);
 
        wake_up_interruptible(&(irq_info[chan_id].waitq));
 }
@@ -123,6 +125,7 @@ static int pxp_ioc_config_chan(unsigned long arg)
        dma_cookie_t cookie;
        int chan_id;
        int i, length, ret;
+       unsigned long flags;
 
        ret = copy_from_user(&pxp_conf,
                             (struct pxp_config_data *)arg,
@@ -134,8 +137,6 @@ static int pxp_ioc_config_chan(unsigned long arg)
        if (chan_id < 0 || chan_id >= NR_PXP_VIRT_CHANNEL)
                return -ENODEV;
 
-       init_waitqueue_head(&(irq_info[chan_id].waitq));
-
        /* find the channel */
        spin_lock(&pxp_chan_lock);
        list_for_each_entry(info, &list, list) {
@@ -191,6 +192,10 @@ static int pxp_ioc_config_chan(unsigned long arg)
                return -EIO;
        }
 
+       spin_lock_irqsave(&(irq_info[chan_id].lock), flags);
+       irq_info[chan_id].irq_pending++;
+       spin_unlock_irqrestore(&(irq_info[chan_id].lock), flags);
+
        return 0;
 }
 
@@ -283,6 +288,7 @@ static long pxp_device_ioctl(struct file *filp,
                        list_add_tail(&info->list, &list);
                        spin_unlock(&pxp_chan_lock);
 
+                       init_waitqueue_head(&(irq_info[info->dma_chan->chan_id].waitq));
                        if (put_user
                            (info->dma_chan->chan_id, (u32 __user *) arg))
                                return -EFAULT;
@@ -320,7 +326,6 @@ static long pxp_device_ioctl(struct file *filp,
                }
        case PXP_IOC_CONFIG_CHAN:
                {
-
                        int ret;
 
                        ret = pxp_ioc_config_chan(arg);
@@ -373,14 +378,14 @@ static long pxp_device_ioctl(struct file *filp,
                                kfree(rec);
                                printk(KERN_ERR
                                       "Physical memory allocation error!\n");
-                               break;
+                               return ret;
                        }
                        ret = copy_to_user((void __user *)arg, &(rec->mem),
                                           sizeof(struct pxp_mem_desc));
                        if (ret) {
                                kfree(rec);
                                ret = -EFAULT;
-                               break;
+                               return ret;
                        }
 
                        spin_lock(&pxp_mem_lock);
@@ -435,13 +440,12 @@ static long pxp_device_ioctl(struct file *filp,
 
                        ret = wait_event_interruptible
                            (irq_info[chan_id].waitq,
-                            (irq_info[chan_id].irq_pending != 0));
+                            (irq_info[chan_id].irq_pending == 0));
                        if (ret < 0) {
                                printk(KERN_WARNING
-                                      "pxp interrupt received.\n");
+                                      "WAIT4CMPLT: signal received.\n");
                                return -ERESTARTSYS;
-                       } else
-                               irq_info[chan_id].irq_pending--;
+                       }
 
                        chan_handle.hist_status = irq_info[chan_id].hist_status;
                        ret = copy_to_user((struct pxp_chan_handle *)arg,
@@ -473,12 +477,15 @@ static struct miscdevice pxp_device_miscdev = {
 
 int register_pxp_device(void)
 {
-       int ret;
+       int i, ret;
 
        ret = misc_register(&pxp_device_miscdev);
        if (ret)
                return ret;
 
+       for (i = 0; i < NR_PXP_VIRT_CHANNEL; i++)
+               spin_lock_init(&(irq_info[i].lock));
+
        pr_debug("PxP_Device registered Successfully\n");
        return 0;
 }
index 41c8a39042c32f443c9202b71e7e2401455cc4ca..61b3e7de4c5784e2a19483290a72261511533f61 100644 (file)
@@ -58,6 +58,7 @@ struct pxp_irq_info {
        wait_queue_head_t waitq;
        int irq_pending;
        int hist_status;
+       spinlock_t lock;
 };
 
 #define to_tx_desc(tx) container_of(tx, struct pxp_tx_desc, txd)