Commit b3ddf280 authored by Toshiro Kobayashi's avatar Toshiro Kobayashi Committed by Tony Lindgren

[PATCH] ARM: OMAP: DSP Gateway v3.3

This is DSP Gateway v3.3 patch.
parent 76330285
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/01/21: DSP Gateway version 3.2 * 2005/06/09: DSP Gateway version 3.3
*/ */
#include "hardware_dsp.h" #include "hardware_dsp.h"
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifdef OLD_BINARY_SUPPORT #ifdef OLD_BINARY_SUPPORT
#define MBREV_3_0 0x0017 #define MBREV_3_0 0x0017
#define MBREV_3_2 0x0018
#endif #endif
#define DSP_INIT_PAGE 0xfff000 #define DSP_INIT_PAGE 0xfff000
...@@ -38,6 +39,22 @@ ...@@ -38,6 +39,22 @@
#define IDLEPG_BASE 0xfffe00 #define IDLEPG_BASE 0xfffe00
#define IDLEPG_SIZE 0x100 #define IDLEPG_SIZE 0x100
/* timeout value for DSP response */
#define DSP_TIMEOUT (10 * HZ)
enum dsp_mem_type_e {
MEM_TYPE_CROSSING = -1,
MEM_TYPE_NONE = 0,
MEM_TYPE_DARAM,
MEM_TYPE_SARAM,
MEM_TYPE_EXTERN,
};
enum arm_dsp_dir {
DIR_A2D,
DIR_D2A,
};
/* /*
* INT_D2A_MB value definition * INT_D2A_MB value definition
* INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox * INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox
...@@ -49,8 +66,22 @@ ...@@ -49,8 +66,22 @@
#define TASKDEV_MAX 254 #define TASKDEV_MAX 254
#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw)) #define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw))
#define MKVIRT(uw,lw) dspword_to_virt(MKLONG((uw), (lw)));
#define MBCMD(nm) OMAP_DSP_MBCMD_##nm #define MBCMD(nm) OMAP_DSP_MBCMD_##nm
struct sync_seq {
unsigned short da_dsp;
unsigned short da_arm;
unsigned short ad_dsp;
unsigned short ad_arm;
};
struct mem_sync_struct {
struct sync_seq *DARAM;
struct sync_seq *SARAM;
struct sync_seq *SDRAM;
};
/* struct mbcmd and struct mbcmd_hw must be compatible */ /* struct mbcmd and struct mbcmd_hw must be compatible */
struct mbcmd { struct mbcmd {
unsigned short cmd_l:8; unsigned short cmd_l:8;
...@@ -79,26 +110,32 @@ struct mb_exarg { ...@@ -79,26 +110,32 @@ struct mb_exarg {
extern void dsp_mb_start(void); extern void dsp_mb_start(void);
extern void dsp_mb_stop(void); extern void dsp_mb_stop(void);
extern void dsp_mb_config(void *sync_seq_adr); extern int dsp_mb_config(void *p);
extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid, extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid,
int try_cnt); int try_cnt);
extern int __mbsend(struct mbcmd *mb); extern int __mbcmd_send(struct mbcmd *mb);
extern int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, extern int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg,
int recovery_flag); int recovery_flag);
#define dsp_mbsend(mb) __dsp_mbsend(mb, NULL, 0) #define dsp_mbcmd_send(mb) __dsp_mbcmd_send(mb, NULL, 0)
#define dsp_mbsend_recovery(mb) __dsp_mbsend(mb, NULL, 1) #define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send(mb, arg, 0)
#define dsp_mbsend_exarg(mb, arg) __dsp_mbsend(mb, arg, 0) extern int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
extern int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, wait_queue_head_t *q);
wait_queue_head_t *q); #define dsp_mbcmd_send_and_wait(mb, q) \
#define dsp_mbsend_and_wait(mb, q) \ __dsp_mbcmd_send_and_wait(mb, NULL, q)
__dsp_mbsend_and_wait(mb, NULL, q) #define dsp_mbcmd_send_and_wait_exarg(mb, arg, q) \
#define dsp_mbsend_and_wait_exarg(mb, arg, q) \ __dsp_mbcmd_send_and_wait(mb, arg, q)
__dsp_mbsend_and_wait(mb, arg, q) int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
int recovery_flag);
#define dsp_mbsend(cmdh, cmdl, data) \
__dsp_mbsend(cmdh, cmdl, data, 0)
#define dsp_mbsend_recovery(cmdh, cmdl, data) \
__dsp_mbsend(cmdh, cmdl, data, 1)
extern void ipbuf_start(void); extern void ipbuf_start(void);
extern void ipbuf_stop(void); extern void ipbuf_stop(void);
extern int ipbuf_config(unsigned short ln, unsigned short lsz, extern int ipbuf_config(unsigned short ln, unsigned short lsz, void *base);
unsigned long adr); extern int ipbuf_sys_config(void *p, enum arm_dsp_dir dir);
extern int ipbuf_p_validate(void *p, enum arm_dsp_dir dir);
extern unsigned short get_free_ipbuf(unsigned char tid); extern unsigned short get_free_ipbuf(unsigned char tid);
extern void unuse_ipbuf_nowait(unsigned short bid); extern void unuse_ipbuf_nowait(unsigned short bid);
extern void unuse_ipbuf(unsigned short bid); extern void unuse_ipbuf(unsigned short bid);
...@@ -110,6 +147,8 @@ extern void balance_ipbuf(void); ...@@ -110,6 +147,8 @@ extern void balance_ipbuf(void);
(ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \ (ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \
} while(0) } while(0)
extern int mbx_revision;
extern int dsp_is_ready(void); extern int dsp_is_ready(void);
extern int dspuncfg(void); extern int dspuncfg(void);
extern void dsp_runlevel(unsigned char level); extern void dsp_runlevel(unsigned char level);
...@@ -125,16 +164,24 @@ extern int dsp_rmdev(char *name); ...@@ -125,16 +164,24 @@ extern int dsp_rmdev(char *name);
extern int dsp_tadd(unsigned char minor, unsigned long adr); extern int dsp_tadd(unsigned char minor, unsigned long adr);
extern int dsp_tdel(unsigned char minor); extern int dsp_tdel(unsigned char minor);
extern int dsp_tkill(unsigned char minor); extern int dsp_tkill(unsigned char minor);
extern long taskdev_state(unsigned char minor); extern long taskdev_state_stale(unsigned char minor);
extern int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz);
extern void dsp_dbg_stop(void);
extern int ipbuf_is_held(unsigned char tid, unsigned short bid); extern int ipbuf_is_held(unsigned char tid, unsigned short bid);
extern void dsp_mem_sync_inc(void);
extern int dsp_mem_sync_config(struct mem_sync_struct *sync);
extern enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len);
extern int dsp_address_validate(void *p, size_t len, char *fmt, ...);
extern int dsp_mem_enable(void *adr); extern int dsp_mem_enable(void *adr);
extern int dsp_mem_disable(void *adr); extern void dsp_mem_disable(void *adr);
extern int __dsp_mem_enable(void *adr); extern void dsp_mem_usecount_clear(void);
extern int __dsp_mem_disable(void *adr); extern void exmap_use(void *vadr, size_t len);
extern void exmap_unuse(void *vadr, size_t len);
extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len); extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len);
extern void dsp_mem_start(void); extern void dsp_mem_start(void);
extern void dsp_mem_stop(void);
extern void dsp_twch_start(void); extern void dsp_twch_start(void);
extern void dsp_twch_stop(void); extern void dsp_twch_stop(void);
...@@ -165,14 +212,9 @@ extern const struct cmdinfo *cmdinfo[]; ...@@ -165,14 +212,9 @@ extern const struct cmdinfo *cmdinfo[];
#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name) #define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name)
extern char *subcmd_name(struct mbcmd *mb); extern char *subcmd_name(struct mbcmd *mb);
enum mblog_dir { extern void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir);
MBLOG_DIR_AD,
MBLOG_DIR_DA,
};
extern void mblog_add(struct mbcmd *mb, enum mblog_dir dir);
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE #ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
extern void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir); extern void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir);
#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ #else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
#define mblog_printcmd(mb, dir) do {} while(0) #define mblog_printcmd(mb, dir) do {} while(0)
#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ #endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/11/19: DSP Gateway version 3.2 * 2005/06/13: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -40,14 +40,28 @@ ...@@ -40,14 +40,28 @@
struct clk *dsp_ck_handle; struct clk *dsp_ck_handle;
struct clk *api_ck_handle; struct clk *api_ck_handle;
unsigned long dspmem_base, dspmem_size; unsigned long dspmem_base, dspmem_size,
int dsp_runstat = RUNSTAT_RESET; daram_base, daram_size,
unsigned short dsp_icrmask = DSPREG_ICR_EMIF_IDLE_DOMAIN | saram_base, saram_size;
DSPREG_ICR_DPLL_IDLE_DOMAIN |
DSPREG_ICR_PER_IDLE_DOMAIN | struct cpustat {
DSPREG_ICR_CACHE_IDLE_DOMAIN | struct semaphore sem;
DSPREG_ICR_DMA_IDLE_DOMAIN | enum e_cpustat stat;
DSPREG_ICR_CPU_IDLE_DOMAIN; enum e_cpustat req;
unsigned short icrmask;
struct {
int mpui;
int mem;
int mem_delayed;
} usecount;
int (*mem_req_cb)(void);
void (*mem_rel_cb)(void);
};
struct cpustat cpustat = {
.sem = __MUTEX_INITIALIZER(cpustat.sem),
.stat = CPUSTAT_RESET,
.icrmask = 0xffff,
};
int dsp_set_rstvect(unsigned long adr) int dsp_set_rstvect(unsigned long adr)
{ {
...@@ -88,22 +102,59 @@ static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len) ...@@ -88,22 +102,59 @@ static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len)
} }
/* program size must be multiple of 2 */ /* program size must be multiple of 2 */
#define IDLE_TEXT_SIZE 28 #define GBL_IDLE_TEXT_SIZE 52
#define IDLE_TEXT(icr) { \ #define GBL_IDLE_TEXT_INIT { \
/* SAM */ \
0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \
0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \
/* disable WDT */ \ /* disable WDT */ \
0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: mov AR3 0x3404 */ \ 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: mov *AR3 0x00f5 */ \ 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
0x9a, /* 0x9a: port */ \ 0x9a, /* 0x9a: PORT */ \
0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: mov *AR3 0x00a0 */ \ 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
0x9a, /* 0x9a: port */ \ 0x9a, /* 0x9a: PORT */ \
/* *IER0 = 0, *IER1 = 0 */ \
0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
/* *ICR = 0xffff */ \
0x3c, 0x1b, /* 0x3c1b: MOV 0x1, AR3 */ \
0xfb, 0x61, 0xff, 0xff, /* 0xfb61ffff: MOV 0xffff, *AR3 */ \
0x9a, /* 0x9a: PORT */ \
/* HOM */ \
0xf5, 0x41, 0x03, 0x00, /* 0xf5410300: OR 0x0300, *AR2 */ \
/* idle and loop forever */ \
0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
0x20, 0x20, 0x20, /* 0x20: NOP */ \
}
/* program size must be multiple of 2 */
#define CPU_IDLE_TEXT_SIZE 48
#define CPU_IDLE_TEXT_INIT(icrh, icrl) { \
/* SAM */ \
0x3c, 0x4b, /* 0x3c4b: MOV 0x4, AR3 */ \
0xf4, 0x61, 0xfc, 0xff, /* 0xf461fcff: AND 0xfcff, *AR3 */ \
/* disable WDT */ \
0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: MOV 0x3404, AR3 */ \
0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: MOV 0x00f5, *AR3 */ \
0x9a, /* 0x9a: PORT */ \
0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: MOV 0x00a0, *AR3 */ \
0x9a, /* 0x9a: PORT */ \
/* *IER0 = 0, *IER1 = 0 */ \
0x3c, 0x0b, /* 0x3c0b: MOV 0x0, AR3 */ \
0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
0x76, 0x00, 0x45, 0xb8, /* 0x76004508: MOV 0x45, AR3 */ \
0xe6, 0x61, 0x00, /* 0xe66100: MOV 0, *AR3 */ \
/* set ICR = icr */ \ /* set ICR = icr */ \
0x3c, 0x1b, /* 0x3c1b: mov AR3 0x1 */ \ 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \
0xe6, 0x61, (icr), /* 0xe661**: mov *AR3, icr */ \ 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \
0x9a, /* 0x9a: port */ \ 0x9a, /* 0x9a: PORT */ \
/* idle and loop forever */ \ /* idle and loop forever */ \
0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: idle */ \ 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \
0x4a, 0x7a, /* 0x4a7a: b -6 (infinite loop) */ \ 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \
0x20, 0x20 /* 0x20: nop */ \ 0x20, 0x20, 0x20 /* 0x20: nop */ \
} }
/* /*
...@@ -115,38 +166,57 @@ static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len) ...@@ -115,38 +166,57 @@ static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len)
*/ */
static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI; static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI;
void dsp_idle(void) static void dsp_gbl_idle(void)
{
unsigned char idle_text[GBL_IDLE_TEXT_SIZE] = GBL_IDLE_TEXT_INIT;
__dsp_reset();
clk_use(api_ck_handle);
#if 0
omap_writew(MPUI_DSP_BOOT_CONFIG_IDLE, MPUI_DSP_BOOT_CONFIG);
#endif
simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
GBL_IDLE_TEXT_SIZE);
if (idle_boot_base == DSP_BOOT_ADR_MPUI)
omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
else
dsp_set_rstvect(idle_boot_base);
__dsp_run();
udelay(100); /* to make things stable */
clk_unuse(api_ck_handle);
}
static void dsp_cpu_idle(void)
{ {
unsigned char icr; unsigned short icr_tmp;
unsigned char icrh, icrl;
disable_irq(INT_DSP_MMU);
preempt_disable();
__dsp_reset(); __dsp_reset();
clk_use(api_ck_handle); clk_use(api_ck_handle);
/* /*
* icr settings: * icr settings:
* DMA should not sleep for DARAM/SARAM access * DMA should not sleep for DARAM/SARAM access
* DPLL should not sleep for DMA. * DPLL should not sleep while any other domain is active
*/ */
icr = dsp_icrmask & icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA_IDLE_DOMAIN |
~(DSPREG_ICR_DMA_IDLE_DOMAIN | DSPREG_ICR_DPLL_IDLE_DOMAIN) & DSPREG_ICR_DPLL_IDLE_DOMAIN);
0xff; icrh = icr_tmp >> 8;
icrl = icr_tmp & 0xff;
{ {
unsigned char idle_text[IDLE_TEXT_SIZE] = IDLE_TEXT(icr); unsigned char idle_text[CPU_IDLE_TEXT_SIZE] = CPU_IDLE_TEXT_INIT(icrh, icrl);
simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base), simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base),
IDLE_TEXT_SIZE); CPU_IDLE_TEXT_SIZE);
} }
if (idle_boot_base == DSP_BOOT_ADR_MPUI) if (idle_boot_base == DSP_BOOT_ADR_MPUI)
omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG); omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG);
else else
dsp_set_rstvect(idle_boot_base); dsp_set_rstvect(idle_boot_base);
clk_unuse(api_ck_handle);
udelay(10); /* to make things stable */
__dsp_run(); __dsp_run();
dsp_runstat = RUNSTAT_IDLE; udelay(100); /* to make things stable */
preempt_enable(); clk_unuse(api_ck_handle);
enable_irq(INT_DSP_MMU);
} }
void dsp_set_idle_boot_base(unsigned long adr, size_t size) void dsp_set_idle_boot_base(unsigned long adr, size_t size)
...@@ -154,13 +224,18 @@ void dsp_set_idle_boot_base(unsigned long adr, size_t size) ...@@ -154,13 +224,18 @@ void dsp_set_idle_boot_base(unsigned long adr, size_t size)
if (adr == idle_boot_base) if (adr == idle_boot_base)
return; return;
idle_boot_base = adr; idle_boot_base = adr;
if (size < IDLE_TEXT_SIZE) { if ((size < GBL_IDLE_TEXT_SIZE) ||
(size < CPU_IDLE_TEXT_SIZE)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: size for idle program is not enough!\n"); "omapdsp: size for idle program is not enough!\n");
BUG(); BUG();
} }
if (dsp_runstat == RUNSTAT_IDLE)
dsp_idle(); /* restart idle program with new base address */
if (cpustat.stat == CPUSTAT_GBL_IDLE)
dsp_gbl_idle();
if (cpustat.stat == CPUSTAT_CPU_IDLE)
dsp_cpu_idle();
} }
static unsigned short save_dsp_idlect2; static unsigned short save_dsp_idlect2;
...@@ -197,9 +272,10 @@ void omap_dsp_pm_resume(void) ...@@ -197,9 +272,10 @@ void omap_dsp_pm_resume(void)
omap_writew(save_arm_idlect2, ARM_IDLECT2); omap_writew(save_arm_idlect2, ARM_IDLECT2);
/* Run DSP, if it was running */ /* Run DSP, if it was running */
if (dsp_runstat != RUNSTAT_RESET) if (cpustat.stat != CPUSTAT_RESET)
__dsp_run(); __dsp_run();
} }
static int init_done; static int init_done;
static int __init omap_dsp_init(void) static int __init omap_dsp_init(void)
...@@ -209,12 +285,20 @@ static int __init omap_dsp_init(void) ...@@ -209,12 +285,20 @@ static int __init omap_dsp_init(void)
if (cpu_is_omap1510()) { if (cpu_is_omap1510()) {
dspmem_base = OMAP1510_DSP_BASE; dspmem_base = OMAP1510_DSP_BASE;
dspmem_size = OMAP1510_DSP_SIZE; dspmem_size = OMAP1510_DSP_SIZE;
daram_base = OMAP1510_DARAM_BASE;
daram_size = OMAP1510_DARAM_SIZE;
saram_base = OMAP1510_SARAM_BASE;
saram_size = OMAP1510_SARAM_SIZE;
} }
#endif #endif
#ifdef CONFIG_ARCH_OMAP16XX #ifdef CONFIG_ARCH_OMAP16XX
if (cpu_is_omap16xx()) { if (cpu_is_omap16xx()) {
dspmem_base = OMAP16XX_DSP_BASE; dspmem_base = OMAP16XX_DSP_BASE;
dspmem_size = OMAP16XX_DSP_SIZE; dspmem_size = OMAP16XX_DSP_SIZE;
daram_base = OMAP16XX_DARAM_BASE;
daram_size = OMAP16XX_DARAM_SIZE;
saram_base = OMAP16XX_SARAM_BASE;
saram_size = OMAP16XX_SARAM_SIZE;
} }
#endif #endif
if (dspmem_size == 0) { if (dspmem_size == 0) {
...@@ -243,31 +327,228 @@ static int __init omap_dsp_init(void) ...@@ -243,31 +327,228 @@ static int __init omap_dsp_init(void)
return 0; return 0;
} }
void omap_dsp_request_idle(void) static void dsp_cpustat_update(void)
{ {
if (dsp_runstat == RUNSTAT_RESET) { if (!init_done)
if (!init_done) omap_dsp_init();
omap_dsp_init();
dsp_idle(); if (cpustat.req == CPUSTAT_RUN) {
if (cpustat.stat < CPUSTAT_RUN) {
__dsp_reset();
clk_use(api_ck_handle);
udelay(10);
__dsp_run();
cpustat.stat = CPUSTAT_RUN;
enable_irq(INT_DSP_MMU);
}
return;
}
/* cpustat.stat < CPUSTAT_RUN */
if (cpustat.stat == CPUSTAT_RUN) {
disable_irq(INT_DSP_MMU);
clk_unuse(api_ck_handle);
}
/*
* (1) when ARM wants DARAM access, MPUI should be SAM and
* DSP needs to be on.
* (2) if any bits of icr is masked, we can not enter global idle.
*/
if ((cpustat.req == CPUSTAT_CPU_IDLE) ||
(cpustat.usecount.mem > 0) ||
(cpustat.usecount.mem_delayed > 0) ||
((cpustat.usecount.mpui > 0) && (cpustat.icrmask != 0xffff))) {
if (cpustat.stat != CPUSTAT_CPU_IDLE) {
dsp_cpu_idle();
cpustat.stat = CPUSTAT_CPU_IDLE;
}
return;
}
/*
* when ARM only needs MPUI access, MPUI can be HOM and
* DSP can be idling.
*/
if ((cpustat.req == CPUSTAT_GBL_IDLE) ||
(cpustat.usecount.mpui > 0)) {
if (cpustat.stat != CPUSTAT_GBL_IDLE) {
dsp_gbl_idle();
cpustat.stat = CPUSTAT_GBL_IDLE;
}
return;
}
/*
* no user, no request
*/
if (cpustat.stat != CPUSTAT_RESET) {
__dsp_reset();
cpustat.stat = CPUSTAT_RESET;
} }
} }
void dsp_cpustat_request(enum e_cpustat req)
{
down(&cpustat.sem);
cpustat.req = req;
dsp_cpustat_update();
up(&cpustat.sem);
}
enum e_cpustat dsp_cpustat_get_stat(void)
{
return cpustat.stat;
}
unsigned short dsp_cpustat_get_icrmask(void)
{
return cpustat.icrmask;
}
void dsp_cpustat_set_icrmask(unsigned short mask)
{
down(&cpustat.sem);
cpustat.icrmask = mask;
dsp_cpustat_update();
up(&cpustat.sem);
}
void omap_dsp_request_mpui(void)
{
down(&cpustat.sem);
if (cpustat.usecount.mpui++ == 0)
dsp_cpustat_update();
up(&cpustat.sem);
}
void omap_dsp_release_mpui(void)
{
down(&cpustat.sem);
if (cpustat.usecount.mpui-- == 0) {
printk(KERN_ERR
"omapdsp: unbalanced mpui request/release detected.\n"
" cpustat.usecount.mpui is going to be "
"less than zero! ... fixed to be zero.\n");
cpustat.usecount.mpui = 0;
}
if (cpustat.usecount.mpui == 0)
dsp_cpustat_update();
up(&cpustat.sem);
}
int omap_dsp_request_mem(void)
{
int ret = 0;
down(&cpustat.sem);
if ((cpustat.usecount.mem++ == 0) &&
(cpustat.usecount.mem_delayed == 0)) {
if (cpustat.mem_req_cb) {
if ((ret = cpustat.mem_req_cb()) < 0) {
cpustat.usecount.mem--;
goto out;
}
}
dsp_cpustat_update();
}
out:
up(&cpustat.sem);
return ret;
}
/*
* release_mem will be delayed.
*/
static void do_release_mem(void) {
down(&cpustat.sem);
cpustat.usecount.mem_delayed = 0;
if (cpustat.usecount.mem == 0) {
dsp_cpustat_update();
if (cpustat.mem_rel_cb)
cpustat.mem_rel_cb();
}
up(&cpustat.sem);
}
static DECLARE_WORK(mem_rel_work, (void (*)(void *))do_release_mem, NULL);
int omap_dsp_release_mem(void)
{
down(&cpustat.sem);
/* cancel previous release work */
cancel_delayed_work(&mem_rel_work);
cpustat.usecount.mem_delayed = 0;
if (cpustat.usecount.mem-- == 0) {
printk(KERN_ERR
"omapdsp: unbalanced memory request/release detected.\n"
" cpustat.usecount.mem is going to be "
"less than zero! ... fixed to be zero.\n");
cpustat.usecount.mem = 0;
}
if (cpustat.usecount.mem == 0) {
cpustat.usecount.mem_delayed = 1;
schedule_delayed_work(&mem_rel_work, HZ);
}
up(&cpustat.sem);
return 0;
}
void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void))
{
down(&cpustat.sem);
cpustat.mem_req_cb = req_cb;
cpustat.mem_rel_cb = rel_cb;
/*
* This function must be called while mem is enabled!
*/
BUG_ON(cpustat.usecount.mem == 0);
up(&cpustat.sem);
}
void dsp_unregister_mem_cb(void)
{
down(&cpustat.sem);
cpustat.mem_req_cb = NULL;
cpustat.mem_rel_cb = NULL;
up(&cpustat.sem);
}
arch_initcall(omap_dsp_init); arch_initcall(omap_dsp_init);
EXPORT_SYMBOL(omap_dsp_pm_suspend); EXPORT_SYMBOL(omap_dsp_pm_suspend);
EXPORT_SYMBOL(omap_dsp_pm_resume); EXPORT_SYMBOL(omap_dsp_pm_resume);
EXPORT_SYMBOL(omap_dsp_request_idle); EXPORT_SYMBOL(omap_dsp_request_mpui);
EXPORT_SYMBOL(omap_dsp_release_mpui);
EXPORT_SYMBOL(omap_dsp_request_mem);
EXPORT_SYMBOL(omap_dsp_release_mem);
#ifdef CONFIG_OMAP_DSP_MODULE #ifdef CONFIG_OMAP_DSP_MODULE
EXPORT_SYMBOL(dsp_ck_handle); EXPORT_SYMBOL(dsp_ck_handle);
EXPORT_SYMBOL(api_ck_handle); EXPORT_SYMBOL(api_ck_handle);
EXPORT_SYMBOL(dspmem_base); EXPORT_SYMBOL(dspmem_base);
EXPORT_SYMBOL(dspmem_size); EXPORT_SYMBOL(dspmem_size);
EXPORT_SYMBOL(dsp_runstat); EXPORT_SYMBOL(daram_base);
EXPORT_SYMBOL(dsp_icrmask); EXPORT_SYMBOL(daram_size);
EXPORT_SYMBOL(saram_base);
EXPORT_SYMBOL(saram_size);
EXPORT_SYMBOL(dsp_set_rstvect); EXPORT_SYMBOL(dsp_set_rstvect);
EXPORT_SYMBOL(dsp_idle);
EXPORT_SYMBOL(dsp_set_idle_boot_base); EXPORT_SYMBOL(dsp_set_idle_boot_base);
EXPORT_SYMBOL(dsp_cpustat_request);
EXPORT_SYMBOL(dsp_cpustat_get_stat);
EXPORT_SYMBOL(dsp_cpustat_get_icrmask);
EXPORT_SYMBOL(dsp_cpustat_set_icrmask);
EXPORT_SYMBOL(dsp_register_mem_cb);
EXPORT_SYMBOL(dsp_unregister_mem_cb);
EXPORT_SYMBOL(__cpu_flush_kern_tlb_range); EXPORT_SYMBOL(__cpu_flush_kern_tlb_range);
#endif #endif
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/11/16: DSP Gateway version 3.2 * 2005/06/13: DSP Gateway version 3.3
*/ */
#include "hardware_dsp.h" #include "hardware_dsp.h"
...@@ -52,28 +52,28 @@ ...@@ -52,28 +52,28 @@
* default setting: wordswap = all, byteswap = APIMEM only * default setting: wordswap = all, byteswap = APIMEM only
*/ */
#define mpui_wordswap_on() \ #define mpui_wordswap_on() \
{ \ do { \
omap_writel( \ omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \ MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \
} while(0) } while(0)
#define mpui_wordswap_off() \ #define mpui_wordswap_off() \
{ \ do { \
omap_writel( \ omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \
MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \ MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \
} while(0) } while(0)
#define mpui_byteswap_on() \ #define mpui_byteswap_on() \
{ \ do { \
omap_writel( \ omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \ MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \
} while(0) } while(0)
#define mpui_byteswap_off() \ #define mpui_byteswap_off() \
{ \ do { \
omap_writel( \ omap_writel( \
(omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \
MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \ MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \
...@@ -83,13 +83,13 @@ ...@@ -83,13 +83,13 @@
* TC wordswap on / off * TC wordswap on / off
*/ */
#define tc_wordswap() \ #define tc_wordswap() \
{ \ do { \
omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \ omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \
TC_ENDIANISM); \ TC_ENDIANISM); \
} while(0) } while(0)
#define tc_noswap() \ #define tc_noswap() \
{ \ do { \
omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \ omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \
TC_ENDIANISM); \ TC_ENDIANISM); \
} while(0) } while(0)
...@@ -102,16 +102,31 @@ ...@@ -102,16 +102,31 @@
#define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1) #define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
#define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1) #define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1)
#define RUNSTAT_RESET 0
#define RUNSTAT_IDLE 1
#define RUNSTAT_RUN 2
extern struct clk *dsp_ck_handle; extern struct clk *dsp_ck_handle;
extern struct clk *api_ck_handle; extern struct clk *api_ck_handle;
extern unsigned long dspmem_base, dspmem_size; extern unsigned long dspmem_base, dspmem_size,
extern int dsp_runstat; daram_base, daram_size,
extern unsigned short dsp_icrmask; saram_base, saram_size;
enum e_cpustat {
CPUSTAT_RESET = 0,
CPUSTAT_GBL_IDLE = 1,
CPUSTAT_CPU_IDLE = 2,
CPUSTAT_RUN = 3
};
#define cpustat_name(stat) \
((stat == CPUSTAT_RESET) ? "RESET" :\
(stat == CPUSTAT_GBL_IDLE) ? "GBL_IDLE" :\
(stat == CPUSTAT_CPU_IDLE) ? "CPU_IDLE" :\
(stat == CPUSTAT_RUN) ? "RUN" :\
"unknown")
int dsp_set_rstvect(unsigned long adr); int dsp_set_rstvect(unsigned long adr);
void dsp_idle(void);
void dsp_set_idle_boot_base(unsigned long adr, size_t size); void dsp_set_idle_boot_base(unsigned long adr, size_t size);
void dsp_cpustat_request(enum e_cpustat req);
enum e_cpustat dsp_cpustat_get_stat(void);
unsigned short dsp_cpustat_get_icrmask(void);
void dsp_cpustat_set_icrmask(unsigned short mask);
void dsp_register_mem_cb(int (*req_cb)(void), void (*rel_cb)(void));
void dsp_unregister_mem_cb(void);
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/15: DSP Gateway version 3.2 * 2005/06/07: DSP Gateway version 3.3
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -55,17 +55,11 @@ enum mbseq_check_level { ...@@ -55,17 +55,11 @@ enum mbseq_check_level {
}; };
static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE; static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE;
static unsigned short mbseq_send;
static unsigned short mbseq_expect;
struct sync_seq {
unsigned short da_dsp;
unsigned short da_arm;
unsigned short ad_dsp;
unsigned short ad_arm;
};
static struct sync_seq *sync_seq; static int mbx1_valid;
static struct sync_seq *mbseq;
static unsigned short mbseq_expect_tmp;
static unsigned short *mbseq_expect = &mbseq_expect_tmp;
/* /*
* mailbox commands * mailbox commands
...@@ -78,7 +72,11 @@ extern void mbx1_bkyld(struct mbcmd *mb); ...@@ -78,7 +72,11 @@ extern void mbx1_bkyld(struct mbcmd *mb);
extern void mbx1_bksndp(struct mbcmd *mb); extern void mbx1_bksndp(struct mbcmd *mb);
extern void mbx1_bkreqp(struct mbcmd *mb); extern void mbx1_bkreqp(struct mbcmd *mb);
extern void mbx1_tctl(struct mbcmd *mb); extern void mbx1_tctl(struct mbcmd *mb);
extern void mbx1_poll(struct mbcmd *mb);
#ifdef OLD_BINARY_SUPPORT
/* v3.3 obsolete */
extern void mbx1_wdt(struct mbcmd *mb); extern void mbx1_wdt(struct mbcmd *mb);
#endif
extern void mbx1_suspend(struct mbcmd *mb); extern void mbx1_suspend(struct mbcmd *mb);
static void mbx1_kfunc(struct mbcmd *mb); static void mbx1_kfunc(struct mbcmd *mb);
extern void mbx1_tcfg(struct mbcmd *mb); extern void mbx1_tcfg(struct mbcmd *mb);
...@@ -100,7 +98,11 @@ static const struct cmdinfo ...@@ -100,7 +98,11 @@ static const struct cmdinfo
cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp }, cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp },
cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp }, cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp },
cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl }, cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl },
cif_poll = { "POLL", CMD_L_TYPE_NULL, mbx1_poll },
#ifdef OLD_BINARY_SUPPORT
/* v3.3 obsolete */
cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_wdt }, cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_wdt },
#endif
cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL }, cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL },
cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL }, cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL },
cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend }, cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend },
...@@ -129,7 +131,7 @@ const struct cmdinfo *cmdinfo[128] = { ...@@ -129,7 +131,7 @@ const struct cmdinfo *cmdinfo[128] = {
&cif_bksndp, &cif_bkreqp, &cif_null, &cif_null, &cif_bksndp, &cif_bkreqp, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
/*30*/ &cif_tctl, &cif_null, &cif_null, &cif_null, /*30*/ &cif_tctl, &cif_null, &cif_poll, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
...@@ -137,7 +139,12 @@ const struct cmdinfo *cmdinfo[128] = { ...@@ -137,7 +139,12 @@ const struct cmdinfo *cmdinfo[128] = {
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
#ifdef OLD_BINARY_SUPPORT
/* v3.3 obsolete */
/*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend, /*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend,
#else
/*50*/ &cif_null, &cif_runlevel, &cif_pm, &cif_suspend,
#endif
&cif_kfunc, &cif_null, &cif_null, &cif_null, &cif_kfunc, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
&cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null, &cif_null,
...@@ -207,7 +214,7 @@ static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt) ...@@ -207,7 +214,7 @@ static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt)
#define print_mb_mmu_abort(mb) do {} while(0) #define print_mb_mmu_abort(mb) do {} while(0)
#endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */ #endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */
int __mbsend(struct mbcmd *mb) int __mbcmd_send(struct mbcmd *mb)
{ {
struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
unsigned long flags; unsigned long flags;
...@@ -220,12 +227,13 @@ int __mbsend(struct mbcmd *mb) ...@@ -220,12 +227,13 @@ int __mbsend(struct mbcmd *mb)
return -1; return -1;
} }
mb->seq = mbseq_send & 1; if (mbseq) {
mbseq_send++; mb->seq = mbseq->ad_arm;
if (sync_seq) mbseq->ad_arm++;
sync_seq->ad_arm = mbseq_send; } else
mblog_add(mb, MBLOG_DIR_AD); mb->seq = 0;
mblog_printcmd(mb, MBLOG_DIR_AD); mblog_add(mb, DIR_A2D);
mblog_printcmd(mb, DIR_A2D);
omap_writew(mb_hw->data, MAILBOX_ARM2DSP1); omap_writew(mb_hw->data, MAILBOX_ARM2DSP1);
omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b); omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b);
...@@ -235,9 +243,9 @@ int __mbsend(struct mbcmd *mb) ...@@ -235,9 +243,9 @@ int __mbsend(struct mbcmd *mb)
} }
/* /*
* __dsp_mbsend(): mailbox dispatcher * __dsp_mbcmd_send(): mailbox dispatcher
*/ */
int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
{ {
static DECLARE_MUTEX(mbsend_sem); static DECLARE_MUTEX(mbsend_sem);
int ret = 0; int ret = 0;
...@@ -257,10 +265,18 @@ int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) ...@@ -257,10 +265,18 @@ int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
if (arg) { /* we have extra argument */ if (arg) { /* we have extra argument */
int i; int i;
if (__dsp_mem_enable(ipbuf_sys_ad) < 0) /*
goto out; * even if ipbuf_sys_ad is in DSP internal memory,
* dsp_mem_enable() never cause to call PM mailbox command
* because in that case DSP memory should be always enabled.
* (see ipbuf_sys_hold_mem_active in ipbuf.c)
*
* Therefore, we can call this function here safely.
*/
dsp_mem_enable(ipbuf_sys_ad);
if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) { if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) {
printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n"); printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n");
dsp_mem_disable(ipbuf_sys_ad);
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
...@@ -268,19 +284,18 @@ int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) ...@@ -268,19 +284,18 @@ int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag)
ipbuf_sys_ad->d[i] = arg->argv[i]; ipbuf_sys_ad->d[i] = arg->argv[i];
} }
ipbuf_sys_ad->s = arg->tid; ipbuf_sys_ad->s = arg->tid;
if (__dsp_mem_disable(ipbuf_sys_ad) < 0) dsp_mem_disable(ipbuf_sys_ad);
goto out;
} }
ret = __mbsend(mb); ret = __mbcmd_send(mb);
out: out:
up(&mbsend_sem); up(&mbsend_sem);
return ret; return ret;
} }
int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
wait_queue_head_t *q) wait_queue_head_t *q)
{ {
long current_state; long current_state;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -288,36 +303,72 @@ int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, ...@@ -288,36 +303,72 @@ int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg,
add_wait_queue(q, &wait); add_wait_queue(q, &wait);
current_state = current->state; current_state = current->state;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (dsp_mbsend_exarg(mb, arg) < 0) { if (dsp_mbcmd_send_exarg(mb, arg) < 0) {
set_current_state(current_state); set_current_state(current_state);
remove_wait_queue(q, &wait); remove_wait_queue(q, &wait);
return -1; return -1;
} }
schedule(); schedule_timeout(DSP_TIMEOUT);
set_current_state(current_state); set_current_state(current_state);
remove_wait_queue(q, &wait); remove_wait_queue(q, &wait);
return 0; return 0;
} }
int __dsp_mbsend(unsigned char cmdh, unsigned char cmdl, unsigned short data,
int recovery_flag)
{
struct mbcmd mb;
mbcmd_set(mb, cmdh, cmdl, data);
return __dsp_mbcmd_send(&mb, NULL, recovery_flag);
}
static int mbsync_hold_mem_active;
void dsp_mb_start(void) void dsp_mb_start(void)
{ {
mbseq_send = 0; mbx1_valid = 1; /* start interpreting */
mbseq_expect = 0; mbseq_expect_tmp = 0;
} }
void dsp_mb_stop(void) void dsp_mb_stop(void)
{ {
sync_seq = NULL; mbx1_valid = 0; /* stop interpreting */
if (mbsync_hold_mem_active) {
dsp_mem_disable((void *)daram_base);
mbsync_hold_mem_active = 0;
}
mbseq = NULL;
mbseq_expect = &mbseq_expect_tmp;
} }
/* int dsp_mb_config(void *p)
* dsp_mb_config() is called from mbx1 workqueue
*/
void dsp_mb_config(void *sync_seq_adr)
{ {
sync_seq = sync_seq_adr; unsigned long flags;
sync_seq->da_arm = mbseq_expect;
if (dsp_address_validate(p, sizeof(struct sync_seq), "mbseq") < 0)
return -1;
if (dsp_mem_type(p, sizeof(struct sync_seq)) != MEM_TYPE_EXTERN) {
printk(KERN_WARNING
"omapdsp: mbseq is placed in DSP internal memory.\n"
" It will prevent DSP from idling.\n");
mbsync_hold_mem_active = 1;
/*
* dsp_mem_enable() never fails because
* it has been already enabled in dspcfg process and
* this will just increment the usecount.
*/
dsp_mem_enable((void *)daram_base);
}
local_irq_save(flags);
mbseq = p;
mbseq->da_arm = mbseq_expect_tmp;
mbseq_expect = &mbseq->da_arm;
local_irq_restore(flags);
return 0;
} }
/* /*
...@@ -351,8 +402,8 @@ static void do_mbx1(void) ...@@ -351,8 +402,8 @@ static void do_mbx1(void)
mb = &mbq.mb[mbq.rp]; mb = &mbq.mb[mbq.rp];
mblog_add(mb, MBLOG_DIR_DA); mblog_add(mb, DIR_D2A);
mblog_printcmd(mb, MBLOG_DIR_DA); mblog_printcmd(mb, DIR_D2A);
/* /*
* call handler for each command * call handler for each command
...@@ -386,7 +437,6 @@ static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL); ...@@ -386,7 +437,6 @@ static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL);
/* /*
* kernel function dispatcher * kernel function dispatcher
*/ */
#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
extern void mbx1_fbctl_disable(void); extern void mbx1_fbctl_disable(void);
static void mbx1_kfunc_fbctl(unsigned short data) static void mbx1_kfunc_fbctl(unsigned short data)
...@@ -400,16 +450,13 @@ static void mbx1_kfunc_fbctl(unsigned short data) ...@@ -400,16 +450,13 @@ static void mbx1_kfunc_fbctl(unsigned short data)
"mailbox: Unknown FBCTL from DSP: 0x%04x\n", data); "mailbox: Unknown FBCTL from DSP: 0x%04x\n", data);
} }
} }
#endif
static void mbx1_kfunc(struct mbcmd *mb) static void mbx1_kfunc(struct mbcmd *mb)
{ {
switch (mb->cmd_l) { switch (mb->cmd_l) {
#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
case OMAP_DSP_MBCMD_KFUNC_FBCTL: case OMAP_DSP_MBCMD_KFUNC_FBCTL:
mbx1_kfunc_fbctl(mb->data); mbx1_kfunc_fbctl(mb->data);
break; break;
#endif
default: default:
printk(KERN_ERR printk(KERN_ERR
...@@ -435,7 +482,11 @@ static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -435,7 +482,11 @@ static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM2b); mb->hw.cmd = omap_readw(MAILBOX_DSP2ARM2b);
#endif #endif
if (mb->sw.seq != (mbseq_expect & 1)) { /* if mbx1 has not been validated yet, discard. */
if (!mbx1_valid)
return IRQ_HANDLED;
if (mb->sw.seq != (*mbseq_expect & 1)) {
switch (mbseq_check_level) { switch (mbseq_check_level) {
case MBSEQ_CHECK_NONE: case MBSEQ_CHECK_NONE:
break; break;
...@@ -449,9 +500,7 @@ static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -449,9 +500,7 @@ static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} }
} }
mbseq_expect++; (*mbseq_expect)++;
if (sync_seq)
sync_seq->da_arm = mbseq_expect;
mbq_inc(mbq.wp); mbq_inc(mbq.wp);
if (mbq.wp == mbq.rp) { /* mbq is full */ if (mbq.wp == mbq.rp) { /* mbq is full */
...@@ -585,6 +634,9 @@ static int __init dsp_drv_probe(struct device *dev) ...@@ -585,6 +634,9 @@ static int __init dsp_drv_probe(struct device *dev)
goto fail6; goto fail6;
} }
/* MMU interrupt is not enabled until DSP runs */
disable_irq(INT_DSP_MMU);
#if 0 #if 0
ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev); ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev);
if (ret) { if (ret) {
...@@ -617,7 +669,7 @@ fail1: ...@@ -617,7 +669,7 @@ fail1:
static int dsp_drv_remove(struct device *dev) static int dsp_drv_remove(struct device *dev)
{ {
__dsp_reset(); dsp_cpustat_request(CPUSTAT_RESET);
#if 0 #if 0
free_irq(INT_MPUIO, dev); free_irq(INT_MPUIO, dev);
...@@ -626,6 +678,9 @@ static int dsp_drv_remove(struct device *dev) ...@@ -626,6 +678,9 @@ static int dsp_drv_remove(struct device *dev)
free_irq(INT_D2A_MB2, dev); free_irq(INT_D2A_MB2, dev);
free_irq(INT_D2A_MB1, dev); free_irq(INT_D2A_MB1, dev);
/* recover disable_depth */
enable_irq(INT_DSP_MMU);
dspuncfg(); dspuncfg();
dsp_taskmod_exit(); dsp_taskmod_exit();
mblog_exit(); mblog_exit();
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/17: DSP Gateway version 3.2 * 2005/06/09: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -47,12 +47,12 @@ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr, ...@@ -47,12 +47,12 @@ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo); static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
extern struct device_attribute dev_attr_ipbuf; extern struct device_attribute dev_attr_ipbuf;
static enum { static enum cfgstat {
CFG_ERR, CFG_ERR,
CFG_READY, CFG_READY,
CFG_SUSPEND CFG_SUSPEND
} cfgstat; } cfgstat;
static int mbx_revision; int mbx_revision;
static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q); static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q);
static unsigned short ioctl_wait_cmd; static unsigned short ioctl_wait_cmd;
static DECLARE_MUTEX(ioctl_sem); static DECLARE_MUTEX(ioctl_sem);
...@@ -62,33 +62,6 @@ static unsigned char n_stask; ...@@ -62,33 +62,6 @@ static unsigned char n_stask;
/* /*
* control functions * control functions
*/ */
static void dsp_run(void)
{
disable_irq(INT_DSP_MMU);
preempt_disable();
if (dsp_runstat == RUNSTAT_RESET) {
clk_use(api_ck_handle);
__dsp_run();
dsp_runstat = RUNSTAT_RUN;
}
preempt_enable();
enable_irq(INT_DSP_MMU);
}
static void dsp_reset(void)
{
disable_irq(INT_DSP_MMU);
preempt_disable();
if (dsp_runstat > RUNSTAT_RESET) {
__dsp_reset();
if (dsp_runstat == RUNSTAT_RUN)
clk_unuse(api_ck_handle);
dsp_runstat = RUNSTAT_RESET;
}
preempt_enable();
enable_irq(INT_DSP_MMU);
}
static short varread_val[5]; /* maximum */ static short varread_val[5]; /* maximum */
static int dsp_regread(unsigned short cmd_l, unsigned short adr, static int dsp_regread(unsigned short cmd_l, unsigned short adr,
...@@ -102,7 +75,7 @@ static int dsp_regread(unsigned short cmd_l, unsigned short adr, ...@@ -102,7 +75,7 @@ static int dsp_regread(unsigned short cmd_l, unsigned short adr,
ioctl_wait_cmd = MBCMD(REGRW); ioctl_wait_cmd = MBCMD(REGRW);
mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
dsp_mbsend_and_wait(&mb, &ioctl_wait_q); dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) { if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: register read error!\n"); printk(KERN_ERR "omapdsp: register read error!\n");
...@@ -128,7 +101,7 @@ static int dsp_regwrite(unsigned short cmd_l, unsigned short adr, ...@@ -128,7 +101,7 @@ static int dsp_regwrite(unsigned short cmd_l, unsigned short adr,
}; };
mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr);
dsp_mbsend_exarg(&mb, &arg); dsp_mbcmd_send_exarg(&mb, &arg);
return 0; return 0;
} }
...@@ -142,7 +115,7 @@ static int dsp_getvar(unsigned char varid, unsigned short *val, int sz) ...@@ -142,7 +115,7 @@ static int dsp_getvar(unsigned char varid, unsigned short *val, int sz)
ioctl_wait_cmd = MBCMD(GETVAR); ioctl_wait_cmd = MBCMD(GETVAR);
mbcmd_set(mb, MBCMD(GETVAR), varid, 0); mbcmd_set(mb, MBCMD(GETVAR), varid, 0);
dsp_mbsend_and_wait(&mb, &ioctl_wait_q); dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) { if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: variable read error!\n"); printk(KERN_ERR "omapdsp: variable read error!\n");
...@@ -159,10 +132,7 @@ up_out: ...@@ -159,10 +132,7 @@ up_out:
static int dsp_setvar(unsigned char varid, unsigned short val) static int dsp_setvar(unsigned char varid, unsigned short val)
{ {
struct mbcmd mb; dsp_mbsend(MBCMD(SETVAR), varid, val);
mbcmd_set(mb, MBCMD(SETVAR), varid, val);
dsp_mbsend(&mb);
return 0; return 0;
} }
...@@ -182,6 +152,15 @@ static int dspcfg(void) ...@@ -182,6 +152,15 @@ static int dspcfg(void)
goto up_out; goto up_out;
} }
/* for safety */
dsp_mem_usecount_clear();
/*
* DSPCFG command and dsp_mem_start() must be called
* while internal mem is on.
*/
dsp_mem_enable((void *)dspmem_base);
dsp_mb_start(); dsp_mb_start();
dsp_twch_start(); dsp_twch_start();
dsp_mem_start(); dsp_mem_start();
...@@ -190,7 +169,7 @@ static int dspcfg(void) ...@@ -190,7 +169,7 @@ static int dspcfg(void)
mbx_revision = -1; mbx_revision = -1;
ioctl_wait_cmd = MBCMD(DSPCFG); ioctl_wait_cmd = MBCMD(DSPCFG);
mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0); mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0);
dsp_mbsend_and_wait(&mb, &ioctl_wait_q); dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) { if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: configuration error!\n"); printk(KERN_ERR "omapdsp: configuration error!\n");
...@@ -199,16 +178,30 @@ static int dspcfg(void) ...@@ -199,16 +178,30 @@ static int dspcfg(void)
goto up_out; goto up_out;
} }
#ifdef OLD_BINARY_SUPPORT
/*
* MBREV 3.2 or earlier doesn't assume DMA domain is on
* when DSPCFG command is sent
*/
if ((mbx_revision == MBREV_3_0) ||
(mbx_revision == MBREV_3_2)) {
ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
DSPREG_ICR_DMA_IDLE_DOMAIN);
}
#endif
if ((ret = dsp_task_config_all(n_stask)) < 0) { if ((ret = dsp_task_config_all(n_stask)) < 0) {
up(&ioctl_sem); up(&ioctl_sem);
dspuncfg(); dspuncfg();
dsp_mem_disable((void *)dspmem_base);
return -EINVAL; return -EINVAL;
} }
cfgstat = CFG_READY; cfgstat = CFG_READY;
/* send parameter */ /* send parameter */
if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask)) < 0) if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK,
dsp_cpustat_get_icrmask())) < 0)
goto up_out; goto up_out;
/* create runtime sysfs entries */ /* create runtime sysfs entries */
...@@ -216,6 +209,7 @@ static int dspcfg(void) ...@@ -216,6 +209,7 @@ static int dspcfg(void)
device_create_file(&dsp_device.dev, &dev_attr_ipbuf); device_create_file(&dsp_device.dev, &dev_attr_ipbuf);
up_out: up_out:
dsp_mem_disable((void *)dspmem_base);
up(&ioctl_sem); up(&ioctl_sem);
return ret; return ret;
} }
...@@ -229,7 +223,7 @@ int dspuncfg(void) ...@@ -229,7 +223,7 @@ int dspuncfg(void)
if (down_interruptible(&ioctl_sem)) if (down_interruptible(&ioctl_sem))
return -ERESTARTSYS; return -ERESTARTSYS;
/* FIXME: lock task module */ /* FIXME: lock task module */
/* remove runtime sysfs entries */ /* remove runtime sysfs entries */
...@@ -238,7 +232,9 @@ int dspuncfg(void) ...@@ -238,7 +232,9 @@ int dspuncfg(void)
dsp_mb_stop(); dsp_mb_stop();
dsp_twch_stop(); dsp_twch_stop();
dsp_mem_stop();
dsp_err_stop(); dsp_err_stop();
dsp_dbg_stop();
dsp_task_unconfig_all(); dsp_task_unconfig_all();
ipbuf_stop(); ipbuf_stop();
cfgstat = CFG_ERR; cfgstat = CFG_ERR;
...@@ -252,33 +248,76 @@ int dsp_is_ready(void) ...@@ -252,33 +248,76 @@ int dsp_is_ready(void)
return (cfgstat == CFG_READY) ? 1 : 0; return (cfgstat == CFG_READY) ? 1 : 0;
} }
void dsp_runlevel(unsigned char level) /*
* polls all tasks
*/
int dsp_poll(void)
{ {
struct mbcmd mb; struct mbcmd mb;
int ret = 0;
mbcmd_set(mb, MBCMD(RUNLEVEL), level, 0); if (down_interruptible(&ioctl_sem))
return -ERESTARTSYS;
ioctl_wait_cmd = MBCMD(POLL);
mbcmd_set(mb, MBCMD(POLL), 0, 0);
dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: poll error!\n");
ret = -EINVAL;
goto up_out;
}
up_out:
up(&ioctl_sem);
return ret;
}
void dsp_runlevel(unsigned char level)
{
if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY) if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY)
dsp_mbsend_recovery(&mb); dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0);
else else
dsp_mbsend(&mb); dsp_mbsend(MBCMD(RUNLEVEL), level, 0);
} }
static enum cfgstat cfgstat_save_suspend;
/*
* suspend / resume callbacks
* DSP is not reset within this code, but done in omap_pm_suspend.
* so if these functions are called as OMAP_DSP_IOCTL_SUSPEND,
* DSP should be reset / unreset out of these functions.
*/
int dsp_suspend(void) int dsp_suspend(void)
{ {
struct mbcmd mb; struct mbcmd mb;
int ret = 0; int ret = 0;
if (cfgstat == CFG_SUSPEND) {
printk(KERN_ERR "omapdsp: DSP is already in suspend state.\n");
return -EINVAL;
}
if (down_interruptible(&ioctl_sem)) if (down_interruptible(&ioctl_sem))
return -ERESTARTSYS; return -ERESTARTSYS;
cfgstat_save_suspend = cfgstat;
if (!dsp_is_ready()) { if (!dsp_is_ready()) {
ret = -EINVAL; if (dsp_cpustat_get_stat() == CPUSTAT_RUN) {
goto up_out; printk(KERN_WARNING
"omapdsp: illegal operation: trying suspend DSP "
"while it is running but has not configured "
"yet.\n"
" Resetting DSP...\n");
}
goto transition;
} }
ioctl_wait_cmd = MBCMD(SUSPEND); ioctl_wait_cmd = MBCMD(SUSPEND);
mbcmd_set(mb, MBCMD(SUSPEND), 0, 0); mbcmd_set(mb, MBCMD(SUSPEND), 0, 0);
dsp_mbsend_and_wait(&mb, &ioctl_wait_q); dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) { if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: DSP suspend error!\n"); printk(KERN_ERR "omapdsp: DSP suspend error!\n");
...@@ -287,6 +326,7 @@ int dsp_suspend(void) ...@@ -287,6 +326,7 @@ int dsp_suspend(void)
} }
udelay(100); udelay(100);
transition:
cfgstat = CFG_SUSPEND; cfgstat = CFG_SUSPEND;
up_out: up_out:
up(&ioctl_sem); up(&ioctl_sem);
...@@ -295,29 +335,24 @@ up_out: ...@@ -295,29 +335,24 @@ up_out:
int dsp_resume(void) int dsp_resume(void)
{ {
if (cfgstat != CFG_SUSPEND) if (cfgstat != CFG_SUSPEND) {
return 0; printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n");
return -EINVAL;
}
cfgstat = CFG_READY; cfgstat = cfgstat_save_suspend;
return 0; return 0;
} }
static void dsp_fbctl_enable(void) static void dsp_fbctl_enable(void)
{ {
#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
struct mbcmd mb; OMAP_DSP_MBCMD_FBCTL_ENABLE);
mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
OMAP_DSP_MBCMD_FBCTL_ENABLE);
dsp_mbsend(&mb);
#endif
} }
static int dsp_fbctl_disable(void) static int dsp_fbctl_disable(void)
{ {
int ret = 0; int ret = 0;
#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
struct mbcmd mb; struct mbcmd mb;
if (down_interruptible(&ioctl_sem)) if (down_interruptible(&ioctl_sem))
...@@ -326,13 +361,12 @@ static int dsp_fbctl_disable(void) ...@@ -326,13 +361,12 @@ static int dsp_fbctl_disable(void)
ioctl_wait_cmd = MBCMD(KFUNC); ioctl_wait_cmd = MBCMD(KFUNC);
mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL,
OMAP_DSP_MBCMD_FBCTL_DISABLE); OMAP_DSP_MBCMD_FBCTL_DISABLE);
dsp_mbsend_and_wait(&mb, &ioctl_wait_q); dsp_mbcmd_send_and_wait(&mb, &ioctl_wait_q);
if (ioctl_wait_cmd != 0) { if (ioctl_wait_cmd != 0) {
printk(KERN_ERR "omapdsp: fb disable error!\n"); printk(KERN_ERR "omapdsp: fb disable error!\n");
ret = -EINVAL; ret = -EINVAL;
} }
up(&ioctl_sem); up(&ioctl_sem);
#endif
return ret; return ret;
} }
...@@ -350,19 +384,23 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, ...@@ -350,19 +384,23 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
* command level 1: commands which don't need lock * command level 1: commands which don't need lock
*/ */
case OMAP_DSP_IOCTL_RUN: case OMAP_DSP_IOCTL_RUN:
dsp_run(); dsp_cpustat_request(CPUSTAT_RUN);
break; break;
case OMAP_DSP_IOCTL_RESET: case OMAP_DSP_IOCTL_RESET:
dsp_reset(); dsp_cpustat_request(CPUSTAT_RESET);
break; break;
case OMAP_DSP_IOCTL_SETRSTVECT: case OMAP_DSP_IOCTL_SETRSTVECT:
ret = dsp_set_rstvect((unsigned long)arg); ret = dsp_set_rstvect((unsigned long)arg);
break; break;
case OMAP_DSP_IOCTL_IDLE: case OMAP_DSP_IOCTL_CPU_IDLE:
dsp_idle(); dsp_cpustat_request(CPUSTAT_CPU_IDLE);
break;
case OMAP_DSP_IOCTL_GBL_IDLE:
dsp_cpustat_request(CPUSTAT_GBL_IDLE);
break; break;
case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON: case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON:
...@@ -389,7 +427,7 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, ...@@ -389,7 +427,7 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
return -EFAULT; return -EFAULT;
mb.cmd = u_cmd.cmd; mb.cmd = u_cmd.cmd;
mb.data = u_cmd.data; mb.data = u_cmd.data;
ret = dsp_mbsend((struct mbcmd *)&mb); ret = dsp_mbcmd_send((struct mbcmd *)&mb);
break; break;
} }
...@@ -425,20 +463,27 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, ...@@ -425,20 +463,27 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file,
ret = dsp_task_count(); ret = dsp_task_count();
break; break;
case OMAP_DSP_IOCTL_POLL:
ret = dsp_poll();
break;
case OMAP_DSP_IOCTL_FBDIS: case OMAP_DSP_IOCTL_FBDIS:
ret = dsp_fbctl_disable(); ret = dsp_fbctl_disable();
break; break;
/*
* FIXME: cpu status control for suspend - resume
*/
case OMAP_DSP_IOCTL_SUSPEND: case OMAP_DSP_IOCTL_SUSPEND:
if ((ret = dsp_suspend()) < 0) if ((ret = dsp_suspend()) < 0)
break; break;
dsp_reset(); dsp_cpustat_request(CPUSTAT_RESET);
break; break;
case OMAP_DSP_IOCTL_RESUME: case OMAP_DSP_IOCTL_RESUME:
if ((ret = dsp_resume()) < 0) if ((ret = dsp_resume()) < 0)
break; break;
dsp_run(); dsp_cpustat_request(CPUSTAT_RUN);
break; break;
case OMAP_DSP_IOCTL_REGMEMR: case OMAP_DSP_IOCTL_REGMEMR:
...@@ -547,7 +592,7 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -547,7 +592,7 @@ void mbx1_dspcfg(struct mbcmd *mb)
{ {
unsigned char last = mb->cmd_l & 0x80; unsigned char last = mb->cmd_l & 0x80;
unsigned char cfgcmd = mb->cmd_l & 0x7f; unsigned char cfgcmd = mb->cmd_l & 0x7f;
static unsigned long tmp_ipbuf_sys_da; static unsigned long tmp_ipb_adr;
/* mailbox protocol check */ /* mailbox protocol check */
if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) { if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) {
...@@ -563,7 +608,8 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -563,7 +608,8 @@ void mbx1_dspcfg(struct mbcmd *mb)
if (mbx_revision == OMAP_DSP_MBPROT_REVISION) if (mbx_revision == OMAP_DSP_MBPROT_REVISION)
return; return;
#ifdef OLD_BINARY_SUPPORT #ifdef OLD_BINARY_SUPPORT
else if (mbx_revision == MBREV_3_0) { else if ((mbx_revision == MBREV_3_0) ||
(mbx_revision == MBREV_3_2)) {
printk(KERN_WARNING printk(KERN_WARNING
"mbx: ***** old DSP binary *****\n" "mbx: ***** old DSP binary *****\n"
" Please update your DSP application.\n"); " Please update your DSP application.\n");
...@@ -576,7 +622,7 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -576,7 +622,7 @@ void mbx1_dspcfg(struct mbcmd *mb)
" expected=0x%04x, received=0x%04x\n", " expected=0x%04x, received=0x%04x\n",
OMAP_DSP_MBPROT_REVISION, mb->data); OMAP_DSP_MBPROT_REVISION, mb->data);
mbx_revision = -1; mbx_revision = -1;
goto abort; goto abort1;
} }
} }
...@@ -601,15 +647,15 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -601,15 +647,15 @@ void mbx1_dspcfg(struct mbcmd *mb)
switch (cfgcmd) { switch (cfgcmd) {
case OMAP_DSP_MBCMD_DSPCFG_SYSADRH: case OMAP_DSP_MBCMD_DSPCFG_SYSADRH:
tmp_ipbuf_sys_da = (unsigned long)mb->data << 16; tmp_ipb_adr = (unsigned long)mb->data << 16;
break; break;
case OMAP_DSP_MBCMD_DSPCFG_SYSADRL: case OMAP_DSP_MBCMD_DSPCFG_SYSADRL:
tmp_ipbuf_sys_da |= mb->data; tmp_ipb_adr |= mb->data;
break; break;
case OMAP_DSP_MBCMD_DSPCFG_ABORT: case OMAP_DSP_MBCMD_DSPCFG_ABORT:
goto abort; goto abort1;
default: default:
printk(KERN_ERR printk(KERN_ERR
...@@ -619,24 +665,23 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -619,24 +665,23 @@ void mbx1_dspcfg(struct mbcmd *mb)
} }
if (last) { if (last) {
unsigned long badr; void *badr;
unsigned short bln; unsigned short bln;
unsigned short bsz; unsigned short bsz;
volatile unsigned short *buf; volatile unsigned short *buf;
void *sync_seq; void *ipb_sys_da, *ipb_sys_ad;
void *mbseq;
short *dbg_buf;
unsigned short dbg_buf_sz, dbg_line_sz;
struct mem_sync_struct mem_sync, *mem_syncp;
/* system IPBUF initialization */ ipb_sys_da = dspword_to_virt(tmp_ipb_adr);
if (tmp_ipbuf_sys_da & 0x1) { if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0)
printk(KERN_ERR goto abort1;
"mbx: system ipbuf address (0x%lx) "
"is odd number!\n", tmp_ipbuf_sys_da);
goto abort;
}
ipbuf_sys_da = dspword_to_virt(tmp_ipbuf_sys_da);
if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) {
printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n"); printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n");
return; goto abort1;
} }
/* /*
* read configuration data on system IPBUF * read configuration data on system IPBUF
...@@ -646,47 +691,95 @@ void mbx1_dspcfg(struct mbcmd *mb) ...@@ -646,47 +691,95 @@ void mbx1_dspcfg(struct mbcmd *mb)
if (mbx_revision == OMAP_DSP_MBPROT_REVISION) { if (mbx_revision == OMAP_DSP_MBPROT_REVISION) {
#endif #endif
buf = ipbuf_sys_da->d; buf = ipbuf_sys_da->d;
n_stask = buf[0]; n_stask = buf[0];
bln = buf[1]; bln = buf[1];
bsz = buf[2]; bsz = buf[2];
badr = MKLONG(buf[3], buf[4]); badr = MKVIRT(buf[3], buf[4]);
/*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[5], buf[6])); */ /* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[7], buf[8])); ipb_sys_ad = MKVIRT(buf[7], buf[8]);
sync_seq = dspword_to_virt(MKLONG(buf[9], buf[10])); mbseq = MKVIRT(buf[9], buf[10]);
dbg_buf = MKVIRT(buf[11], buf[12]);
dbg_buf_sz = buf[13];
dbg_line_sz = buf[14];
mem_sync.DARAM = MKVIRT(buf[15], buf[16]);
mem_sync.SARAM = MKVIRT(buf[17], buf[18]);
mem_sync.SDRAM = MKVIRT(buf[19], buf[20]);
mem_syncp = &mem_sync;
#ifdef OLD_BINARY_SUPPORT #ifdef OLD_BINARY_SUPPORT
} else if (mbx_revision == MBREV_3_2) {
buf = ipbuf_sys_da->d;
n_stask = buf[0];
bln = buf[1];
bsz = buf[2];
badr = MKVIRT(buf[3], buf[4]);
/* ipb_sys_da = MKVIRT(buf[5], buf[6]); */
ipb_sys_ad = MKVIRT(buf[7], buf[8]);
mbseq = MKVIRT(buf[9], buf[10]);
dbg_buf = NULL;
dbg_buf_sz = 0;
dbg_line_sz = 0;
mem_syncp = NULL;
} else if (mbx_revision == MBREV_3_0) { } else if (mbx_revision == MBREV_3_0) {
buf = ipbuf_sys_da->d; buf = ipbuf_sys_da->d;
n_stask = buf[0]; n_stask = buf[0];
bln = buf[1]; bln = buf[1];
bsz = buf[2]; bsz = buf[2];
badr = MKLONG(buf[3], buf[4]); badr = MKVIRT(buf[3], buf[4]);
/* bkeep = buf[5]; */ /* bkeep = buf[5]; */
/*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[6], buf[67)); */ /* ipb_sys_da = MKVIRT(buf[6], buf[7]); */
ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[8], buf[9])); ipb_sys_ad = MKVIRT(buf[8], buf[9]);
sync_seq = dspword_to_virt(MKLONG(buf[10], buf[11])); mbseq = MKVIRT(buf[10], buf[11]);
dbg_buf = NULL;
dbg_buf_sz = 0;
dbg_line_sz = 0;
mem_syncp = NULL;
} else /* should not occur */ } else /* should not occur */
goto abort; goto abort1;
#endif #endif /* OLD_BINARY_SUPPORT */
/* ipbuf_config() should be done in interrupt routine. */
if (ipbuf_config(bln, bsz, badr) < 0)
goto abort;
ipbuf_sys_da->s = OMAP_DSP_TID_FREE; release_ipbuf_pvt(ipbuf_sys_da);
/* mb_config() should be done in interrupt routine. */ /*
dsp_mb_config(sync_seq); * following configurations need to be done before
* waking up the dspcfg initiator process.
*/
if (ipbuf_sys_config(ipb_sys_ad, DIR_A2D) < 0)
goto abort1;
if (ipbuf_config(bln, bsz, badr) < 0)
goto abort1;
if (dsp_mb_config(mbseq) < 0)
goto abort2;
if (dsp_dbg_config(dbg_buf, dbg_buf_sz, dbg_line_sz) < 0)
goto abort2;
if (dsp_mem_sync_config(mem_syncp) < 0)
goto abort2;
ioctl_wait_cmd = 0; ioctl_wait_cmd = 0;
wake_up_interruptible(&ioctl_wait_q); wake_up_interruptible(&ioctl_wait_q);
} }
return; return;
abort: abort2:
ipbuf_stop();
abort1:
wake_up_interruptible(&ioctl_wait_q); wake_up_interruptible(&ioctl_wait_q);
return; return;
} }
void mbx1_poll(struct mbcmd *mb)
{
if (!waitqueue_active(&ioctl_wait_q) ||
(ioctl_wait_cmd != MBCMD(POLL))) {
printk(KERN_WARNING
"mbx: POLL command received, "
"but nobody is waiting for it...\n");
return;
}
ioctl_wait_cmd = 0;
wake_up_interruptible(&ioctl_wait_q);
}
void mbx1_regrw(struct mbcmd *mb) void mbx1_regrw(struct mbcmd *mb)
{ {
if (!waitqueue_active(&ioctl_wait_q) || if (!waitqueue_active(&ioctl_wait_q) ||
...@@ -743,7 +836,7 @@ void mbx1_getvar(struct mbcmd *mb) ...@@ -743,7 +836,7 @@ void mbx1_getvar(struct mbcmd *mb)
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
varread_val[i] = buf[i]; varread_val[i] = buf[i];
} }
ipbuf_sys_da->s = OMAP_DSP_TID_FREE; release_ipbuf_pvt(ipbuf_sys_da);
break; break;
} }
} }
...@@ -765,51 +858,54 @@ static ssize_t ifver_show(struct device *dev, struct device_attribute *attr, ...@@ -765,51 +858,54 @@ static ssize_t ifver_show(struct device *dev, struct device_attribute *attr,
* *
* 3.2: sysfs / udev support * 3.2: sysfs / udev support
* KMEM_RESERVE / KMEM_RELEASE ioctls for mem device * KMEM_RESERVE / KMEM_RELEASE ioctls for mem device
* 3.3: added following ioctls
* OMAP_DSP_IOCTL_GBL_IDLE
* OMAP_DSP_IOCTL_CPU_IDLE (instead of OMAP_DSP_IOCTL_IDLE)
* OMAP_DSP_IOCTL_POLL
*/ */
/* /*
* print all supporting I/F VERSIONs, like followings. * print all supporting I/F VERSIONs, like followings.
* *
* len += sprintf(buf, "3.1\n");
* len += sprintf(buf, "3.2\n"); * len += sprintf(buf, "3.2\n");
* len += sprintf(buf, "3.3\n");
*/ */
len += sprintf(buf + len, "3.2\n"); len += sprintf(buf + len, "3.2\n");
len += sprintf(buf + len, "3.3\n");
return len; return len;
} }
static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver); static struct device_attribute dev_attr_ifver = __ATTR_RO(ifver);
static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr, static ssize_t cpustat_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
#if 0 return sprintf(buf, "%s\n", cpustat_name(dsp_cpustat_get_stat()));
if (dsp_is_ready()) { }
int ret;
unsigned short val;
if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_ICRMASK, &val, 1)) < 0) static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat);
return ret;
if (val != dsp_icrmask) static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr,
printk(KERN_WARNING char *buf)
"omapdsp: icrmask value is inconsistent!\n"); {
} return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask());
#endif
return sprintf(buf, "0x%04x\n", dsp_icrmask);
} }
static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr, static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
unsigned short mask;
int ret; int ret;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
dsp_icrmask = simple_strtol(buf, NULL, 16); mask = simple_strtol(buf, NULL, 16);
dsp_cpustat_set_icrmask(mask);
if (dsp_is_ready()) { if (dsp_is_ready()) {
ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask); ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, mask);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -848,7 +944,6 @@ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr, ...@@ -848,7 +944,6 @@ static ssize_t loadinfo_show(struct device *dev, struct device_attribute *attr,
* static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo); * static struct device_attribute dev_attr_loadinfo = __ATTR_RO(loadinfo);
*/ */
#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC
void mbx1_fbctl_disable(void) void mbx1_fbctl_disable(void)
{ {
if (!waitqueue_active(&ioctl_wait_q) || if (!waitqueue_active(&ioctl_wait_q) ||
...@@ -861,7 +956,6 @@ void mbx1_fbctl_disable(void) ...@@ -861,7 +956,6 @@ void mbx1_fbctl_disable(void)
ioctl_wait_cmd = 0; ioctl_wait_cmd = 0;
wake_up_interruptible(&ioctl_wait_q); wake_up_interruptible(&ioctl_wait_q);
} }
#endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* for backward compatibility */ /* for backward compatibility */
...@@ -902,6 +996,7 @@ struct file_operations dsp_ctl_fops = { ...@@ -902,6 +996,7 @@ struct file_operations dsp_ctl_fops = {
void __init dsp_ctl_init(void) void __init dsp_ctl_init(void)
{ {
device_create_file(&dsp_device.dev, &dev_attr_ifver); device_create_file(&dsp_device.dev, &dev_attr_ifver);
device_create_file(&dsp_device.dev, &dev_attr_cpustat);
device_create_file(&dsp_device.dev, &dev_attr_icrmask); device_create_file(&dsp_device.dev, &dev_attr_icrmask);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
dsp_ctl_create_proc(); dsp_ctl_create_proc();
...@@ -911,6 +1006,7 @@ void __init dsp_ctl_init(void) ...@@ -911,6 +1006,7 @@ void __init dsp_ctl_init(void)
void dsp_ctl_exit(void) void dsp_ctl_exit(void)
{ {
device_remove_file(&dsp_device.dev, &dev_attr_ifver); device_remove_file(&dsp_device.dev, &dev_attr_ifver);
device_remove_file(&dsp_device.dev, &dev_attr_cpustat);
device_remove_file(&dsp_device.dev, &dev_attr_icrmask); device_remove_file(&dsp_device.dev, &dev_attr_icrmask);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
dsp_ctl_remove_proc(); dsp_ctl_remove_proc();
......
...@@ -21,14 +21,13 @@ ...@@ -21,14 +21,13 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/10: DSP Gateway version 3.2 * 2005/07/26: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/arch/dsp.h> #include <asm/arch/dsp.h>
#include "hardware_dsp.h" #include "hardware_dsp.h"
...@@ -75,13 +74,12 @@ static struct file_operations dsp_ctl_core_fops = { ...@@ -75,13 +74,12 @@ static struct file_operations dsp_ctl_core_fops = {
static const struct dev_list { static const struct dev_list {
unsigned int minor; unsigned int minor;
char *devname; char *devname;
char *devfs_name;
umode_t mode; umode_t mode;
} dev_list[] = { } dev_list[] = {
{CTL_MINOR, "dspctl", "dspctl/ctl", S_IRUSR | S_IWUSR}, {CTL_MINOR, "dspctl", S_IRUSR | S_IWUSR},
{MEM_MINOR, "dspmem", "dspctl/mem", S_IRUSR | S_IWUSR | S_IRGRP}, {MEM_MINOR, "dspmem", S_IRUSR | S_IWUSR | S_IRGRP},
{TWCH_MINOR, "dsptwch", "dspctl/twch", S_IRUSR | S_IWUSR | S_IRGRP}, {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP},
{ERR_MINOR, "dsperr", "dspctl/err", S_IRUSR | S_IRGRP}, {ERR_MINOR, "dsperr", S_IRUSR | S_IRGRP},
}; };
int __init dsp_ctl_core_init(void) int __init dsp_ctl_core_init(void)
...@@ -99,15 +97,11 @@ int __init dsp_ctl_core_init(void) ...@@ -99,15 +97,11 @@ int __init dsp_ctl_core_init(void)
} }
dsp_ctl_class = class_create(THIS_MODULE, "dspctl"); dsp_ctl_class = class_create(THIS_MODULE, "dspctl");
devfs_mk_dir("dspctl");
for (i = 0; i < ARRAY_SIZE(dev_list); i++) { for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
class_device_create(dsp_ctl_class, class_device_create(dsp_ctl_class,
MKDEV(OMAP_DSP_CTL_MAJOR, MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor), dev_list[i].minor),
NULL, dev_list[i].devname); NULL, dev_list[i].devname);
devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor),
S_IFCHR | dev_list[i].mode,
dev_list[i].devfs_name);
} }
return 0; return 0;
...@@ -118,12 +112,10 @@ void dsp_ctl_core_exit(void) ...@@ -118,12 +112,10 @@ void dsp_ctl_core_exit(void)
int i; int i;
for (i = 0; i < ARRAY_SIZE(dev_list); i++) { for (i = 0; i < ARRAY_SIZE(dev_list); i++) {
devfs_remove(dev_list[i].devfs_name);
class_device_destroy(dsp_ctl_class, class_device_destroy(dsp_ctl_class,
MKDEV(OMAP_DSP_CTL_MAJOR, MKDEV(OMAP_DSP_CTL_MAJOR,
dev_list[i].minor)); dev_list[i].minor));
} }
devfs_remove("dspctl");
class_destroy(dsp_ctl_class); class_destroy(dsp_ctl_class);
unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl"); unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl");
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com> * Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
* 2005/02/17: DSP Gateway version 3.2 * 2005/06/09: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -42,8 +42,8 @@ ...@@ -42,8 +42,8 @@
#include <asm/hardware/clock.h> #include <asm/hardware/clock.h>
#include <asm/arch/tc.h> #include <asm/arch/tc.h>
#include <asm/arch/dsp.h> #include <asm/arch/dsp.h>
#include <asm/arch/dsp_common.h>
#include "uaccess_dsp.h" #include "uaccess_dsp.h"
#include "ipbuf.h"
#include "dsp.h" #include "dsp.h"
#define SZ_1MB 0x100000 #define SZ_1MB 0x100000
...@@ -99,9 +99,12 @@ enum exmap_type { ...@@ -99,9 +99,12 @@ enum exmap_type {
struct exmap_tbl { struct exmap_tbl {
unsigned int valid:1; unsigned int valid:1;
unsigned int cntnu:1; /* grouping */ unsigned int cntnu:1; /* grouping */
int usecount; /* reference count by mmap */
enum exmap_type type; enum exmap_type type;
void *buf; void *buf; /* virtual address of the buffer,
void *vadr; * i.e. 0xc0000000 - */
void *vadr; /* DSP shadow space,
* i.e. 0xe0000000 - 0xe0ffffff */
unsigned int order; unsigned int order;
}; };
#define DSPMMU_TLB_LINES 32 #define DSPMMU_TLB_LINES 32
...@@ -112,6 +115,7 @@ static int dsp_exunmap(unsigned long dspadr); ...@@ -112,6 +115,7 @@ static int dsp_exunmap(unsigned long dspadr);
static void *dspvect_page; static void *dspvect_page;
static unsigned long dsp_fault_adr; static unsigned long dsp_fault_adr;
static struct mem_sync_struct mem_sync;
static __inline__ unsigned long lineup_offset(unsigned long adr, static __inline__ unsigned long lineup_offset(unsigned long adr,
unsigned long ref, unsigned long ref,
...@@ -125,6 +129,47 @@ static __inline__ unsigned long lineup_offset(unsigned long adr, ...@@ -125,6 +129,47 @@ static __inline__ unsigned long lineup_offset(unsigned long adr,
return newadr; return newadr;
} }
void dsp_mem_sync_inc(void)
{
/*
* FIXME: dsp_mem_enable()!!!
*/
if (mem_sync.DARAM)
mem_sync.DARAM->ad_arm++;
if (mem_sync.SARAM)
mem_sync.SARAM->ad_arm++;
if (mem_sync.SDRAM)
mem_sync.SDRAM->ad_arm++;
}
/*
* dsp_mem_sync_config() is called from mbx1 workqueue
*/
int dsp_mem_sync_config(struct mem_sync_struct *sync)
{
size_t sync_seq_sz = sizeof(struct sync_seq);
#ifdef OLD_BINARY_SUPPORT
if (sync == NULL) {
memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
return 0;
}
#endif
if ((dsp_mem_type(sync->DARAM, sync_seq_sz) != MEM_TYPE_DARAM) ||
(dsp_mem_type(sync->SARAM, sync_seq_sz) != MEM_TYPE_SARAM) ||
(dsp_mem_type(sync->SDRAM, sync_seq_sz) != MEM_TYPE_EXTERN)) {
printk(KERN_ERR
"omapdsp: mem_sync address validation failure!\n"
" mem_sync.DARAM = 0x%p,\n"
" mem_sync.SARAM = 0x%p,\n"
" mem_sync.SDRAM = 0x%p,\n",
sync->DARAM, sync->SARAM, sync->SDRAM);
return -1;
}
memcpy(&mem_sync, sync, sizeof(struct mem_sync_struct));
return 0;
}
/* /*
* kmem_reserve(), kmem_release(): * kmem_reserve(), kmem_release():
* reserve or release kernel memory for exmap(). * reserve or release kernel memory for exmap().
...@@ -262,11 +307,21 @@ static unsigned long dsp_mem_get_dma_pages(unsigned int order) ...@@ -262,11 +307,21 @@ static unsigned long dsp_mem_get_dma_pages(unsigned int order)
return __get_dma_pages(GFP_KERNEL, order); return __get_dma_pages(GFP_KERNEL, order);
} }
static void dsp_mem_free_pages(unsigned int buf, unsigned int order) static void dsp_mem_free_pages(unsigned long buf, unsigned int order)
{ {
struct kmem_pool *pool; struct kmem_pool *pool;
struct page *page, *ps, *pe;
int i; int i;
ps = virt_to_page(buf);
pe = virt_to_page(buf + (1 << (PAGE_SHIFT + order)));
for (page = ps; page < pe; page++) {
ClearPageReserved(page);
}
/*
* return buffer to kmem_pool or paging system
*/
switch (order) { switch (order) {
case ORDER_1MB: case ORDER_1MB:
pool = &kmem_pool_1M; pool = &kmem_pool_1M;
...@@ -358,6 +413,7 @@ static void exmap_clear_armmmu(unsigned long virt, unsigned long size) ...@@ -358,6 +413,7 @@ static void exmap_clear_armmmu(unsigned long virt, unsigned long size)
static int exmap_valid(void *vadr, size_t len) static int exmap_valid(void *vadr, size_t len)
{ {
/* exmap_sem should be held before calling this function */
int i; int i;
start: start:
...@@ -389,6 +445,107 @@ start: ...@@ -389,6 +445,107 @@ start:
return 0; return 0;
} }
enum dsp_mem_type_e dsp_mem_type(void *vadr, size_t len)
{
void *ds = (void *)daram_base;
void *de = (void *)daram_base + daram_size;
void *ss = (void *)saram_base;
void *se = (void *)saram_base + saram_size;
int ret;
if ((vadr >= ds) && (vadr < de)) {
if (vadr + len > de)
return MEM_TYPE_CROSSING;
else
return MEM_TYPE_DARAM;
} else if ((vadr >= ss) && (vadr < se)) {
if (vadr + len > se)
return MEM_TYPE_CROSSING;
else
return MEM_TYPE_SARAM;
} else {
down_read(&exmap_sem);
if (exmap_valid(vadr, len))
ret = MEM_TYPE_EXTERN;
else
ret = MEM_TYPE_NONE;
up_read(&exmap_sem);
return ret;
}
}
int dsp_address_validate(void *p, size_t len, char *fmt, ...)
{
if (dsp_mem_type(p, len) <= 0) {
if (fmt != NULL) {
char s[64];
va_list args;
va_start(args, fmt);
vsprintf(s, fmt, args);
va_end(args);
printk(KERN_ERR
"omapdsp: %s address(0x%p) and size(0x%x) is "
"not valid!\n"
" (crossing different type of memories, or \n"
" external memory space where no "
"actual memory is mapped)\n",
s, p, len);
}
return -1;
}
return 0;
}
/*
* exmap_use(), unuse():
* when the mapped area is exported to user space with mmap,
* the usecount is incremented.
* while the usecount > 0, that area can't be released.
*/
void exmap_use(void *vadr, size_t len)
{
int i;
down_write(&exmap_sem);
for (i = 0; i < DSPMMU_TLB_LINES; i++) {
void *mapadr;
unsigned long mapsize;
struct exmap_tbl *ent = &exmap_tbl[i];
if (!ent->valid)
continue;
mapadr = (void *)ent->vadr;
mapsize = 1 << (ent->order + PAGE_SHIFT);
if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
ent->usecount++;
}
}
up_write(&exmap_sem);
}
void exmap_unuse(void *vadr, size_t len)
{
int i;
down_write(&exmap_sem);
for (i = 0; i < DSPMMU_TLB_LINES; i++) {
void *mapadr;
unsigned long mapsize;
struct exmap_tbl *ent = &exmap_tbl[i];
if (!ent->valid)
continue;
mapadr = (void *)ent->vadr;
mapsize = 1 << (ent->order + PAGE_SHIFT);
if ((vadr + len > mapadr) && (vadr < mapadr + mapsize)) {
ent->usecount--;
}
}
up_write(&exmap_sem);
}
/* /*
* dsp_virt_to_phys() * dsp_virt_to_phys()
* returns physical address, and sets len to valid length * returns physical address, and sets len to valid length
...@@ -744,12 +901,13 @@ found_free: ...@@ -744,12 +901,13 @@ found_free:
goto fail; goto fail;
} }
exmap_ent->buf = buf; exmap_ent->buf = buf;
exmap_ent->vadr = _vadr; exmap_ent->vadr = _vadr;
exmap_ent->order = order; exmap_ent->order = order;
exmap_ent->valid = 1; exmap_ent->valid = 1;
exmap_ent->cntnu = cntnu; exmap_ent->cntnu = cntnu;
exmap_ent->type = type; exmap_ent->type = type;
exmap_ent->usecount = 0;
if ((_size -= unit) == 0) { /* normal completion */ if ((_size -= unit) == 0) { /* normal completion */
up_write(&exmap_sem); up_write(&exmap_sem);
...@@ -812,6 +970,14 @@ static int dsp_exunmap(unsigned long dspadr) ...@@ -812,6 +970,14 @@ static int dsp_exunmap(unsigned long dspadr)
return -EINVAL; return -EINVAL;
found_map: found_map:
if (ent->usecount > 0) {
printk(KERN_ERR
"omapdsp: exmap reference count is not 0.\n"
" idx=%d, vadr=%p, order=%d, usecount=%d\n",
idx, ent->vadr, ent->order, ent->usecount);
up_write(&exmap_sem);
return -EINVAL;
}
/* clearing DSP TLB entry */ /* clearing DSP TLB entry */
dsp_mmu_clear_tlb(dspadr); dsp_mmu_clear_tlb(dspadr);
...@@ -871,11 +1037,6 @@ static void exmap_flush(void) ...@@ -871,11 +1037,6 @@ static void exmap_flush(void)
/* flush TLB */ /* flush TLB */
flush_tlb_kernel_range(dspmem_base + dspmem_size, flush_tlb_kernel_range(dspmem_base + dspmem_size,
dspmem_base + DSPSPACE_SIZE); dspmem_base + DSPSPACE_SIZE);
/*
* we should clear processes' mm as well,
* because processes might had accessed to those spaces
* with old table in the past.
*/
up_write(&exmap_sem); up_write(&exmap_sem);
} }
...@@ -998,11 +1159,12 @@ static void dsp_mmu_init(void) ...@@ -998,11 +1159,12 @@ static void dsp_mmu_init(void)
phys = __pa(dspvect_page); phys = __pa(dspvect_page);
virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */ virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */
exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE);
exmap_tbl[0].buf = dspvect_page; exmap_tbl[0].buf = dspvect_page;
exmap_tbl[0].vadr = virt; exmap_tbl[0].vadr = virt;
exmap_tbl[0].order = 0; exmap_tbl[0].usecount = 0;
exmap_tbl[0].valid = 1; exmap_tbl[0].order = 0;
exmap_tbl[0].cntnu = 0; exmap_tbl[0].valid = 1;
exmap_tbl[0].cntnu = 0;
/* DSP TLB initialization */ /* DSP TLB initialization */
set_tlb_lock(0, 0); set_tlb_lock(0, 0);
...@@ -1020,88 +1182,66 @@ static void dsp_mmu_shutdown(void) ...@@ -1020,88 +1182,66 @@ static void dsp_mmu_shutdown(void)
} }
/* /*
* dsp_mem_enable() / disable(): * intmem_enable() / disable():
* if the address is in DSP internal memories, * if the address is in DSP internal memories,
* we send PM mailbox commands so that DSP DMA domain won't go in idle * we send PM mailbox commands so that DSP DMA domain won't go in idle
* when ARM is accessing to those memories. * when ARM is accessing to those memories.
* if the address is in external memory, acquire exmap_sem.
*
* __dsp_mem_enable() / disable() should be called only from __dsp_mbsend().
*/ */
static int dsp_mem_en_count; static int intmem_enable(void)
int dsp_mem_enable(void *adr)
{ {
struct mbcmd mb; int ret = 0;
int ret;
if (is_dsp_internal_mem(adr)) { if (dsp_is_ready())
if (dsp_is_ready() && (!dsp_mem_en_count) && ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
(dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) { DSPREG_ICR_DMA_IDLE_DOMAIN);
mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
DSPREG_ICR_DMA_IDLE_DOMAIN);
if ((ret = dsp_mbsend(&mb)) < 0)
return ret;
dsp_mem_en_count++;
}
} else
down_read(&exmap_sem);
return 0;
}
int dsp_mem_disable(void *adr) return ret;
{ }
struct mbcmd mb;
int ret;
if (is_dsp_internal_mem(adr)) { static void intmem_disable(void) {
if (dsp_is_ready() && dsp_mem_en_count) { if (dsp_is_ready())
mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE,
DSPREG_ICR_DMA_IDLE_DOMAIN); DSPREG_ICR_DMA_IDLE_DOMAIN);
if ((ret = dsp_mbsend(&mb)) < 0)
return ret;
dsp_mem_en_count--;
}
} else
up_read(&exmap_sem);
return 0;
} }
int __dsp_mem_enable(void *adr) /*
* dsp_mem_enable() / disable()
*/
int intmem_usecount;
int dsp_mem_enable(void *adr)
{ {
struct mbcmd mb; int ret = 0;
int ret;
if (is_dsp_internal_mem(adr)) { if (is_dsp_internal_mem(adr)) {
if (dsp_is_ready() && (!dsp_mem_en_count) && if (intmem_usecount++ == 0)
(dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) { ret = omap_dsp_request_mem();
mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE,
DSPREG_ICR_DMA_IDLE_DOMAIN);
if ((ret = __mbsend(&mb)) < 0)
return ret;
dsp_mem_en_count++;
}
} else } else
down_read(&exmap_sem); down_read(&exmap_sem);
return 0;
return ret;
} }
int __dsp_mem_disable(void *adr) void dsp_mem_disable(void *adr)
{ {
struct mbcmd mb;
int ret;
if (is_dsp_internal_mem(adr)) { if (is_dsp_internal_mem(adr)) {
if (dsp_is_ready() && dsp_mem_en_count) { if (--intmem_usecount == 0)
mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, omap_dsp_release_mem();
DSPREG_ICR_DMA_IDLE_DOMAIN);
if ((ret = __mbsend(&mb)) < 0)
return ret;
dsp_mem_en_count--;
}
} else } else
up_read(&exmap_sem); up_read(&exmap_sem);
return 0; }
/* for safety */
void dsp_mem_usecount_clear(void)
{
if (intmem_usecount != 0) {
printk(KERN_WARNING
"omapdsp: unbalanced memory request/release detected.\n"
" intmem_usecount is not zero at where "
"it should be! ... fixed to be zero.\n");
intmem_usecount = 0;
omap_dsp_release_mem();
}
} }
/* /*
...@@ -1144,10 +1284,10 @@ static ssize_t intmem_read(struct file *file, char *buf, size_t count, ...@@ -1144,10 +1284,10 @@ static ssize_t intmem_read(struct file *file, char *buf, size_t count,
read = size - p; read = size - p;
if (copy_to_user(buf, vadr, read)) { if (copy_to_user(buf, vadr, read)) {
read = -EFAULT; read = -EFAULT;
goto finish; goto out;
} }
*ppos += read; *ppos += read;
finish: out:
clk_unuse(api_ck_handle); clk_unuse(api_ck_handle);
return read; return read;
} }
...@@ -1157,39 +1297,37 @@ static ssize_t exmem_read(struct file *file, char *buf, size_t count, ...@@ -1157,39 +1297,37 @@ static ssize_t exmem_read(struct file *file, char *buf, size_t count,
{ {
unsigned long p = *ppos; unsigned long p = *ppos;
void *vadr = dspbyte_to_virt(p); void *vadr = dspbyte_to_virt(p);
ssize_t ret;
down_read(&exmap_sem);
if (!exmap_valid(vadr, count)) { if (!exmap_valid(vadr, count)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: DSP address %08lx / size %08x " "omapdsp: DSP address %08lx / size %08x "
"is not valid!\n", p, count); "is not valid!\n", p, count);
ret = -EFAULT; return -EFAULT;
goto up_out;
} }
if (count > DSPSPACE_SIZE - p) if (count > DSPSPACE_SIZE - p)
count = DSPSPACE_SIZE - p; count = DSPSPACE_SIZE - p;
if (copy_to_user(buf, vadr, count)) { if (copy_to_user(buf, vadr, count))
ret = -EFAULT; return -EFAULT;
goto up_out;
}
*ppos += count; *ppos += count;
up_read(&exmap_sem);
return count; return count;
up_out:
up_read(&exmap_sem);
return ret;
} }
static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count, static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
int ret;
void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
if (dsp_mem_enable(vadr) < 0)
return -EBUSY;
if (is_dspbyte_internal_mem(*ppos)) if (is_dspbyte_internal_mem(*ppos))
return intmem_read(file, buf, count, ppos); ret = intmem_read(file, buf, count, ppos);
else else
return exmem_read(file, buf, count, ppos); ret = exmem_read(file, buf, count, ppos);
dsp_mem_disable(vadr);
return ret;
} }
static ssize_t intmem_write(struct file *file, const char *buf, size_t count, static ssize_t intmem_write(struct file *file, const char *buf, size_t count,
...@@ -1208,10 +1346,10 @@ static ssize_t intmem_write(struct file *file, const char *buf, size_t count, ...@@ -1208,10 +1346,10 @@ static ssize_t intmem_write(struct file *file, const char *buf, size_t count,
written = size - p; written = size - p;
if (copy_from_user(vadr, buf, written)) { if (copy_from_user(vadr, buf, written)) {
written = -EFAULT; written = -EFAULT;
goto finish; goto out;
} }
*ppos += written; *ppos += written;
finish: out:
clk_unuse(api_ck_handle); clk_unuse(api_ck_handle);
return written; return written;
} }
...@@ -1221,39 +1359,37 @@ static ssize_t exmem_write(struct file *file, const char *buf, size_t count, ...@@ -1221,39 +1359,37 @@ static ssize_t exmem_write(struct file *file, const char *buf, size_t count,
{ {
unsigned long p = *ppos; unsigned long p = *ppos;
void *vadr = dspbyte_to_virt(p); void *vadr = dspbyte_to_virt(p);
ssize_t ret;
down_read(&exmap_sem);
if (!exmap_valid(vadr, count)) { if (!exmap_valid(vadr, count)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: DSP address %08lx / size %08x " "omapdsp: DSP address %08lx / size %08x "
"is not valid!\n", p, count); "is not valid!\n", p, count);
ret = -EFAULT; return -EFAULT;
goto up_out;
} }
if (count > DSPSPACE_SIZE - p) if (count > DSPSPACE_SIZE - p)
count = DSPSPACE_SIZE - p; count = DSPSPACE_SIZE - p;
if (copy_from_user(vadr, buf, count)) { if (copy_from_user(vadr, buf, count))
ret = -EFAULT; return -EFAULT;
goto up_out;
}
*ppos += count; *ppos += count;
up_read(&exmap_sem);
return count; return count;
up_out:
up_read(&exmap_sem);
return ret;
} }
static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count, static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count,
loff_t *ppos) loff_t *ppos)
{ {
int ret;
void *vadr = dspbyte_to_virt(*(unsigned long *)ppos);
if (dsp_mem_enable(vadr) < 0)
return -EBUSY;
if (is_dspbyte_internal_mem(*ppos)) if (is_dspbyte_internal_mem(*ppos))
return intmem_write(file, buf, count, ppos); ret = intmem_write(file, buf, count, ppos);
else else
return exmem_write(file, buf, count, ppos); ret = exmem_write(file, buf, count, ppos);
dsp_mem_disable(vadr);
return ret;
} }
static int dsp_mem_ioctl(struct inode *inode, struct file *file, static int dsp_mem_ioctl(struct inode *inode, struct file *file,
...@@ -1325,15 +1461,12 @@ static int dsp_mem_open(struct inode *inode, struct file *file) ...@@ -1325,15 +1461,12 @@ static int dsp_mem_open(struct inode *inode, struct file *file)
{ {
if (!capable(CAP_SYS_RAWIO)) if (!capable(CAP_SYS_RAWIO))
return -EPERM; return -EPERM;
if (dsp_mem_enable((void *)dspmem_base) < 0)
return -EBUSY;
return 0; return 0;
} }
static int dsp_mem_release(struct inode *inode, struct file *file) static int dsp_mem_release(struct inode *inode, struct file *file)
{ {
dsp_mem_disable((void *)dspmem_base);
return 0; return 0;
} }
...@@ -1414,16 +1547,16 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, ...@@ -1414,16 +1547,16 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
down_read(&exmap_sem); down_read(&exmap_sem);
len = sprintf(buf, "v: valid, c: cntnu\n" len = sprintf(buf, "v: valid, c: cntnu\n"
"ety vadr buf od\n"); "ety vadr buf od uc\n");
/* 00: v c 0xe0300000 0xc0171800 0 */ /* 00: v c 0xe0300000 0xc0171800 0 */
for (i = 0; i < DSPMMU_TLB_LINES; i++) { for (i = 0; i < DSPMMU_TLB_LINES; i++) {
struct exmap_tbl *ent = &exmap_tbl[i]; struct exmap_tbl *ent = &exmap_tbl[i];
/* 00: v c 0xe0300000 0xc0171800 0 */ /* 00: v c 0xe0300000 0xc0171800 0 */
len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d\n", len += sprintf(buf + len, "%02d: %c %c 0x%8p 0x%8p %2d %2d\n",
i, i,
ent->valid ? 'v' : ' ', ent->valid ? 'v' : ' ',
ent->cntnu ? 'c' : ' ', ent->cntnu ? 'c' : ' ',
ent->vadr, ent->buf, ent->order); ent->vadr, ent->buf, ent->order, ent->usecount);
} }
up_read(&exmap_sem); up_read(&exmap_sem);
...@@ -1432,6 +1565,19 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, ...@@ -1432,6 +1565,19 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr,
static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap); static struct device_attribute dev_attr_exmap = __ATTR_RO(exmap);
static ssize_t kmem_pool_show(struct device *dev, char *buf)
{
int count_1M, count_64K, total;
count_1M = kmem_pool_1M.count;
count_64K = kmem_pool_64K.count;
total = count_1M * SZ_1MB + count_64K * SZ_64KB;
return sprintf(buf, "0x%x %d %d\n", total, count_1M, count_64K);
}
static struct device_attribute dev_attr_kmem_pool = __ATTR_RO(kmem_pool);
/* /*
* DSP MMU interrupt handler * DSP MMU interrupt handler
*/ */
...@@ -1516,9 +1662,11 @@ irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1516,9 +1662,11 @@ irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* FIXME */ /* FIXME */
dsp_err_mmu_set(dsp_fault_adr); dsp_err_mmu_set(dsp_fault_adr);
} else { } else {
disable_irq(INT_DSP_MMU);
__dsp_mmu_itack();
printk(KERN_INFO "Resetting DSP...\n"); printk(KERN_INFO "Resetting DSP...\n");
__dsp_reset(); dsp_cpustat_request(CPUSTAT_RESET);
clk_unuse(api_ck_handle); enable_irq(INT_DSP_MMU);
/* /*
* if we enable followings, semaphore lock should be avoided. * if we enable followings, semaphore lock should be avoided.
* *
...@@ -1547,7 +1695,13 @@ struct file_operations dsp_mem_fops = { ...@@ -1547,7 +1695,13 @@ struct file_operations dsp_mem_fops = {
void dsp_mem_start(void) void dsp_mem_start(void)
{ {
dsp_mem_en_count = 0; dsp_register_mem_cb(intmem_enable, intmem_disable);
}
void dsp_mem_stop(void)
{
memset(&mem_sync, 0, sizeof(struct mem_sync_struct));
dsp_unregister_mem_cb();
} }
int __init dsp_mem_init(void) int __init dsp_mem_init(void)
...@@ -1570,6 +1724,7 @@ int __init dsp_mem_init(void) ...@@ -1570,6 +1724,7 @@ int __init dsp_mem_init(void)
device_create_file(&dsp_device.dev, &dev_attr_mmu); device_create_file(&dsp_device.dev, &dev_attr_mmu);
device_create_file(&dsp_device.dev, &dev_attr_exmap); device_create_file(&dsp_device.dev, &dev_attr_exmap);
device_create_file(&dsp_device.dev, &dev_attr_kmem_pool);
return 0; return 0;
} }
...@@ -1581,19 +1736,18 @@ void dsp_mem_exit(void) ...@@ -1581,19 +1736,18 @@ void dsp_mem_exit(void)
if (dspvect_page != NULL) { if (dspvect_page != NULL) {
unsigned long virt; unsigned long virt;
pmd_t *pmdp;
pte_t *ptep;
down_read(&exmap_sem);
virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE);
flush_tlb_kernel_range(virt, virt + PAGE_SIZE);
free_page((unsigned long)dspvect_page); free_page((unsigned long)dspvect_page);
dspvect_page = NULL; dspvect_page = NULL;
virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE); up_read(&exmap_sem);
pmdp = pmd_offset(pgd_offset_k(virt), virt);
ptep = pte_offset_kernel(pmdp, 0);
pmd_clear(pmdp);
pte_free_kernel(ptep);
} }
device_remove_file(&dsp_device.dev, &dev_attr_mmu); device_remove_file(&dsp_device.dev, &dev_attr_mmu);
device_remove_file(&dsp_device.dev, &dev_attr_exmap); device_remove_file(&dsp_device.dev, &dev_attr_exmap);
device_remove_file(&dsp_device.dev, &dev_attr_kmem_pool);
} }
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/11/22: DSP Gateway version 3.2 * 2005/03/11: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -138,15 +138,22 @@ int dsp_err_wdt_isset(void) ...@@ -138,15 +138,22 @@ int dsp_err_wdt_isset(void)
/* /*
* functions called from mailbox1 interrupt routine * functions called from mailbox1 interrupt routine
*/ */
void mbx1_wdt(struct mbcmd *mb) static void mbx1_err_wdt(unsigned short data)
{ {
printk(KERN_WARNING "omapdsp: DSP WDT expired!\n");
errcode |= OMAP_DSP_ERRDT_WDT; errcode |= OMAP_DSP_ERRDT_WDT;
errcnt++; errcnt++;
wdtval = mb->data; wdtval = data;
wake_up_interruptible(&err_wait_q); wake_up_interruptible(&err_wait_q);
} }
#ifdef OLD_BINARY_SUPPORT
/* v3.3 obsolete */
void mbx1_wdt(struct mbcmd *mb)
{
mbx1_err_wdt(mb->data);
}
#endif
extern void mbx1_err_ipbfull(void); extern void mbx1_err_ipbfull(void);
extern void mbx1_err_fatal(unsigned char tid); extern void mbx1_err_fatal(unsigned char tid);
...@@ -174,6 +181,10 @@ void mbx1_err(struct mbcmd *mb) ...@@ -174,6 +181,10 @@ void mbx1_err(struct mbcmd *mb)
tid = mb->data & 0x00ff; tid = mb->data & 0x00ff;
mbx1_err_fatal(tid); mbx1_err_fatal(tid);
break; break;
case OMAP_DSP_EID_WDT:
mbx1_err_wdt(mb->data);
break;
} }
} }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/24: DSP Gateway version 3.2 * 2005/02/24: DSP Gateway version 3.3
*/ */
struct fifo_struct { struct fifo_struct {
......
...@@ -21,12 +21,25 @@ ...@@ -21,12 +21,25 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/09/30: DSP Gateway version 3.2 * 2005/05/30: DSP Gateway version 3.3
*/ */
#ifndef __OMAP_DSP_HARDWARE_DSP_H #ifndef __OMAP_DSP_HARDWARE_DSP_H
#define __OMAP_DSP_HARDWARE_DSP_H #define __OMAP_DSP_HARDWARE_DSP_H
#ifdef CONFIG_ARCH_OMAP1510
#define OMAP1510_DARAM_BASE 0xe0000000
#define OMAP1510_DARAM_SIZE 0x10000
#define OMAP1510_SARAM_BASE 0xe0010000
#define OMAP1510_SARAM_SIZE 0x18000
#endif
#ifdef CONFIG_ARCH_OMAP16XX
#define OMAP16XX_DARAM_BASE 0xe0000000
#define OMAP16XX_DARAM_SIZE 0x10000
#define OMAP16XX_SARAM_BASE 0xe0010000
#define OMAP16XX_SARAM_SIZE 0x18000
#endif
/* /*
* MAJOR device number: !! allocated arbitrary !! * MAJOR device number: !! allocated arbitrary !!
*/ */
...@@ -186,6 +199,7 @@ ...@@ -186,6 +199,7 @@
/* /*
* DSP ICR * DSP ICR
*/ */
#define DSPREG_ICR_RESERVED_BITS 0xffc0
#define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020 #define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020
#define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010 #define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010
#define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008 #define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/17: DSP Gateway version 3.2 * 2005/06/06: DSP Gateway version 3.3
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -38,51 +38,51 @@ struct ipbuf **ipbuf; ...@@ -38,51 +38,51 @@ struct ipbuf **ipbuf;
struct ipbcfg ipbcfg; struct ipbcfg ipbcfg;
struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
static struct ipblink ipb_free = IPBLINK_INIT; static struct ipblink ipb_free = IPBLINK_INIT;
static int ipbuf_sys_hold_mem_active;
void ipbuf_stop(void) void ipbuf_stop(void)
{ {
int i;
spin_lock(&ipb_free.lock);
INIT_IPBLINK(&ipb_free);
spin_unlock(&ipb_free.lock);
ipbcfg.ln = 0; ipbcfg.ln = 0;
if (ipbuf) { if (ipbuf) {
kfree(ipbuf); kfree(ipbuf);
ipbuf = NULL; 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)
* ipbuf_config() is called by mailbox workqueue
*/
int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr)
{ {
void *base;
unsigned long lsz_byte = ((unsigned long)lsz) << 1; unsigned long lsz_byte = ((unsigned long)lsz) << 1;
size_t size; size_t size;
int ret = 0; int ret = 0;
int i; int i;
spin_lock(&ipb_free.lock);
INIT_IPBLINK(&ipb_free);
spin_unlock(&ipb_free.lock);
/* /*
* global IPBUF * global IPBUF
*/ */
if (adr & 0x1) { if (((unsigned long)base) & 0x3) {
printk(KERN_ERR printk(KERN_ERR
"mbx: global ipbuf address (0x%08lx) is odd number!\n", "omapdsp: global ipbuf address(0x%p) is not "
adr); "32-bit aligned!\n", base);
return -EINVAL; return -EINVAL;
} }
size = lsz_byte * ln; size = lsz_byte * ln;
if (adr + size > DSPSPACE_SIZE) { if (dsp_address_validate(base, size, "global ipbuf") < 0)
printk(KERN_ERR
"mbx: ipbuf address (0x%08lx) and size (0x%08x) is "
"illegal!\n", adr, size);
return -EINVAL; return -EINVAL;
}
base = dspword_to_virt(adr);
ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL); ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL);
if (ipbuf == NULL) { if (ipbuf == NULL) {
printk(KERN_ERR "mbx: memory allocation for ipbuf failed.\n"); printk(KERN_ERR
"omapdsp: memory allocation for ipbuf failed.\n");
return -ENOMEM; return -ENOMEM;
} }
for (i = 0; i < ln; i++) { for (i = 0; i < ln; i++) {
...@@ -101,20 +101,75 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr) ...@@ -101,20 +101,75 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr)
"omapdsp: ipbuf[%d] crosses 64k-word boundary!\n" "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n"
" @0x%p, size=0x%08lx\n", i, top, lsz_byte); " @0x%p, size=0x%08lx\n", i, top, lsz_byte);
ret = -EINVAL; ret = -EINVAL;
goto free_out;
} }
} }
ipbcfg.ln = ln; ipbcfg.ln = ln;
ipbcfg.lsz = lsz; ipbcfg.lsz = lsz;
ipbcfg.adr = adr; ipbcfg.base = base;
ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */ ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */
ipbcfg.cnt_full = 0; ipbcfg.cnt_full = 0;
printk(KERN_INFO printk(KERN_INFO
"omapdsp: IPBUF configuration\n" "omapdsp: IPBUF configuration\n"
" %d words * %d lines at 0x%p.\n", " %d words * %d lines at 0x%p.\n",
ipbcfg.lsz, ipbcfg.ln, dspword_to_virt(ipbcfg.adr)); ipbcfg.lsz, ipbcfg.ln, ipbcfg.base);
return ret; return ret;
free_out:
kfree(ipbuf);
ipbuf = NULL;
return ret;
}
int ipbuf_sys_config(void *p, enum arm_dsp_dir dir)
{
char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
if (((unsigned long)p) & 0x3) {
printk(KERN_ERR
"omapdsp: system ipbuf(%s) address(0x%p) is "
"not 32-bit aligned!\n", dir_str, p);
return -1;
}
if (dsp_address_validate(p, sizeof(struct ipbuf_sys),
"system ipbuf(%s)", dir_str) < 0)
return -1;
if (dsp_mem_type(p, sizeof(struct ipbuf_sys)) != MEM_TYPE_EXTERN) {
printk(KERN_WARNING
"omapdsp: system ipbuf(%s) is placed in"
" DSP internal memory.\n"
" It will prevent DSP from idling.\n", dir_str);
ipbuf_sys_hold_mem_active++;
/*
* dsp_mem_enable() never fails because
* it has been already enabled in dspcfg process and
* this will just increment the usecount.
*/
dsp_mem_enable((void *)daram_base);
}
if (dir == DIR_D2A)
ipbuf_sys_da = p;
else
ipbuf_sys_ad = p;
return 0;
}
int ipbuf_p_validate(void *p, enum arm_dsp_dir dir)
{
char *dir_str = (dir == DIR_D2A) ? "D2A" : "A2D";
if (((unsigned long)p) & 0x3) {
printk(KERN_ERR
"omapdsp: private ipbuf(%s) address(0x%p) is "
"not 32-bit aligned!\n", dir_str, p);
return -1;
}
return dsp_address_validate(p, sizeof(struct ipbuf_p),
"private ipbuf(%s)", dir_str);
} }
/* /*
...@@ -124,19 +179,22 @@ unsigned short get_free_ipbuf(unsigned char tid) ...@@ -124,19 +179,22 @@ unsigned short get_free_ipbuf(unsigned char tid)
{ {
unsigned short bid; unsigned short bid;
if (ipblink_empty(&ipb_free)) { if (dsp_mem_enable_ipbuf() < 0)
/* FIXME: wait on queue when not available. */
return OMAP_DSP_BID_NULL; return OMAP_DSP_BID_NULL;
}
/*
* FIXME: dsp_enable_dspmem!
*/
spin_lock(&ipb_free.lock); spin_lock(&ipb_free.lock);
if (ipblink_empty(&ipb_free)) {
/* FIXME: wait on queue when not available. */
bid = OMAP_DSP_BID_NULL;
goto out;
}
bid = ipb_free.top; bid = ipb_free.top;
ipbuf[bid]->la = tid; /* lock */ ipbuf[bid]->la = tid; /* lock */
ipblink_del_top(&ipb_free, ipbuf); ipblink_del_top(&ipb_free, ipbuf);
out:
spin_unlock(&ipb_free.lock); spin_unlock(&ipb_free.lock);
dsp_mem_disable_ipbuf();
return bid; return bid;
} }
...@@ -161,12 +219,10 @@ void release_ipbuf(unsigned short bid) ...@@ -161,12 +219,10 @@ void release_ipbuf(unsigned short bid)
static int try_yld(unsigned short bid) static int try_yld(unsigned short bid)
{ {
struct mbcmd mb;
int status; int status;
ipbuf[bid]->sa = OMAP_DSP_TID_ANON; ipbuf[bid]->sa = OMAP_DSP_TID_ANON;
mbcmd_set(mb, MBCMD(BKYLD), 0, bid); status = dsp_mbsend(MBCMD(BKYLD), 0, bid);
status = dsp_mbsend(&mb);
if (status < 0) { if (status < 0) {
/* DSP is busy and ARM keeps this line. */ /* DSP is busy and ARM keeps this line. */
release_ipbuf(bid); release_ipbuf(bid);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/17: DSP Gateway version 3.2 * 2005/05/17: DSP Gateway version 3.3
*/ */
struct ipbuf { struct ipbuf {
...@@ -43,13 +43,13 @@ struct ipbuf_p { ...@@ -43,13 +43,13 @@ struct ipbuf_p {
struct ipbuf_sys { struct ipbuf_sys {
unsigned short s; /* sync word */ unsigned short s; /* sync word */
unsigned short d[15]; /* data */ unsigned short d[31]; /* data */
}; };
struct ipbcfg { struct ipbcfg {
unsigned short ln; unsigned short ln;
unsigned short lsz; unsigned short lsz;
unsigned long adr; void *base;
unsigned short bsycnt; unsigned short bsycnt;
unsigned long cnt_full; /* count of IPBFULL error */ unsigned long cnt_full; /* count of IPBFULL error */
}; };
...@@ -72,8 +72,8 @@ extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; ...@@ -72,8 +72,8 @@ extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad;
enable_irq(INT_D2A_MB1); \ enable_irq(INT_D2A_MB1); \
} while(0) } while(0)
#define dsp_mem_enable_ipbuf() dsp_mem_enable(dspword_to_virt(ipbcfg.adr)) #define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base)
#define dsp_mem_disable_ipbuf() dsp_mem_disable(dspword_to_virt(ipbcfg.adr)) #define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base)
struct ipblink { struct ipblink {
spinlock_t lock; spinlock_t lock;
...@@ -89,6 +89,7 @@ struct ipblink { ...@@ -89,6 +89,7 @@ struct ipblink {
#define INIT_IPBLINK(link) \ #define INIT_IPBLINK(link) \
do { \ do { \
spin_lock_init(&(link)->lock); \
(link)->top = OMAP_DSP_BID_NULL; \ (link)->top = OMAP_DSP_BID_NULL; \
(link)->tail = OMAP_DSP_BID_NULL; \ (link)->tail = OMAP_DSP_BID_NULL; \
} while(0) } while(0)
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/17: DSP Gateway version 3.2 * 2005/05/18: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -98,6 +98,7 @@ char *subcmd_name(struct mbcmd *mb) ...@@ -98,6 +98,7 @@ char *subcmd_name(struct mbcmd *mb)
(cmd_l == EID(BADTCTL)) ? "BADTCTL": (cmd_l == EID(BADTCTL)) ? "BADTCTL":
(cmd_l == EID(BADPARAM)) ? "BADPARAM": (cmd_l == EID(BADPARAM)) ? "BADPARAM":
(cmd_l == EID(FATAL)) ? "FATAL": (cmd_l == EID(FATAL)) ? "FATAL":
(cmd_l == EID(WDT)) ? "WDT":
(cmd_l == EID(NOMEM)) ? "NOMEM": (cmd_l == EID(NOMEM)) ? "NOMEM":
(cmd_l == EID(NORES)) ? "NORES": (cmd_l == EID(NORES)) ? "NORES":
(cmd_l == EID(IPBFULL)) ? "IPBFULL": (cmd_l == EID(IPBFULL)) ? "IPBFULL":
...@@ -124,7 +125,7 @@ struct mblogent { ...@@ -124,7 +125,7 @@ struct mblogent {
unsigned long jiffies; unsigned long jiffies;
unsigned short cmd; unsigned short cmd;
unsigned short data; unsigned short data;
enum mblog_dir dir; enum arm_dsp_dir dir;
}; };
static struct { static struct {
...@@ -134,7 +135,7 @@ static struct { ...@@ -134,7 +135,7 @@ static struct {
struct mblogent ent[MBLOG_DEPTH]; struct mblogent ent[MBLOG_DEPTH];
} mblog; } mblog;
void mblog_add(struct mbcmd *mb, enum mblog_dir dir) void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir)
{ {
struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb;
struct mblogent *ent; struct mblogent *ent;
...@@ -148,11 +149,11 @@ void mblog_add(struct mbcmd *mb, enum mblog_dir dir) ...@@ -148,11 +149,11 @@ void mblog_add(struct mbcmd *mb, enum mblog_dir dir)
if (mblog.cnt < 0xffffffff) if (mblog.cnt < 0xffffffff)
mblog.cnt++; mblog.cnt++;
switch (dir) { switch (dir) {
case MBLOG_DIR_AD: case DIR_A2D:
if (mblog.cnt_ad < 0xffffffff) if (mblog.cnt_ad < 0xffffffff)
mblog.cnt_ad++; mblog.cnt_ad++;
break; break;
case MBLOG_DIR_DA: case DIR_D2A:
if (mblog.cnt_da < 0xffffffff) if (mblog.cnt_da < 0xffffffff)
mblog.cnt_da++; mblog.cnt_da++;
break; break;
...@@ -197,7 +198,7 @@ static ssize_t mblog_show(struct device *dev, struct device_attribute *attr, ...@@ -197,7 +198,7 @@ static ssize_t mblog_show(struct device *dev, struct device_attribute *attr,
const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h]; const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h];
len += sprintf(buf + len, len += sprintf(buf + len,
(ent->dir == MBLOG_DIR_AD) ? (ent->dir == DIR_A2D) ?
"%08lx %d %04x %04x ": "%08lx %d %04x %04x ":
"%08lx %d %04x %04x ", "%08lx %d %04x %04x ",
ent->jiffies, mb.sw.seq, ent->cmd, ent->data); ent->jiffies, mb.sw.seq, ent->cmd, ent->data);
...@@ -230,13 +231,13 @@ done: ...@@ -230,13 +231,13 @@ done:
static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog); static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog);
#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE #ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE
void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir) void mblog_printcmd(struct mbcmd *mb, enum arm_dsp_dir dir)
{ {
const struct cmdinfo *ci = cmdinfo[mb->cmd_h]; const struct cmdinfo *ci = cmdinfo[mb->cmd_h];
char *dir_str; char *dir_str;
char *subname; char *subname;
dir_str = (dir == MBLOG_DIR_AD) ? "sending" : "receiving"; dir_str = (dir == DIR_A2D) ? "sending" : "receiving";
switch (ci->cmd_l_type) { switch (ci->cmd_l_type) {
case CMD_L_TYPE_SUBCMD: case CMD_L_TYPE_SUBCMD:
if ((subname = subcmd_name(mb)) == NULL) if ((subname = subcmd_name(mb)) == NULL)
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/11/22: DSP Gateway version 3.2 * 2004/11/22: DSP Gateway version 3.3
*/ */
struct proc_list { struct proc_list {
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/02/22: DSP Gateway version 3.2 * 2005/07/26: DSP Gateway version 3.3
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -49,16 +48,32 @@ ...@@ -49,16 +48,32 @@
#include "fifo.h" #include "fifo.h"
#include "proclist.h" #include "proclist.h"
#define is_aligned(adr,align) (!((adr)&((align)-1)))
/* /*
* device state machine * taskdev.state: device state machine
* NOTASK: task is not attached. * NOTASK: task is not attached.
* ATTACHED: task is attached. * ATTACHED: task is attached.
* GARBAGE: task is detached. waiting for all processes to close this device. * GARBAGE: task is detached. waiting for all processes to close this device.
* ADDREQ: requesting for tadd * ADDREQ: requesting for tadd
* DELREQ: requesting for tdel. no process is opening this device. * DELREQ: requesting for tdel. no process is opening this device.
* KILLREQ: requesting for tkill.
* ADDFAIL: tadd failed. * ADDFAIL: tadd failed.
* ADDING: tadd in process.
* DELING: tdel in process.
* KILLING: tkill in process.
*/ */
#define devstate_name(stat) (\
((stat) & OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\
((stat) & OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
((stat) & OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\
((stat) & OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\
((stat) & OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\
((stat) & OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\
((stat) & OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\
((stat) & OMAP_DSP_DEVSTATE_ADDING) ? "ADDING" :\
((stat) & OMAP_DSP_DEVSTATE_DELING) ? "DELING" :\
((stat) & OMAP_DSP_DEVSTATE_KILLING) ? "KILLING" :\
"unknown")
struct taskdev { struct taskdev {
struct bus_type *bus; struct bus_type *bus;
...@@ -147,6 +162,7 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor); ...@@ -147,6 +162,7 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
static void taskdev_delete(unsigned char minor); static void taskdev_delete(unsigned char minor);
static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task); static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
static void taskdev_detach_task(struct taskdev *dev); static void taskdev_detach_task(struct taskdev *dev);
static int dsp_tdel_bh(unsigned char minor, unsigned short type);
static ssize_t devname_show(struct device *d, struct device_attribute *attr, static ssize_t devname_show(struct device *d, struct device_attribute *attr,
char *buf); char *buf);
...@@ -345,23 +361,27 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ...@@ -345,23 +361,27 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
{ {
unsigned short ttyp; unsigned short ttyp;
struct mbcmd mb; struct mbcmd mb;
int ret;
dsptask[tid] = task;
task->tid = tid; task->tid = tid;
dsptask[tid] = task;
/* TCFG request */ /* TCFG request */
task->state = TASK_STATE_CFGREQ; task->state = TASK_STATE_CFGREQ;
if (down_interruptible(&cfg_sem)) if (down_interruptible(&cfg_sem)) {
return -ERESTARTSYS; ret = -ERESTARTSYS;
goto fail_out;
}
cfg_cmd = MBCMD(TCFG); cfg_cmd = MBCMD(TCFG);
mbcmd_set(mb, MBCMD(TCFG), tid, 0); mbcmd_set(mb, MBCMD(TCFG), tid, 0);
dsp_mbsend_and_wait(&mb, &cfg_wait_q); dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
cfg_cmd = 0; cfg_cmd = 0;
up(&cfg_sem); up(&cfg_sem);
if (task->state != TASK_STATE_READY) { if (task->state != TASK_STATE_READY) {
printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid); printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
return -EINVAL; ret = -EINVAL;
goto fail_out;
} }
if (strlen(task->name) <= 1) if (strlen(task->name) <= 1)
...@@ -370,35 +390,49 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ...@@ -370,35 +390,49 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
ttyp = task->ttyp; ttyp = task->ttyp;
/*
* task info sanity check
*/
/* task type check */ /* task type check */
if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) { if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) {
printk(KERN_ERR "mbx: illegal task type(0x%04x), tid=%d\n", printk(KERN_ERR "omapdsp: illegal task type(0x%04x), tid=%d\n",
tid, ttyp); tid, ttyp);
ret = -EINVAL;
goto fail_out;
} }
/* private buffer address check */ /* private buffer address check */
if (sndtyp_pvt(ttyp)) { if (sndtyp_pvt(ttyp) &&
void *p = task->rcvdt.bk.ipbuf_pvt_r; (ipbuf_p_validate(task->rcvdt.bk.ipbuf_pvt_r, DIR_D2A) < 0)) {
ret = -EINVAL;
if ((unsigned long)p & 0x1) { goto fail_out;
printk(KERN_ERR
"mbx: private ipbuf (DSP->ARM) address (0x%p) "
"is odd number!\n", p);
return -EINVAL;
}
} }
if (rcvtyp_pvt(ttyp) &&
if (rcvtyp_pvt(ttyp)) { (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) {
void *p = task->ipbuf_pvt_w; ret = -EINVAL;
goto fail_out;
if ((unsigned long)p & 0x1) { }
printk(KERN_ERR
"mbx: private ipbuf (ARM->DSP) address (0x%p) " /* mmap buffer configuration check */
"is odd number!\n", p); if ((task->map_length > 0) &&
return -EINVAL; ((!is_aligned((unsigned long)task->map_base, PAGE_SIZE)) ||
} (!is_aligned(task->map_length, PAGE_SIZE)) ||
(dsp_mem_type(task->map_base, task->map_length) != MEM_TYPE_EXTERN))) {
printk(KERN_ERR
"omapdsp: illegal mmap buffer address(0x%p) or "
"length(0x%x).\n"
" It needs to be page-aligned and located at "
"external memory.\n",
task->map_base, task->map_length);
ret = -EINVAL;
goto fail_out;
} }
/*
* initialization
*/
/* read initialization */ /* read initialization */
if (sndtyp_wd(ttyp)) { if (sndtyp_wd(ttyp)) {
/* word */ /* word */
...@@ -410,11 +444,11 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ...@@ -410,11 +444,11 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
printk(KERN_ERR printk(KERN_ERR
"omapdsp: unable to allocate receive buffer. " "omapdsp: unable to allocate receive buffer. "
"(%d bytes for %s)\n", fifosz, task->name); "(%d bytes for %s)\n", fifosz, task->name);
return -ENOMEM; ret = -ENOMEM;
goto fail_out;
} }
} else { } else {
/* block */ /* block */
spin_lock_init(&task->rcvdt.bk.link.lock);
INIT_IPBLINK(&task->rcvdt.bk.link); INIT_IPBLINK(&task->rcvdt.bk.link);
task->rcvdt.bk.rp = 0; task->rcvdt.bk.rp = 0;
} }
...@@ -426,14 +460,15 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ...@@ -426,14 +460,15 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
ipbcfg.lsz*2; /* passive block */ ipbcfg.lsz*2; /* passive block */
return 0; return 0;
fail_out:
dsptask[tid] = NULL;
return ret;
} }
static void dsp_task_init(struct dsptask *task) static void dsp_task_init(struct dsptask *task)
{ {
struct mbcmd mb; dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
mbcmd_set(mb, MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
dsp_mbsend(&mb);
} }
int dsp_task_config_all(unsigned char n) int dsp_task_config_all(unsigned char n)
...@@ -558,11 +593,22 @@ int dsp_taskmod_busy(void) ...@@ -558,11 +593,22 @@ int dsp_taskmod_busy(void)
for (minor = 0; minor < TASKDEV_MAX; minor++) { for (minor = 0; minor < TASKDEV_MAX; minor++) {
dev = taskdev[minor]; dev = taskdev[minor];
if (dev && if (dev == NULL)
((dev->usecount > 0) || continue;
(dev->state == OMAP_DSP_DEVSTATE_ADDREQ) || if (dev->usecount > 0) {
(dev->state == OMAP_DSP_DEVSTATE_DELREQ))) printk("dsp_taskmod_busy(): %s: usecount=%d\n",
dev->name, dev->usecount);
return 1; return 1;
}
/*
if ((dev->state & (OMAP_DSP_DEVSTATE_ADDREQ |
OMAP_DSP_DEVSTATE_DELREQ)) {
*/
if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ) {
printk("dsp_taskmod_busy(): %s is in %s\n",
dev->name, devstate_name(dev->state));
return 1;
}
} }
return 0; return 0;
} }
...@@ -704,13 +750,19 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, ...@@ -704,13 +750,19 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count,
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto up_out; goto up_out;
} }
base = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al)); base = MKVIRT(ipbp->ah, ipbp->al);
src = base + rcvdt->rp; bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
if (dsp_address_validate(base, bkcnt,
"task %s read buffer",
dev->task->name) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
if (dsp_mem_enable(base) < 0) { if (dsp_mem_enable(base) < 0) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto pv_out1; goto pv_out1;
} }
bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp; src = base + rcvdt->rp;
if (bkcnt > count) { if (bkcnt > count) {
if (copy_to_user_dsp(buf, src, count)) { if (copy_to_user_dsp(buf, src, count)) {
ret = -EFAULT; ret = -EFAULT;
...@@ -813,7 +865,7 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count, ...@@ -813,7 +865,7 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count,
devstate_unlock(dev); devstate_unlock(dev);
mbcmd_set(mb, MBCMD(WDREQ), tid, 0); mbcmd_set(mb, MBCMD(WDREQ), tid, 0);
dsp_mbsend_and_wait(&mb, &dev->read_wait_q); dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
...@@ -868,7 +920,7 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, ...@@ -868,7 +920,7 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count,
devstate_unlock(dev); devstate_unlock(dev);
mbcmd_set(mb, MBCMD(BKREQ), tid, count/2); mbcmd_set(mb, MBCMD(BKREQ), tid, count/2);
dsp_mbsend_and_wait(&mb, &dev->read_wait_q); dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
...@@ -896,12 +948,17 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, ...@@ -896,12 +948,17 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count,
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto unlock_out; goto unlock_out;
} }
src = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al)); src = MKVIRT(ipbp->ah, ipbp->al);
rcvcnt = ((unsigned long)ipbp->c) * 2;
if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
dev->task->name) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
if (dsp_mem_enable(src) < 0) { if (dsp_mem_enable(src) < 0) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto pv_out1; goto pv_out1;
} }
rcvcnt = ((unsigned long)ipbp->c) * 2;
if (count > rcvcnt) if (count > rcvcnt)
count = rcvcnt; count = rcvcnt;
if (copy_to_user_dsp(buf, src, count)) { if (copy_to_user_dsp(buf, src, count)) {
...@@ -955,7 +1012,6 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf, ...@@ -955,7 +1012,6 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
{ {
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
struct taskdev *dev = taskdev[minor]; struct taskdev *dev = taskdev[minor];
struct mbcmd mb;
unsigned short wd; unsigned short wd;
int have_devstate_lock = 0; int have_devstate_lock = 0;
int ret = 0; int ret = 0;
...@@ -1013,9 +1069,8 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf, ...@@ -1013,9 +1069,8 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
goto up_out; goto up_out;
} }
mbcmd_set(mb, MBCMD(WDSND), dev->task->tid, wd);
spin_lock(&dev->task->wsz_lock); spin_lock(&dev->task->wsz_lock);
if (dsp_mbsend(&mb) < 0) { if (dsp_mbsend(MBCMD(WDSND), dev->task->tid, wd) < 0) {
spin_unlock(&dev->task->wsz_lock); spin_unlock(&dev->task->wsz_lock);
goto up_out; goto up_out;
} }
...@@ -1036,7 +1091,6 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, ...@@ -1036,7 +1091,6 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
{ {
unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
struct taskdev *dev = taskdev[minor]; struct taskdev *dev = taskdev[minor];
struct mbcmd mb;
int have_devstate_lock = 0; int have_devstate_lock = 0;
int ret = 0; int ret = 0;
...@@ -1102,7 +1156,12 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, ...@@ -1102,7 +1156,12 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto up_out; goto up_out;
} }
dst = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al)); dst = MKVIRT(ipbp->ah, ipbp->al);
if (dsp_address_validate(dst, count, "task %s write buffer",
dev->task->name) < 0) {
ret = -ERESTARTSYS;
goto pv_out1;
}
if (dsp_mem_enable(dst) < 0) { if (dsp_mem_enable(dst) < 0) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto pv_out1; goto pv_out1;
...@@ -1113,9 +1172,8 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, ...@@ -1113,9 +1172,8 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
} }
ipbp->c = count/2; ipbp->c = count/2;
ipbp->s = dev->task->tid; ipbp->s = dev->task->tid;
mbcmd_set(mb, MBCMD(BKSNDP), dev->task->tid, 0);
spin_lock(&dev->task->wsz_lock); spin_lock(&dev->task->wsz_lock);
if (dsp_mbsend(&mb) == 0) { if (dsp_mbsend(MBCMD(BKSNDP), dev->task->tid, 0) == 0) {
if (rcvtyp_acv(dev->task->ttyp)) if (rcvtyp_acv(dev->task->ttyp))
dev->task->wsz = 0; dev->task->wsz = 0;
ret = count; ret = count;
...@@ -1145,9 +1203,8 @@ pv_out1: ...@@ -1145,9 +1203,8 @@ pv_out1:
} }
ipbp->c = count/2; ipbp->c = count/2;
ipbp->sa = dev->task->tid; ipbp->sa = dev->task->tid;
mbcmd_set(mb, MBCMD(BKSND), dev->task->tid, bid);
spin_lock(&dev->task->wsz_lock); spin_lock(&dev->task->wsz_lock);
if (dsp_mbsend(&mb) == 0) { if (dsp_mbsend(MBCMD(BKSND), dev->task->tid, bid) == 0) {
if (rcvtyp_acv(dev->task->ttyp)) if (rcvtyp_acv(dev->task->ttyp))
dev->task->wsz = 0; dev->task->wsz = 0;
ret = count; ret = count;
...@@ -1226,6 +1283,9 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, ...@@ -1226,6 +1283,9 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file,
* reserved for backward compatibility * reserved for backward compatibility
* user-defined TCTL commands: no arg, non-interactive * user-defined TCTL commands: no arg, non-interactive
*/ */
printk(KERN_WARNING "omapdsp: "
"TCTL commands in 0x0080 - 0x0100 are obsolete.\n"
"they won't be supported in the future.\n");
mbargc = 0; mbargc = 0;
interactive = 0; interactive = 0;
} else if (cmd < 0x8000) { } else if (cmd < 0x8000) {
...@@ -1315,7 +1375,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, ...@@ -1315,7 +1375,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file,
dev->task->tctl_stat = -ERESTARTSYS; dev->task->tctl_stat = -ERESTARTSYS;
devstate_unlock(dev); devstate_unlock(dev);
dsp_mbsend_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q); dsp_mbcmd_send_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q);
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -ERESTARTSYS; ret = -ERESTARTSYS;
goto up_out; goto up_out;
...@@ -1330,7 +1390,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, ...@@ -1330,7 +1390,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file,
goto unlock_out; goto unlock_out;
} }
} else { } else {
dsp_mbsend_exarg(&mb, mbargp); dsp_mbcmd_send_exarg(&mb, mbargp);
ret = 0; ret = 0;
} }
...@@ -1341,18 +1401,42 @@ up_out: ...@@ -1341,18 +1401,42 @@ up_out:
return ret; return ret;
} }
static void dsp_task_mmap_open(struct vm_area_struct *vma)
{
struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
struct dsptask *task;
size_t len = vma->vm_end - vma->vm_start;
BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
task = dev->task;
exmap_use(task->map_base, len);
}
static void dsp_task_mmap_close(struct vm_area_struct *vma)
{
struct taskdev *dev = (struct taskdev *)vma->vm_private_data;
struct dsptask *task;
size_t len = vma->vm_end - vma->vm_start;
BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
task = dev->task;
exmap_unuse(task->map_base, len);
}
/** /**
* On demand page allocation is not allowed. The mapping area is defined by * On demand page allocation is not allowed. The mapping area is defined by
* corresponding DSP tasks. * corresponding DSP tasks.
*/ */
static struct page *dsp_task_nopage_mmap(struct vm_area_struct *vma, static struct page *dsp_task_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type) unsigned long address, int *type)
{ {
return NOPAGE_SIGBUS; return NOPAGE_SIGBUS;
} }
static struct vm_operations_struct dsp_task_vm_ops = { static struct vm_operations_struct dsp_task_vm_ops = {
.nopage = dsp_task_nopage_mmap, .open = dsp_task_mmap_open,
.close = dsp_task_mmap_close,
.nopage = dsp_task_mmap_nopage,
}; };
static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
...@@ -1368,21 +1452,6 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -1368,21 +1452,6 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
task = dev->task; task = dev->task;
if (task->map_length == 0) {
printk(KERN_ERR
"omapdsp: task %s doesn't have mmap buffer.\n",
task->name);
ret = -EINVAL;
goto unlock_out;
}
if (is_dsp_internal_mem(task->map_base)) {
printk(KERN_ERR
"omapdsp: task %s: map_base = %p\n"
" DARAM/SARAM can't be used as mmap buffer.\n",
task->name, task->map_base);
ret = -EINVAL;
goto unlock_out;
}
/* /*
* Don't swap this area out * Don't swap this area out
...@@ -1430,6 +1499,9 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) ...@@ -1430,6 +1499,9 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
} while (req_len); } while (req_len);
vma->vm_ops = &dsp_task_vm_ops; vma->vm_ops = &dsp_task_vm_ops;
vma->vm_private_data = dev;
exmap_use(task->map_base, vma->vm_end - vma->vm_start);
unlock_out: unlock_out:
devstate_unlock(dev); devstate_unlock(dev);
return ret; return ret;
...@@ -1441,12 +1513,8 @@ static int dsp_task_open(struct inode *inode, struct file *file) ...@@ -1441,12 +1513,8 @@ static int dsp_task_open(struct inode *inode, struct file *file)
struct taskdev *dev; struct taskdev *dev;
int ret = 0; int ret = 0;
if (minor >= TASKDEV_MAX) if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
return -ENODEV;
dev = taskdev[minor];
if (dev == NULL)
return -ENODEV; return -ENODEV;
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK | if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK |
OMAP_DSP_DEVSTATE_ATTACHED) < 0) OMAP_DSP_DEVSTATE_ATTACHED) < 0)
return -ERESTARTSYS; return -ERESTARTSYS;
...@@ -1457,15 +1525,20 @@ static int dsp_task_open(struct inode *inode, struct file *file) ...@@ -1457,15 +1525,20 @@ static int dsp_task_open(struct inode *inode, struct file *file)
} }
#endif #endif
if (dev->state == OMAP_DSP_DEVSTATE_NOTASK) { if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) {
dev->state = OMAP_DSP_DEVSTATE_ADDREQ; dev->state = OMAP_DSP_DEVSTATE_ADDREQ;
/* wake up twch daemon for tadd */ /* wake up twch daemon for tadd */
dsp_twch_touch(); dsp_twch_touch();
devstate_unlock(dev); devstate_unlock(dev);
if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED | if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED |
OMAP_DSP_DEVSTATE_ADDFAIL) < 0) OMAP_DSP_DEVSTATE_ADDFAIL) < 0) {
spin_lock(&dev->state_lock);
if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ)
dev->state = OMAP_DSP_DEVSTATE_NOTASK;
spin_unlock(&dev->state_lock);
return -ERESTARTSYS; return -ERESTARTSYS;
if (dev->state == OMAP_DSP_DEVSTATE_ADDFAIL) { }
if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) {
printk(KERN_ERR "omapdsp: task attach failed for %s!\n", printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
dev->name); dev->name);
ret = -EBUSY; ret = -EBUSY;
...@@ -1496,10 +1569,10 @@ static int dsp_task_release(struct inode *inode, struct file *file) ...@@ -1496,10 +1569,10 @@ static int dsp_task_release(struct inode *inode, struct file *file)
/* state_lock covers usecount, proc_list as well. */ /* state_lock covers usecount, proc_list as well. */
spin_lock(&dev->state_lock); spin_lock(&dev->state_lock);
/* state can be ATTACHED, KILLREQ or GARBAGE here. */ /* state can be ATTACHED, KILLING or GARBAGE here. */
switch (dev->state) { switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
case OMAP_DSP_DEVSTATE_KILLREQ: case OMAP_DSP_DEVSTATE_KILLING:
dev->usecount--; dev->usecount--;
break; break;
...@@ -1582,11 +1655,10 @@ int dsp_rmdev(char *name) ...@@ -1582,11 +1655,10 @@ int dsp_rmdev(char *name)
static int dsp_rmdev_minor(unsigned char minor) static int dsp_rmdev_minor(unsigned char minor)
{ {
struct taskdev *dev = taskdev[minor]; struct taskdev *dev = taskdev[minor];
struct dsptask *task = dev->task;
spin_lock(&dev->state_lock); spin_lock(&dev->state_lock);
switch (dev->state) { switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
case OMAP_DSP_DEVSTATE_NOTASK: case OMAP_DSP_DEVSTATE_NOTASK:
/* fine */ /* fine */
...@@ -1598,6 +1670,7 @@ static int dsp_rmdev_minor(unsigned char minor) ...@@ -1598,6 +1670,7 @@ static int dsp_rmdev_minor(unsigned char minor)
siginfo_t info; siginfo_t info;
struct proc_list *pl; struct proc_list *pl;
dev->state = OMAP_DSP_DEVSTATE_KILLING;
info.si_signo = SIGBUS; info.si_signo = SIGBUS;
info.si_errno = 0; info.si_errno = 0;
info.si_code = SI_KERNEL; info.si_code = SI_KERNEL;
...@@ -1605,12 +1678,10 @@ static int dsp_rmdev_minor(unsigned char minor) ...@@ -1605,12 +1678,10 @@ static int dsp_rmdev_minor(unsigned char minor)
list_for_each_entry(pl, &dev->proc_list, list_head) { list_for_each_entry(pl, &dev->proc_list, list_head) {
send_sig_info(SIGBUS, &info, pl->tsk); send_sig_info(SIGBUS, &info, pl->tsk);
} }
taskdev_detach_task(dev); spin_unlock(&dev->state_lock);
dsp_task_unconfig(task); dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
kfree(task); goto invalidate;
dev->state = OMAP_DSP_DEVSTATE_GARBAGE;
} }
break;
case OMAP_DSP_DEVSTATE_ADDREQ: case OMAP_DSP_DEVSTATE_ADDREQ:
/* open() is waiting. drain it. */ /* open() is waiting. drain it. */
...@@ -1624,7 +1695,9 @@ static int dsp_rmdev_minor(unsigned char minor) ...@@ -1624,7 +1695,9 @@ static int dsp_rmdev_minor(unsigned char minor)
wake_up_interruptible_all(&dev->state_wait_q); wake_up_interruptible_all(&dev->state_wait_q);
break; break;
case OMAP_DSP_DEVSTATE_KILLREQ: case OMAP_DSP_DEVSTATE_ADDING:
case OMAP_DSP_DEVSTATE_DELING:
case OMAP_DSP_DEVSTATE_KILLING:
case OMAP_DSP_DEVSTATE_GARBAGE: case OMAP_DSP_DEVSTATE_GARBAGE:
case OMAP_DSP_DEVSTATE_ADDFAIL: case OMAP_DSP_DEVSTATE_ADDFAIL:
/* transient state. wait for a moment. */ /* transient state. wait for a moment. */
...@@ -1634,12 +1707,13 @@ static int dsp_rmdev_minor(unsigned char minor) ...@@ -1634,12 +1707,13 @@ static int dsp_rmdev_minor(unsigned char minor)
spin_unlock(&dev->state_lock); spin_unlock(&dev->state_lock);
invalidate:
/* wait for some time and hope the state is settled */ /* wait for some time and hope the state is settled */
devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ); devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ);
if (dev->state != OMAP_DSP_DEVSTATE_NOTASK) { if (!(dev->state & OMAP_DSP_DEVSTATE_NOTASK)) {
printk(KERN_WARNING printk(KERN_WARNING
"omapdsp: illegal device state on rmdev %s.\n", "omapdsp: illegal device state (%s) on rmdev %s.\n",
dev->name); devstate_name(dev->state), dev->name);
} }
dev->state = OMAP_DSP_DEVSTATE_INVALID; dev->state = OMAP_DSP_DEVSTATE_INVALID;
devstate_unlock(dev); devstate_unlock(dev);
...@@ -1656,7 +1730,6 @@ struct file_operations dsp_task_fops = { ...@@ -1656,7 +1730,6 @@ struct file_operations dsp_task_fops = {
.ioctl = dsp_task_ioctl, .ioctl = dsp_task_ioctl,
.open = dsp_task_open, .open = dsp_task_open,
.release = dsp_task_release, .release = dsp_task_release,
.mmap = dsp_task_mmap,
}; };
static void dsptask_dev_release(struct device *dev) static void dsptask_dev_release(struct device *dev)
...@@ -1694,8 +1767,6 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor) ...@@ -1694,8 +1767,6 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
device_create_file(&dev->dev, &dev_attr_proc_list); device_create_file(&dev->dev, &dev_attr_proc_list);
class_device_create(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor), class_device_create(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor),
NULL, "dsptask%d", minor); NULL, "dsptask%d", minor);
devfs_mk_cdev(MKDEV(OMAP_DSP_TASK_MAJOR, minor),
S_IFCHR | S_IRUGO | S_IWUGO, "dsptask%d", minor);
init_waitqueue_head(&dev->state_wait_q); init_waitqueue_head(&dev->state_wait_q);
spin_lock_init(&dev->state_lock); spin_lock_init(&dev->state_lock);
...@@ -1712,9 +1783,7 @@ static void taskdev_delete(unsigned char minor) ...@@ -1712,9 +1783,7 @@ static void taskdev_delete(unsigned char minor)
device_remove_file(&dev->dev, &dev_attr_devname); device_remove_file(&dev->dev, &dev_attr_devname);
device_remove_file(&dev->dev, &dev_attr_devstate); device_remove_file(&dev->dev, &dev_attr_devstate);
device_remove_file(&dev->dev, &dev_attr_proc_list); device_remove_file(&dev->dev, &dev_attr_proc_list);
class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor)); class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
devfs_remove("dsptask%d", minor);
device_unregister(&dev->dev); device_unregister(&dev->dev);
proc_list_flush(&dev->proc_list); proc_list_flush(&dev->proc_list);
taskdev[minor] = NULL; taskdev[minor] = NULL;
...@@ -1736,6 +1805,8 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) ...@@ -1736,6 +1805,8 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
dev->fops.write = dev->fops.write =
rcvtyp_wd(ttyp) ? dsp_task_write_wd: rcvtyp_wd(ttyp) ? dsp_task_write_wd:
/* rcvbyp_bk */ dsp_task_write_bk; /* rcvbyp_bk */ dsp_task_write_bk;
if (task->map_length)
dev->fops.mmap = dsp_task_mmap;
device_create_file(&dev->dev, &dev_attr_taskname); device_create_file(&dev->dev, &dev_attr_taskname);
device_create_file(&dev->dev, &dev_attr_ttyp); device_create_file(&dev->dev, &dev_attr_ttyp);
...@@ -1781,7 +1852,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1781,7 +1852,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
struct dsptask *task; struct dsptask *task;
struct mbcmd mb; struct mbcmd mb;
struct mb_exarg arg; struct mb_exarg arg;
unsigned char tid; unsigned char tid, tid_response;
unsigned short argv[2]; unsigned short argv[2];
int ret = minor; int ret = minor;
...@@ -1790,16 +1861,17 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1790,16 +1861,17 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
"omapdsp: no task device with minor %d\n", minor); "omapdsp: no task device with minor %d\n", minor);
return -EINVAL; return -EINVAL;
} }
/*
* we don't need to lock state_lock because spin_lock(&dev->state_lock);
* only tadd is allowed when devstate is ADDREQ. if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) {
*/
if (dev->state != OMAP_DSP_DEVSTATE_ADDREQ) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: taskdev %s is not requesting for tadd.\n", "omapdsp: taskdev %s is not requesting for tadd. "
dev->name); "(state is %s)\n", dev->name, devstate_name(dev->state));
spin_unlock(&dev->state_lock);
return -EINVAL; return -EINVAL;
} }
dev->state = OMAP_DSP_DEVSTATE_ADDING;
spin_unlock(&dev->state_lock);
if (adr == OMAP_DSP_TADD_ABORTADR) { if (adr == OMAP_DSP_TADD_ABORTADR) {
/* aborting tadd intentionally */ /* aborting tadd intentionally */
...@@ -1828,7 +1900,8 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1828,7 +1900,8 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
arg.argc = 2; arg.argc = 2;
arg.argv = argv; arg.argv = argv;
dsp_mbsend_and_wait_exarg(&mb, &arg, &cfg_wait_q); dsp_mem_sync_inc();
dsp_mbcmd_send_and_wait_exarg(&mb, &arg, &cfg_wait_q);
tid = cfg_tid; tid = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON; cfg_tid = OMAP_DSP_TID_ANON;
...@@ -1847,7 +1920,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1847,7 +1920,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
} }
if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) { if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail_out; goto del_out;
} }
memset(task, 0, sizeof(struct dsptask)); memset(task, 0, sizeof(struct dsptask));
...@@ -1860,9 +1933,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1860,9 +1933,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
"omapdsp: task name (%s) doesn't match with " "omapdsp: task name (%s) doesn't match with "
"device name (%s).\n", task->name, dev->name); "device name (%s).\n", task->name, dev->name);
ret = -EINVAL; ret = -EINVAL;
dev->state = OMAP_DSP_DEVSTATE_DELREQ; goto free_out;
dsp_twch_touch();
return -EINVAL;
} }
dsp_task_init(task); dsp_task_init(task);
...@@ -1873,6 +1944,30 @@ int dsp_tadd(unsigned char minor, unsigned long adr) ...@@ -1873,6 +1944,30 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
free_out: free_out:
kfree(task); kfree(task);
del_out:
printk(KERN_ERR "omapdsp: deleting the task...\n");
dev->state = OMAP_DSP_DEVSTATE_DELING;
if (down_interruptible(&cfg_sem)) {
printk(KERN_ERR "omapdsp: aborting tdel process. "
"DSP side could be corrupted.\n");
goto fail_out;
}
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = MBCMD(TDEL);
mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL);
dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
tid_response = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = 0;
up(&cfg_sem);
if (tid_response != tid)
printk(KERN_ERR "omapdsp: tdel failed. "
"DSP side could be corrupted.\n");
fail_out: fail_out:
dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
wake_up_interruptible_all(&dev->state_wait_q); wake_up_interruptible_all(&dev->state_wait_q);
...@@ -1882,64 +1977,31 @@ fail_out: ...@@ -1882,64 +1977,31 @@ fail_out:
int dsp_tdel(unsigned char minor) int dsp_tdel(unsigned char minor)
{ {
struct taskdev *dev; struct taskdev *dev;
struct dsptask *task;
struct mbcmd mb;
unsigned char tid, tid_response;
int ret = minor;
if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: no task device with minor %d\n", minor); "omapdsp: no task device with minor %d\n", minor);
return -EINVAL; return -EINVAL;
} }
/* spin_lock(&dev->state_lock);
* we don't need to lock state_lock because if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) {
* only tdel is allowed when devstate is DELREQ.
*/
if (dev->state != OMAP_DSP_DEVSTATE_DELREQ) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: taskdev %s is not requesting for tdel.\n", "omapdsp: taskdev %s is not requesting for tdel. "
dev->name); "(state is %s)\n", dev->name, devstate_name(dev->state));
spin_unlock(&dev->state_lock);
return -EINVAL; return -EINVAL;
} }
dev->state = OMAP_DSP_DEVSTATE_DELING;
spin_unlock(&dev->state_lock);
task = dev->task; return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE);
tid = task->tid;
if (down_interruptible(&cfg_sem)) {
return -ERESTARTSYS;
}
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = MBCMD(TDEL);
mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_SAFE);
dsp_mbsend_and_wait(&mb, &cfg_wait_q);
tid_response = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = 0;
up(&cfg_sem);
taskdev_detach_task(dev);
dsp_task_unconfig(task);
kfree(task);
dev->state = OMAP_DSP_DEVSTATE_NOTASK;
wake_up_interruptible_all(&dev->state_wait_q);
if (tid_response != tid) {
printk(KERN_ERR "omapdsp: tdel failed!\n");
ret = -EINVAL;
}
return ret;
} }
int dsp_tkill(unsigned char minor) int dsp_tkill(unsigned char minor)
{ {
struct taskdev *dev; struct taskdev *dev;
struct dsptask *task;
struct mbcmd mb;
unsigned char tid, tid_response;
siginfo_t info; siginfo_t info;
struct proc_list *pl; struct proc_list *pl;
int ret = minor;
if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
printk(KERN_ERR printk(KERN_ERR
...@@ -1947,14 +2009,14 @@ int dsp_tkill(unsigned char minor) ...@@ -1947,14 +2009,14 @@ int dsp_tkill(unsigned char minor)
return -EINVAL; return -EINVAL;
} }
spin_lock(&dev->state_lock); spin_lock(&dev->state_lock);
if (dev->state != OMAP_DSP_DEVSTATE_ATTACHED) { if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) {
printk(KERN_ERR printk(KERN_ERR
"omapdsp: task has not been attached for taskdev %s\n", "omapdsp: task has not been attached for taskdev %s\n",
dev->name); dev->name);
spin_unlock(&dev->state_lock); spin_unlock(&dev->state_lock);
return -EINVAL; return -EINVAL;
} }
dev->state = OMAP_DSP_DEVSTATE_KILLREQ; dev->state = OMAP_DSP_DEVSTATE_KILLING;
info.si_signo = SIGBUS; info.si_signo = SIGBUS;
info.si_errno = 0; info.si_errno = 0;
info.si_code = SI_KERNEL; info.si_code = SI_KERNEL;
...@@ -1964,17 +2026,33 @@ int dsp_tkill(unsigned char minor) ...@@ -1964,17 +2026,33 @@ int dsp_tkill(unsigned char minor)
} }
spin_unlock(&dev->state_lock); spin_unlock(&dev->state_lock);
return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
}
static int dsp_tdel_bh(unsigned char minor, unsigned short type)
{
struct taskdev *dev = taskdev[minor];
struct dsptask *task;
struct mbcmd mb;
unsigned char tid, tid_response;
int ret = minor;
task = dev->task; task = dev->task;
tid = task->tid; tid = task->tid;
if (down_interruptible(&cfg_sem)) { if (down_interruptible(&cfg_sem)) {
tid_response = OMAP_DSP_TID_ANON; if (type == OMAP_DSP_MBCMD_TDEL_SAFE) {
ret = -ERESTARTSYS; dev->state = OMAP_DSP_DEVSTATE_DELREQ;
goto detach_out; return -ERESTARTSYS;
} else {
tid_response = OMAP_DSP_TID_ANON;
ret = -ERESTARTSYS;
goto detach_out;
}
} }
cfg_tid = OMAP_DSP_TID_ANON; cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = MBCMD(TDEL); cfg_cmd = MBCMD(TDEL);
mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL); mbcmd_set(mb, MBCMD(TDEL), tid, type);
dsp_mbsend_and_wait(&mb, &cfg_wait_q); dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
tid_response = cfg_tid; tid_response = cfg_tid;
cfg_tid = OMAP_DSP_TID_ANON; cfg_tid = OMAP_DSP_TID_ANON;
cfg_cmd = 0; cfg_cmd = 0;
...@@ -1985,9 +2063,11 @@ detach_out: ...@@ -1985,9 +2063,11 @@ detach_out:
dsp_task_unconfig(task); dsp_task_unconfig(task);
kfree(task); kfree(task);
if (tid_response != tid) if (tid_response != tid) {
printk(KERN_ERR "omapdsp: tkill failed!\n"); printk(KERN_ERR "omapdsp: %s failed!\n",
(type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill");
ret = -EINVAL;
}
spin_lock(&dev->state_lock); spin_lock(&dev->state_lock);
dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE : dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE :
OMAP_DSP_DEVSTATE_NOTASK; OMAP_DSP_DEVSTATE_NOTASK;
...@@ -2000,10 +2080,14 @@ detach_out: ...@@ -2000,10 +2080,14 @@ detach_out:
/* /*
* state inquiry * state inquiry
*/ */
long taskdev_state(unsigned char minor) long taskdev_state_stale(unsigned char minor)
{ {
return taskdev[minor] ? taskdev[minor]->state : if (taskdev[minor]) {
OMAP_DSP_DEVSTATE_NOTASK; long state = taskdev[minor]->state;
taskdev[minor]->state |= OMAP_DSP_DEVSTATE_STALE;
return state;
} else
return OMAP_DSP_DEVSTATE_NOTASK;
} }
/* /*
...@@ -2271,9 +2355,6 @@ void mbx1_tcfg(struct mbcmd *mb) ...@@ -2271,9 +2355,6 @@ void mbx1_tcfg(struct mbcmd *mb)
{ {
unsigned char tid = mb->cmd_l; unsigned char tid = mb->cmd_l;
struct dsptask *task = dsptask[tid]; struct dsptask *task = dsptask[tid];
unsigned long tmp_ipbp_r, tmp_ipbp_w;
unsigned long tmp_mapstart, tmp_maplen;
unsigned long tmp_tnm;
unsigned short *tnm; unsigned short *tnm;
volatile unsigned short *buf; volatile unsigned short *buf;
int i; int i;
...@@ -2289,25 +2370,29 @@ void mbx1_tcfg(struct mbcmd *mb) ...@@ -2289,25 +2370,29 @@ void mbx1_tcfg(struct mbcmd *mb)
if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) { if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n"); printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n");
return; goto out;
} }
/* /*
* read configuration data on system IPBUF * read configuration data on system IPBUF
*/ */
buf = ipbuf_sys_da->d; buf = ipbuf_sys_da->d;
task->ttyp = buf[0]; task->ttyp = buf[0];
tmp_ipbp_r = MKLONG(buf[1], buf[2]); task->rcvdt.bk.ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
tmp_ipbp_w = MKLONG(buf[3], buf[4]); task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
tmp_mapstart = MKLONG(buf[5], buf[6]); task->map_base = MKVIRT(buf[5], buf[6]);
tmp_maplen = MKLONG(buf[7], buf[8]); task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */
tmp_tnm = MKLONG(buf[9], buf[10]); tnm = MKVIRT(buf[9], buf[10]);
release_ipbuf_pvt(ipbuf_sys_da);
task->rcvdt.bk.ipbuf_pvt_r = dspword_to_virt(tmp_ipbp_r);
task->ipbuf_pvt_w = dspword_to_virt(tmp_ipbp_w); /*
task->map_base = dspword_to_virt(tmp_mapstart); * copy task name string
task->map_length = tmp_maplen << 1; /* word -> byte */ */
tnm = dspword_to_virt(tmp_tnm); if (dsp_address_validate(tnm, OMAP_DSP_TNM_LEN, "task name buffer") <0) {
task->name[0] = '\0';
goto out;
}
for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) { for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) {
/* avoiding byte access */ /* avoiding byte access */
unsigned short tmp = tnm[i]; unsigned short tmp = tnm[i];
...@@ -2317,8 +2402,8 @@ void mbx1_tcfg(struct mbcmd *mb) ...@@ -2317,8 +2402,8 @@ void mbx1_tcfg(struct mbcmd *mb)
} }
task->name[OMAP_DSP_TNM_LEN-1] = '\0'; task->name[OMAP_DSP_TNM_LEN-1] = '\0';
release_ipbuf_pvt(ipbuf_sys_da);
task->state = TASK_STATE_READY; task->state = TASK_STATE_READY;
out:
wake_up_interruptible(&cfg_wait_q); wake_up_interruptible(&cfg_wait_q);
} }
...@@ -2368,7 +2453,117 @@ void mbx1_err_fatal(unsigned char tid) ...@@ -2368,7 +2453,117 @@ void mbx1_err_fatal(unsigned char tid)
spin_unlock(&task->dev->state_lock); spin_unlock(&task->dev->state_lock);
} }
static short *dbg_buf;
static unsigned short dbg_buf_sz, dbg_line_sz;
static int dbg_rp;
int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz)
{
#ifdef OLD_BINARY_SUPPORT
if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
dbg_buf = NULL;
dbg_buf_sz = 0;
dbg_line_sz = 0;
dbg_rp = 0;
return 0;
}
#endif
if (dsp_address_validate(buf, sz, "debug buffer") < 0)
return -1;
if (lsz > sz) {
printk(KERN_ERR
"omapdsp: dbg_buf lsz (%d) is greater than its "
"buffer size (%d)\n", lsz, sz);
return -1;
}
dbg_buf = buf;
dbg_buf_sz = sz;
dbg_line_sz = lsz;
dbg_rp = 0;
return 0;
}
void dsp_dbg_stop(void)
{
dbg_buf = NULL;
}
#ifdef OLD_BINARY_SUPPORT
static void mbx1_dbg_old(struct mbcmd *mb);
#endif
void mbx1_dbg(struct mbcmd *mb) void mbx1_dbg(struct mbcmd *mb)
{
unsigned char tid = mb->cmd_l;
int cnt = mb->data;
char s[80], *s_end = &s[79], *p;
unsigned short *src;
int i;
#ifdef OLD_BINARY_SUPPORT
if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
mbx1_dbg_old(mb);
return;
}
#endif
if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
(tid != OMAP_DSP_TID_ANON)) {
printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
return;
}
if (dbg_buf == NULL) {
printk(KERN_ERR "mbx: DBG command received, but "
"dbg_buf has not been configured yet.\n");
return;
}
if (dsp_mem_enable(dbg_buf) < 0)
return;
src = &dbg_buf[dbg_rp];
p = s;
for (i = 0; i < cnt; i++) {
unsigned short tmp;
/*
* Be carefull that dbg_buf should not be read with
* 1-byte access since it might be placed in DARAM/SARAM
* and it can cause unexpected byteswap.
* For example,
* *(p++) = *(src++) & 0xff;
* causes 1-byte access!
*/
tmp = *src++;
*(p++) = tmp & 0xff;
if (*(p-1) == '\n') {
*p = '\0';
printk(KERN_INFO "%s", s);
p = s;
continue;
}
if (p == s_end) {
*p = '\0';
printk(KERN_INFO "%s\n", s);
p = s;
continue;
}
}
if (p > s) {
*p = '\0';
printk(KERN_INFO "%s\n", s);
}
if ((dbg_rp += cnt + 1) > dbg_buf_sz - dbg_line_sz)
dbg_rp = 0;
dsp_mem_disable(dbg_buf);
}
#ifdef OLD_BINARY_SUPPORT
static void mbx1_dbg_old(struct mbcmd *mb)
{ {
unsigned char tid = mb->cmd_l; unsigned char tid = mb->cmd_l;
char s[80], *s_end = &s[79], *p; char s[80], *s_end = &s[79], *p;
...@@ -2388,7 +2583,13 @@ void mbx1_dbg(struct mbcmd *mb) ...@@ -2388,7 +2583,13 @@ void mbx1_dbg(struct mbcmd *mb)
} }
buf = ipbuf_sys_da->d; buf = ipbuf_sys_da->d;
cnt = buf[0]; cnt = buf[0];
src = dspword_to_virt(MKLONG(buf[1], buf[2])); src = MKVIRT(buf[1], buf[2]);
if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
return;
if (dsp_mem_enable(src) < 0)
return;
p = s; p = s;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
unsigned short tmp; unsigned short tmp;
...@@ -2421,8 +2622,9 @@ void mbx1_dbg(struct mbcmd *mb) ...@@ -2421,8 +2622,9 @@ void mbx1_dbg(struct mbcmd *mb)
} }
release_ipbuf_pvt(ipbuf_sys_da); release_ipbuf_pvt(ipbuf_sys_da);
dsp_mem_disable(src);
} }
#endif /* OLD_BINARY_SUPPORT */
/* /*
* sysfs files * sysfs files
...@@ -2434,17 +2636,6 @@ static ssize_t devname_show(struct device *d, struct device_attribute *attr, ...@@ -2434,17 +2636,6 @@ static ssize_t devname_show(struct device *d, struct device_attribute *attr,
return sprintf(buf, "%s\n", dev->name); return sprintf(buf, "%s\n", dev->name);
} }
#define devstate_name(stat) (\
((stat) == OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\
((stat) == OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
((stat) == OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\
((stat) == OMAP_DSP_DEVSTATE_INVALID) ? "INVALID" :\
((stat) == OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\
((stat) == OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\
((stat) == OMAP_DSP_DEVSTATE_KILLREQ) ? "KILLREQ" :\
((stat) == OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\
"unknown")
static ssize_t devstate_show(struct device *d, struct device_attribute *attr, static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -2622,14 +2813,12 @@ int __init dsp_taskmod_init(void) ...@@ -2622,14 +2813,12 @@ int __init dsp_taskmod_init(void)
return -EINVAL; return -EINVAL;
} }
dsp_task_class = class_create(THIS_MODULE, "dsptask"); dsp_task_class = class_create(THIS_MODULE, "dsptask");
devfs_mk_dir("dsptask");
return 0; return 0;
} }
void dsp_taskmod_exit(void) void dsp_taskmod_exit(void)
{ {
devfs_remove("dsptask");
class_destroy(dsp_task_class); class_destroy(dsp_task_class);
driver_unregister(&dsptask_driver); driver_unregister(&dsptask_driver);
bus_unregister(&dsptask_bus); bus_unregister(&dsptask_bus);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/12/01: DSP Gateway version 3.2 * 200%/05/16: DSP Gateway version 3.3
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -83,7 +83,12 @@ static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count, ...@@ -83,7 +83,12 @@ static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count,
count = devcount * sizeof(long); count = devcount * sizeof(long);
change_cnt = 0; change_cnt = 0;
for (i = 0; i < devcount; i++) { for (i = 0; i < devcount; i++) {
taskstat[i] = taskdev_state(i); /*
* once the device state is read, the 'STALE' bit will be set
* so that the Dynamic Loader can distinguish the new request
* from the old one.
*/
taskstat[i] = taskdev_state_stale(i);
} }
if (copy_to_user(buf, taskstat, count)) if (copy_to_user(buf, taskstat, count))
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/06/29: DSP Gateway version 3.2 * 2004/06/29: DSP Gateway version 3.3
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/06/29: DSP Gateway version 3.2 * 2004/06/29: DSP Gateway version 3.3
*/ */
#ifndef _OMAP_DSP_UACCESS_DSP_H #ifndef _OMAP_DSP_UACCESS_DSP_H
......
...@@ -191,7 +191,7 @@ static int omap_mcbsp_check(unsigned int id) ...@@ -191,7 +191,7 @@ static int omap_mcbsp_check(unsigned int id)
static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_request(void)
{ {
if (cpu_is_omap1510() || cpu_is_omap16xx()) { if (cpu_is_omap1510() || cpu_is_omap16xx()) {
omap_dsp_request_idle(); omap_dsp_request_mem();
clk_use(mcbsp_dsp_ck); clk_use(mcbsp_dsp_ck);
clk_use(mcbsp_api_ck); clk_use(mcbsp_api_ck);
...@@ -210,6 +210,7 @@ static void omap_mcbsp_dsp_request(void) ...@@ -210,6 +210,7 @@ static void omap_mcbsp_dsp_request(void)
static void omap_mcbsp_dsp_free(void) static void omap_mcbsp_dsp_free(void)
{ {
if (cpu_is_omap1510() || cpu_is_omap16xx()) { if (cpu_is_omap1510() || cpu_is_omap16xx()) {
omap_dsp_release_mem();
clk_unuse(mcbsp_dspxor_ck); clk_unuse(mcbsp_dspxor_ck);
clk_unuse(mcbsp_dsp_ck); clk_unuse(mcbsp_dsp_ck);
clk_unuse(mcbsp_api_ck); clk_unuse(mcbsp_api_ck);
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2005/01/17: DSP Gateway version 3.2 * 2005/06/01: DSP Gateway version 3.3
*/ */
#ifndef ASM_ARCH_DSP_H #ifndef ASM_ARCH_DSP_H
...@@ -34,14 +34,16 @@ ...@@ -34,14 +34,16 @@
#define OMAP_DSP_IOCTL_RESET 1 #define OMAP_DSP_IOCTL_RESET 1
#define OMAP_DSP_IOCTL_RUN 2 #define OMAP_DSP_IOCTL_RUN 2
#define OMAP_DSP_IOCTL_SETRSTVECT 3 #define OMAP_DSP_IOCTL_SETRSTVECT 3
#define OMAP_DSP_IOCTL_IDLE 4 #define OMAP_DSP_IOCTL_CPU_IDLE 4
#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5 #define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5
#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6 #define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6
#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7 #define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7
#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8 #define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8
#define OMAP_DSP_IOCTL_GBL_IDLE 9
#define OMAP_DSP_IOCTL_DSPCFG 10 #define OMAP_DSP_IOCTL_DSPCFG 10
#define OMAP_DSP_IOCTL_DSPUNCFG 11 #define OMAP_DSP_IOCTL_DSPUNCFG 11
#define OMAP_DSP_IOCTL_TASKCNT 12 #define OMAP_DSP_IOCTL_TASKCNT 12
#define OMAP_DSP_IOCTL_POLL 13
#define OMAP_DSP_IOCTL_REGMEMR 40 #define OMAP_DSP_IOCTL_REGMEMR 40
#define OMAP_DSP_IOCTL_REGMEMW 41 #define OMAP_DSP_IOCTL_REGMEMW 41
#define OMAP_DSP_IOCTL_REGIOR 42 #define OMAP_DSP_IOCTL_REGIOR 42
...@@ -97,8 +99,12 @@ struct omap_dsp_mapinfo { ...@@ -97,8 +99,12 @@ struct omap_dsp_mapinfo {
#define OMAP_DSP_DEVSTATE_INVALID 0x00000008 #define OMAP_DSP_DEVSTATE_INVALID 0x00000008
#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100 #define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100
#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200 #define OMAP_DSP_DEVSTATE_DELREQ 0x00000200
#define OMAP_DSP_DEVSTATE_KILLREQ 0x00000400
#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000 #define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000
#define OMAP_DSP_DEVSTATE_ADDING 0x00010000
#define OMAP_DSP_DEVSTATE_DELING 0x00020000
#define OMAP_DSP_DEVSTATE_KILLING 0x00040000
#define OMAP_DSP_DEVSTATE_STATE_MASK 0x7fffffff
#define OMAP_DSP_DEVSTATE_STALE 0x80000000
struct omap_dsp_taddinfo { struct omap_dsp_taddinfo {
unsigned char minor; unsigned char minor;
...@@ -133,7 +139,7 @@ struct omap_dsp_varinfo { ...@@ -133,7 +139,7 @@ struct omap_dsp_varinfo {
unsigned short val[0]; unsigned short val[0];
}; };
#define OMAP_DSP_MBPROT_REVISION 0x0018 #define OMAP_DSP_MBPROT_REVISION 0x0019
#define OMAP_DSP_MBCMD_WDSND 0x10 #define OMAP_DSP_MBCMD_WDSND 0x10
#define OMAP_DSP_MBCMD_WDREQ 0x11 #define OMAP_DSP_MBCMD_WDREQ 0x11
...@@ -144,7 +150,8 @@ struct omap_dsp_varinfo { ...@@ -144,7 +150,8 @@ struct omap_dsp_varinfo {
#define OMAP_DSP_MBCMD_BKREQP 0x25 #define OMAP_DSP_MBCMD_BKREQP 0x25
#define OMAP_DSP_MBCMD_TCTL 0x30 #define OMAP_DSP_MBCMD_TCTL 0x30
#define OMAP_DSP_MBCMD_TCTLDATA 0x31 #define OMAP_DSP_MBCMD_TCTLDATA 0x31
#define OMAP_DSP_MBCMD_WDT 0x50 #define OMAP_DSP_MBCMD_POLL 0x32
#define OMAP_DSP_MBCMD_WDT 0x50 /* v3.3: obsolete */
#define OMAP_DSP_MBCMD_RUNLEVEL 0x51 #define OMAP_DSP_MBCMD_RUNLEVEL 0x51
#define OMAP_DSP_MBCMD_PM 0x52 #define OMAP_DSP_MBCMD_PM 0x52
#define OMAP_DSP_MBCMD_SUSPEND 0x53 #define OMAP_DSP_MBCMD_SUSPEND 0x53
...@@ -217,6 +224,7 @@ struct omap_dsp_varinfo { ...@@ -217,6 +224,7 @@ struct omap_dsp_varinfo {
#define OMAP_DSP_EID_NOMEM 0xc0 #define OMAP_DSP_EID_NOMEM 0xc0
#define OMAP_DSP_EID_NORES 0xc1 #define OMAP_DSP_EID_NORES 0xc1
#define OMAP_DSP_EID_IPBFULL 0xc2 #define OMAP_DSP_EID_IPBFULL 0xc2
#define OMAP_DSP_EID_WDT 0xd0
#define OMAP_DSP_EID_TASKNOTRDY 0xe0 #define OMAP_DSP_EID_TASKNOTRDY 0xe0
#define OMAP_DSP_EID_TASKBSY 0xe1 #define OMAP_DSP_EID_TASKBSY 0xe1
#define OMAP_DSP_EID_TASKERR 0xef #define OMAP_DSP_EID_TASKERR 0xef
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* 2004/09/22: DSP Gateway version 3.2 * 2005/06/03: DSP Gateway version 3.3
*/ */
#ifndef ASM_ARCH_DSP_COMMON_H #ifndef ASM_ARCH_DSP_COMMON_H
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
void omap_dsp_pm_suspend(void); void omap_dsp_pm_suspend(void);
void omap_dsp_pm_resume(void); void omap_dsp_pm_resume(void);
void omap_dsp_request_idle(void); void omap_dsp_request_mpui(void);
void omap_dsp_release_mpui(void);
int omap_dsp_request_mem(void);
int omap_dsp_release_mem(void);
#endif /* ASM_ARCH_DSP_COMMON_H */ #endif /* ASM_ARCH_DSP_COMMON_H */
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