From vijaykumar@bravegnu.org Mon Oct 26 15:02:07 2009 From: vijaykumar@bravegnu.org Date: Mon, 21 Sep 2009 11:23:55 +0530 Subject: Staging: poch: Fetch Flush IOCTL interface To: greg@kroah.com Cc: jayakumar.lkml@gmail.com, alexey.zaytsev@gmail.com Message-ID: <20090921055913.884674616@bravegnu.org> From: Vijay Kumar B. Change user space interface to an IOCTL based interface instead of a memory mapped circular buffer. The circular buffer had some serious cache(?) issues and never worked. Signed-off-by: Vijay Kumar B. Signed-off-by: Greg Kroah-Hartman --- drivers/staging/poch/poch.c | 58 ++++++++++++++++++++++++++++++++++++++++++-- drivers/staging/poch/poch.h | 9 ++++++ 2 files changed, 65 insertions(+), 2 deletions(-) --- a/drivers/staging/poch/poch.c +++ b/drivers/staging/poch/poch.c @@ -201,6 +201,8 @@ struct channel_info { struct page *header_pg; unsigned long header_size; + /* Last group consumed by user space. */ + unsigned int consumed; /* Last group indicated as 'complete' to user space. */ unsigned int transfer; @@ -589,6 +591,7 @@ static int poch_channel_init(struct chan if (ret != 0) goto out; + channel->consumed = 0; channel->transfer = 0; /* Allocate memory to hold group information. */ @@ -1033,6 +1036,51 @@ static int poch_ioctl(struct inode *inod break; } break; + case POCH_IOC_CONSUME: + { + int available; + int nfetch; + unsigned int from; + unsigned int count; + unsigned int i, j; + struct poch_consume consume; + struct poch_consume *uconsume; + + uconsume = argp; + ret = copy_from_user(&consume, uconsume, sizeof(consume)); + if (ret) + return ret; + + spin_lock_irq(&channel->group_offsets_lock); + + channel->consumed += consume.nflush; + channel->consumed %= channel->group_count; + + available = channel->transfer - channel->consumed; + if (available < 0) + available += channel->group_count; + + from = channel->consumed; + + spin_unlock_irq(&channel->group_offsets_lock); + + nfetch = consume.nfetch; + count = min(available, nfetch); + + for (i = 0; i < count; i++) { + j = (from + i) % channel->group_count; + ret = put_user(channel->groups[j].user_offset, + &consume.offsets[i]); + if (ret) + return -EFAULT; + } + + ret = put_user(count, &uconsume->nfetch); + if (ret) + return -EFAULT; + + break; + } case POCH_IOC_GET_COUNTERS: if (!access_ok(VERIFY_WRITE, argp, sizeof(struct poch_counters))) return -EFAULT; @@ -1108,12 +1156,18 @@ static void poch_irq_dma(struct channel_ for (i = 0; i < groups_done; i++) { j = (prev_transfer + i) % channel->group_count; group_offsets[j] = groups[j].user_offset; + + channel->transfer += 1; + channel->transfer %= channel->group_count; + + if (channel->transfer == channel->consumed) { + channel->consumed += 1; + channel->consumed %= channel->group_count; + } } spin_unlock(&channel->group_offsets_lock); - channel->transfer = curr_transfer; - wake_up_interruptible(&channel->wq); } --- a/drivers/staging/poch/poch.h +++ b/drivers/staging/poch/poch.h @@ -19,6 +19,12 @@ struct poch_counters { __u32 pll_unlock; }; +struct poch_consume { + __u32 __user *offsets; + __u32 nfetch; + __u32 nflush; +}; + #define POCH_IOC_NUM '9' #define POCH_IOC_TRANSFER_START _IO(POCH_IOC_NUM, 0) @@ -27,3 +33,6 @@ struct poch_counters { struct poch_counters) #define POCH_IOC_SYNC_GROUP_FOR_USER _IO(POCH_IOC_NUM, 3) #define POCH_IOC_SYNC_GROUP_FOR_DEVICE _IO(POCH_IOC_NUM, 4) + +#define POCH_IOC_CONSUME _IOWR(POCH_IOC_NUM, 5, \ + struct poch_consume)