Commit 024765d0 authored by Hiroshi DOYU's avatar Hiroshi DOYU Committed by Tony Lindgren

DSPGW: Use kfifo APIs instead of homemade ones

Signed-off-by: default avatarHiroshi DOYU <Hiroshi.DOYU@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 1a8db668
/*
* This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
*
* Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
*
* Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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 St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __PLAT_OMAP_DSP_FIFO_H
#define __PLAT_OMAP_DSP_FIFO_H
struct fifo_struct {
spinlock_t lock;
char *buf;
size_t sz;
size_t cnt;
unsigned int wp;
};
static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz)
{
if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) {
fifo->sz = 0;
return -ENOMEM;
}
fifo->sz = sz;
fifo->cnt = 0;
fifo->wp = 0;
return 0;
}
static inline int init_fifo(struct fifo_struct *fifo, size_t sz)
{
spin_lock_init(&fifo->lock);
return alloc_fifo(fifo, sz);
}
static inline void free_fifo(struct fifo_struct *fifo)
{
spin_lock(&fifo->lock);
if (fifo->buf == NULL) {
spin_unlock(&fifo->lock);
return;
}
kfree(fifo->buf);
fifo->buf = NULL;
fifo->sz = 0;
spin_unlock(&fifo->lock);
}
static inline void flush_fifo(struct fifo_struct *fifo)
{
spin_lock(&fifo->lock);
fifo->cnt = 0;
fifo->wp = 0;
spin_unlock(&fifo->lock);
}
#define fifo_empty(fifo) ((fifo)->cnt == 0)
static inline int realloc_fifo(struct fifo_struct *fifo, size_t sz)
{
int ret = sz;
spin_lock(&fifo->lock);
if (!fifo_empty(fifo)) {
ret = -EBUSY;
goto out;
}
/* free */
if (fifo->buf)
kfree(fifo->buf);
/* alloc */
ret = alloc_fifo(fifo, sz);
out:
spin_unlock(&fifo->lock);
return ret;
}
static inline void write_word_to_fifo(struct fifo_struct *fifo, u16 word)
{
spin_lock(&fifo->lock);
*(u16 *)&fifo->buf[fifo->wp] = word;
if ((fifo->wp += 2) == fifo->sz)
fifo->wp = 0;
if ((fifo->cnt += 2) > fifo->sz)
fifo->cnt = fifo->sz;
spin_unlock(&fifo->lock);
}
/*
* (before)
*
* [*******----------*************]
* ^wp
* <----------------------------> sz = 30
* <-----> <-----------> cnt = 20
*
* (read: count=16)
* <-> <-----------> count = 16
* <-----------> cnt1 = 13
* ^rp
*
* (after)
* [---****-----------------------]
* ^wp
*/
static inline ssize_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo,
size_t count)
{
int rp;
ssize_t ret;
/* fifo size can be zero */
if (fifo->sz == 0)
return 0;
spin_lock(&fifo->lock);
if (count > fifo->cnt)
count = fifo->cnt;
if ((rp = fifo->wp - fifo->cnt) >= 0) {
/* valid area is straight */
if (copy_to_user(dst, &fifo->buf[rp], count)) {
ret = -EFAULT;
goto out;
}
} else {
int cnt1 = -rp;
rp += fifo->sz;
if (cnt1 >= count) {
/* requested area is straight */
if (copy_to_user(dst, &fifo->buf[rp], count)) {
ret = -EFAULT;
goto out;
}
} else {
if (copy_to_user(dst, &fifo->buf[rp], cnt1)) {
ret = -EFAULT;
goto out;
}
if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) {
ret = -EFAULT;
goto out;
}
}
}
fifo->cnt -= count;
ret = count;
out:
spin_unlock(&fifo->lock);
return ret;
}
#endif /* __PLAT_OMAP_DSP_FIFO_H */
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/mailbox.h> #include <asm/arch/mailbox.h>
...@@ -41,7 +42,6 @@ ...@@ -41,7 +42,6 @@
#include "dsp_mbcmd.h" #include "dsp_mbcmd.h"
#include "dsp.h" #include "dsp.h"
#include "ipbuf.h" #include "ipbuf.h"
#include "fifo.h"
#include "proclist.h" #include "proclist.h"
#define is_aligned(adr,align) (!((adr)&((align)-1))) #define is_aligned(adr,align) (!((adr)&((align)-1)))
...@@ -125,8 +125,9 @@ struct taskdev { ...@@ -125,8 +125,9 @@ struct taskdev {
/* read stuff */ /* read stuff */
wait_queue_head_t read_wait_q; wait_queue_head_t read_wait_q;
struct mutex read_mutex; struct mutex read_mutex;
spinlock_t read_lock;
union { union {
struct fifo_struct fifo; /* for active word */ struct kfifo *fifo; /* for active word */
struct rcvdt_bk_struct bk; struct rcvdt_bk_struct bk;
} rcvdt; } rcvdt;
...@@ -356,7 +357,7 @@ static int taskdev_flush_buf(struct taskdev *dev) ...@@ -356,7 +357,7 @@ static int taskdev_flush_buf(struct taskdev *dev)
if (sndtyp_wd(ttyp)) { if (sndtyp_wd(ttyp)) {
/* word receiving */ /* word receiving */
flush_fifo(&dev->rcvdt.fifo); kfifo_reset(dev->rcvdt.fifo);
} else { } else {
/* block receiving */ /* block receiving */
struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk; struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
...@@ -379,7 +380,6 @@ static int taskdev_flush_buf(struct taskdev *dev) ...@@ -379,7 +380,6 @@ static int taskdev_flush_buf(struct taskdev *dev)
static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz) static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
{ {
u16 ttyp = dev->task->ttyp; u16 ttyp = dev->task->ttyp;
int stat;
if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) { if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
printk(KERN_ERR printk(KERN_ERR
...@@ -393,15 +393,18 @@ static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz) ...@@ -393,15 +393,18 @@ static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
return -EINVAL; return -EINVAL;
} }
stat = realloc_fifo(&dev->rcvdt.fifo, sz); if (kfifo_len(dev->rcvdt.fifo)) {
if (stat == -EBUSY) {
printk(KERN_ERR "omapdsp: buffer is not empty!\n"); printk(KERN_ERR "omapdsp: buffer is not empty!\n");
return stat; return -EIO;
} else if (stat < 0) { }
kfifo_free(dev->rcvdt.fifo);
dev->rcvdt.fifo = kfifo_alloc(sz, GFP_KERNEL, &dev->read_lock);
if (IS_ERR(dev->rcvdt.fifo)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: unable to change receive buffer size. " "omapdsp: unable to change receive buffer size. "
"(%ld bytes for %s)\n", sz, dev->name); "(%ld bytes for %s)\n", sz, dev->name);
return stat; return -ENOMEM;
} }
return 0; return 0;
...@@ -670,10 +673,10 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf, ...@@ -670,10 +673,10 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&dev->read_wait_q, &wait, TASK_INTERRUPTIBLE);
if (fifo_empty(&dev->rcvdt.fifo)) if (kfifo_len(dev->rcvdt.fifo) == 0)
schedule(); schedule();
finish_wait(&dev->read_wait_q, &wait); finish_wait(&dev->read_wait_q, &wait);
if (fifo_empty(&dev->rcvdt.fifo)) { if (kfifo_len(dev->rcvdt.fifo) == 0) {
/* failure */ /* failure */
if (signal_pending(current)) if (signal_pending(current))
ret = -EINTR; ret = -EINTR;
...@@ -681,7 +684,7 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf, ...@@ -681,7 +684,7 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
} }
ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count); ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
up_out: up_out:
taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
...@@ -837,14 +840,14 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf, ...@@ -837,14 +840,14 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q); mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
if (fifo_empty(&dev->rcvdt.fifo)) { if (kfifo_len(dev->rcvdt.fifo) == 0) {
/* failure */ /* failure */
if (signal_pending(current)) if (signal_pending(current))
ret = -EINTR; ret = -EINTR;
goto up_out; goto up_out;
} }
ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count); ret = kfifo_get_to_user(dev->rcvdt.fifo, buf, count);
up_out: up_out:
taskdev_unlock_and_stateunlock(dev, &dev->read_mutex); taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
...@@ -1125,7 +1128,7 @@ static unsigned int dsp_task_poll(struct file * file, poll_table * wait) ...@@ -1125,7 +1128,7 @@ static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
poll_wait(file, &dev->read_wait_q, wait); poll_wait(file, &dev->read_wait_q, wait);
poll_wait(file, &dev->write_wait_q, wait); poll_wait(file, &dev->write_wait_q, wait);
if (sndtyp_psv(task->ttyp) || if (sndtyp_psv(task->ttyp) ||
(sndtyp_wd(task->ttyp) && !fifo_empty(&dev->rcvdt.fifo)) || (sndtyp_wd(task->ttyp) && kfifo_len(dev->rcvdt.fifo)) ||
(sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link))) (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
mask |= POLLIN | POLLRDNORM; mask |= POLLIN | POLLRDNORM;
if (dev->wsz) if (dev->wsz)
...@@ -1815,11 +1818,11 @@ static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task) ...@@ -1815,11 +1818,11 @@ static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
/* sndtyp_bk */ dsp_task_read_bk_psv; /* sndtyp_bk */ dsp_task_read_bk_psv;
if (sndtyp_wd(ttyp)) { if (sndtyp_wd(ttyp)) {
/* word */ /* word */
size_t fifosz; size_t fifosz = sndtyp_psv(ttyp) ? 2:32; /* passive:active */
fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */ dev->rcvdt.fifo = kfifo_alloc(fifosz, GFP_KERNEL,
32; /* active */ &dev->read_lock);
if (init_fifo(&dev->rcvdt.fifo, fifosz) < 0) { if (IS_ERR(dev->rcvdt.fifo)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: unable to allocate receive buffer. " "omapdsp: unable to allocate receive buffer. "
"(%d bytes for %s)\n", fifosz, dev->name); "(%d bytes for %s)\n", fifosz, dev->name);
...@@ -1896,7 +1899,7 @@ static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task) ...@@ -1896,7 +1899,7 @@ static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
taskdev_flush_buf(dev); taskdev_flush_buf(dev);
if (sndtyp_wd(ttyp)) if (sndtyp_wd(ttyp))
free_fifo(&dev->rcvdt.fifo); kfifo_free(dev->rcvdt.fifo);
dev->task = NULL; dev->task = NULL;
...@@ -1923,7 +1926,7 @@ static void taskdev_detach_task(struct taskdev *dev) ...@@ -1923,7 +1926,7 @@ static void taskdev_detach_task(struct taskdev *dev)
dev->fops.read = NULL; dev->fops.read = NULL;
taskdev_flush_buf(dev); taskdev_flush_buf(dev);
if (sndtyp_wd(ttyp)) if (sndtyp_wd(ttyp))
free_fifo(&dev->rcvdt.fifo); kfifo_free(dev->rcvdt.fifo);
dev->fops.write = NULL; dev->fops.write = NULL;
dev->wsz = 0; dev->wsz = 0;
...@@ -2246,7 +2249,9 @@ long taskdev_state_stale(unsigned char minor) ...@@ -2246,7 +2249,9 @@ long taskdev_state_stale(unsigned char minor)
*/ */
void mbox_wdsnd(struct mbcmd *mb) void mbox_wdsnd(struct mbcmd *mb)
{ {
unsigned int n;
u8 tid = mb->cmd_l; u8 tid = mb->cmd_l;
u16 data = mb->data;
struct dsptask *task = dsptask[tid]; struct dsptask *task = dsptask[tid];
if ((tid >= TASKDEV_MAX) || (task == NULL)) { if ((tid >= TASKDEV_MAX) || (task == NULL)) {
...@@ -2266,7 +2271,11 @@ void mbox_wdsnd(struct mbcmd *mb) ...@@ -2266,7 +2271,11 @@ void mbox_wdsnd(struct mbcmd *mb)
return; return;
} }
write_word_to_fifo(&task->dev->rcvdt.fifo, mb->data); n = kfifo_put(task->dev->rcvdt.fifo, (unsigned char *)&data,
sizeof(data));
if (n != sizeof(data))
printk(KERN_WARNING "Receive FIFO(%d) is full\n", tid);
wake_up_interruptible(&task->dev->read_wait_q); wake_up_interruptible(&task->dev->read_wait_q);
} }
...@@ -2883,8 +2892,8 @@ static ssize_t ttyp_show(struct device *d, struct device_attribute *attr, ...@@ -2883,8 +2892,8 @@ static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
static ssize_t fifosz_show(struct device *d, struct device_attribute *attr, static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo; struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
return sprintf(buf, "%d\n", fifo->sz); return sprintf(buf, "%d\n", fifo->size);
} }
static int fifosz_store(struct device *d, struct device_attribute *attr, static int fifosz_store(struct device *d, struct device_attribute *attr,
...@@ -2895,7 +2904,10 @@ static int fifosz_store(struct device *d, struct device_attribute *attr, ...@@ -2895,7 +2904,10 @@ static int fifosz_store(struct device *d, struct device_attribute *attr,
int ret; int ret;
fifosz = simple_strtol(buf, NULL, 10); fifosz = simple_strtol(buf, NULL, 10);
if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
return -ENODEV;
ret = taskdev_set_fifosz(dev, fifosz); ret = taskdev_set_fifosz(dev, fifosz);
taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
return (ret < 0) ? ret : strlen(buf); return (ret < 0) ? ret : strlen(buf);
} }
...@@ -2904,8 +2916,8 @@ static int fifosz_store(struct device *d, struct device_attribute *attr, ...@@ -2904,8 +2916,8 @@ static int fifosz_store(struct device *d, struct device_attribute *attr,
static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr, static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo; struct kfifo *fifo = to_taskdev(d)->rcvdt.fifo;
return sprintf(buf, "%d\n", fifo->cnt); return sprintf(buf, "%d\n", fifo->size);
} }
/* ipblink */ /* ipblink */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment