/*
- * linux/arch/arm/mach-omap/dsp/ipbuf.c
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
*
- * IPBUF handler
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
*
- * Copyright (C) 2002-2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
- * Written by 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 free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
*
- * 2005/06/06: DSP Gateway version 3.3
*/
-#include <linux/init.h>
#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
#include <linux/device.h>
-#include <asm/signal.h>
-#include <asm/arch/dsp.h>
+#include <asm/arch/mailbox.h>
+#include "dsp_mbcmd.h"
#include "dsp.h"
#include "ipbuf.h"
-struct ipbuf **ipbuf;
+static struct ipbuf_head *g_ipbuf;
struct ipbcfg ipbcfg;
struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
static struct ipblink ipb_free = IPBLINK_INIT;
static int ipbuf_sys_hold_mem_active;
+static ssize_t ipbuf_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);
+
void ipbuf_stop(void)
{
int i;
+ device_remove_file(&dsp_device.dev, &dev_attr_ipbuf);
+
spin_lock(&ipb_free.lock);
- INIT_IPBLINK(&ipb_free);
+ RESET_IPBLINK(&ipb_free);
spin_unlock(&ipb_free.lock);
ipbcfg.ln = 0;
- if (ipbuf) {
- kfree(ipbuf);
- ipbuf = NULL;
+ if (g_ipbuf) {
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
}
for (i = 0; i < ipbuf_sys_hold_mem_active; i++) {
dsp_mem_disable((void *)daram_base);
ipbuf_sys_hold_mem_active = 0;
}
-int ipbuf_config(unsigned short ln, unsigned short lsz, void *base)
+int ipbuf_config(u16 ln, u16 lsz, void *base)
{
- unsigned long lsz_byte = ((unsigned long)lsz) << 1;
+ size_t lsz_byte = ((size_t)lsz) << 1;
size_t size;
int ret = 0;
int i;
if (dsp_address_validate(base, size, "global ipbuf") < 0)
return -EINVAL;
- ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL);
- if (ipbuf == NULL) {
+ g_ipbuf = kmalloc(sizeof(struct ipbuf_head) * ln, GFP_KERNEL);
+ if (g_ipbuf == NULL) {
printk(KERN_ERR
"omapdsp: memory allocation for ipbuf failed.\n");
return -ENOMEM;
top = base + (sizeof(struct ipbuf) + lsz_byte) * i;
btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1;
- ipbuf[i] = (struct ipbuf *)top;
+ g_ipbuf[i].p = (struct ipbuf *)top;
+ g_ipbuf[i].bid = i;
if (((unsigned long)top & 0xfffe0000) !=
((unsigned long)btm & 0xfffe0000)) {
/*
*/
printk(KERN_ERR
"omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
- " @0x%p, size=0x%08lx\n", i, top, lsz_byte);
+ " @0x%p, size=0x%08x\n", i, top, lsz_byte);
ret = -EINVAL;
goto free_out;
}
" %d words * %d lines at 0x%p.\n",
ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
+ device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
+
return ret;
free_out:
- kfree(ipbuf);
- ipbuf = NULL;
+ kfree(g_ipbuf);
+ g_ipbuf = NULL;
return ret;
}
-int ipbuf_sys_config(void *p, enum arm_dsp_dir dir)
+int ipbuf_sys_config(void *p, enum arm_dsp_dir_e dir)
{
char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
ipbuf_sys_da = p;
else
ipbuf_sys_ad = p;
-
+
return 0;
}
-int ipbuf_p_validate(void *p, enum arm_dsp_dir dir)
+int ipbuf_p_validate(void *p, enum arm_dsp_dir_e dir)
{
char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
/*
* Global IPBUF operations
*/
-unsigned short get_free_ipbuf(unsigned char tid)
+struct ipbuf_head *bid_to_ipbuf(u16 bid)
{
- unsigned short bid;
+ return &g_ipbuf[bid];
+}
+
+struct ipbuf_head *get_free_ipbuf(u8 tid)
+{
+ struct ipbuf_head *ipb_h;
if (dsp_mem_enable_ipbuf() < 0)
- return OMAP_DSP_BID_NULL;
+ return NULL;
spin_lock(&ipb_free.lock);
if (ipblink_empty(&ipb_free)) {
/* FIXME: wait on queue when not available. */
- bid = OMAP_DSP_BID_NULL;
+ ipb_h = NULL;
goto out;
}
- bid = ipb_free.top;
- ipbuf[bid]->la = tid; /* lock */
- ipblink_del_top(&ipb_free, ipbuf);
+ ipb_h = &g_ipbuf[ipb_free.top];
+ ipb_h->p->la = tid; /* lock */
+ __ipblink_del_top(&ipb_free);
out:
spin_unlock(&ipb_free.lock);
dsp_mem_disable_ipbuf();
- return bid;
+ return ipb_h;
}
-void release_ipbuf(unsigned short bid)
+void release_ipbuf(struct ipbuf_head *ipb_h)
{
- if (ipbuf[bid]->la == OMAP_DSP_TID_FREE) {
+ if (ipb_h->p->la == TID_FREE) {
printk(KERN_WARNING
"omapdsp: attempt to release unlocked IPBUF[%d].\n",
- bid);
+ ipb_h->bid);
/*
* FIXME: re-calc bsycnt
*/
return;
}
- ipbuf[bid]->la = OMAP_DSP_TID_FREE;
- ipbuf[bid]->sa = OMAP_DSP_TID_FREE;
- spin_lock(&ipb_free.lock);
- ipblink_add_tail(&ipb_free, bid, ipbuf);
- spin_unlock(&ipb_free.lock);
+ ipb_h->p->la = TID_FREE;
+ ipb_h->p->sa = TID_FREE;
+ ipblink_add_tail(&ipb_free, ipb_h->bid);
}
-static int try_yld(unsigned short bid)
+static int try_yld(struct ipbuf_head *ipb_h)
{
int status;
- ipbuf[bid]->sa = OMAP_DSP_TID_ANON;
- status = dsp_mbsend(MBCMD(BKYLD), 0, bid);
+ ipb_h->p->sa = TID_ANON;
+ status = mbcompose_send(BKYLD, 0, ipb_h->bid);
if (status < 0) {
/* DSP is busy and ARM keeps this line. */
- release_ipbuf(bid);
+ release_ipbuf(ipb_h);
return status;
}
static void do_balance_ipbuf(void)
{
while (ipbcfg.bsycnt <= ipbcfg.ln / 4) {
- unsigned short bid;
+ struct ipbuf_head *ipb_h;
- bid = get_free_ipbuf(OMAP_DSP_TID_ANON);
- if (bid == OMAP_DSP_BID_NULL)
+ if ((ipb_h = get_free_ipbuf(TID_ANON)) == NULL)
return;
- if (try_yld(bid) < 0)
+ if (try_yld(ipb_h) < 0)
return;
}
}
}
/* for process context */
-void unuse_ipbuf(unsigned short bid)
+void unuse_ipbuf(struct ipbuf_head *ipb_h)
{
if (ipbcfg.bsycnt > ipbcfg.ln / 4) {
/* we don't have enough IPBUF lines. let's keep it. */
- release_ipbuf(bid);
+ release_ipbuf(ipb_h);
} else {
/* we have enough IPBUF lines. let's return this line to DSP. */
- ipbuf[bid]->la = OMAP_DSP_TID_ANON;
- try_yld(bid);
+ ipb_h->p->la = TID_ANON;
+ try_yld(ipb_h);
balance_ipbuf();
}
}
/* for interrupt context */
-void unuse_ipbuf_nowait(unsigned short bid)
+void unuse_ipbuf_nowait(struct ipbuf_head *ipb_h)
{
- release_ipbuf(bid);
+ release_ipbuf(ipb_h);
balance_ipbuf();
}
/*
- * functions called from mailbox1 interrupt routine
+ * functions called from mailbox interrupt routine
*/
-void mbx1_err_ipbfull(void)
+void mbox_err_ipbfull(void)
{
ipbcfg.cnt_full++;
}
char *buf)
{
int len = 0;
- unsigned short bid;
+ u16 bid;
for (bid = 0; bid < ipbcfg.ln; bid++) {
- unsigned short la = ipbuf[bid]->la;
- unsigned short ld = ipbuf[bid]->ld;
- unsigned short c = ipbuf[bid]->c;
+ struct ipbuf_head *ipb_h = &g_ipbuf[bid];
+ u16 la = ipb_h->p->la;
+ u16 ld = ipb_h->p->ld;
+ u16 c = ipb_h->p->c;
if (len > PAGE_SIZE - 100) {
len += sprintf(buf + len, "out of buffer.\n");
}
len += sprintf(buf + len, "ipbuf[%d]: adr = 0x%p\n",
- bid, ipbuf[bid]);
- if (la == OMAP_DSP_TID_FREE) {
+ bid, ipb_h->p);
+ if (la == TID_FREE) {
len += sprintf(buf + len,
" DSPtask[%d]->Linux "
"(already read and now free for Linux)\n",
ld);
- } else if (ld == OMAP_DSP_TID_FREE) {
+ } else if (ld == TID_FREE) {
len += sprintf(buf + len,
" Linux->DSPtask[%d] "
"(already read and now free for DSP)\n",
len += sprintf(buf + len, "\nFree IPBUF link: ");
spin_lock(&ipb_free.lock);
- ipblink_for_each(bid, &ipb_free, ipbuf) {
+ ipblink_for_each(bid, &ipb_free) {
len += sprintf(buf + len, "%d ", bid);
}
spin_unlock(&ipb_free.lock);
finish:
return len;
}
-
-struct device_attribute dev_attr_ipbuf = __ATTR_RO(ipbuf);