From b3ddf280517f67ea6bf138be9919a615f9737d88 Mon Sep 17 00:00:00 2001 From: Toshiro Kobayashi Date: Wed, 27 Jul 2005 04:06:19 -0700 Subject: [PATCH] [PATCH] ARM: OMAP: DSP Gateway v3.3 This is DSP Gateway v3.3 patch. --- arch/arm/plat-omap/dsp/dsp.h | 96 ++-- arch/arm/plat-omap/dsp/dsp_common.c | 381 +++++++++++++--- arch/arm/plat-omap/dsp/dsp_common.h | 45 +- arch/arm/plat-omap/dsp/dsp_core.c | 155 ++++--- arch/arm/plat-omap/dsp/dsp_ctl.c | 354 +++++++++------ arch/arm/plat-omap/dsp/dsp_ctl_core.c | 18 +- arch/arm/plat-omap/dsp/dsp_mem.c | 418 ++++++++++++------ arch/arm/plat-omap/dsp/error.c | 19 +- arch/arm/plat-omap/dsp/fifo.h | 2 +- arch/arm/plat-omap/dsp/hardware_dsp.h | 16 +- arch/arm/plat-omap/dsp/ipbuf.c | 118 +++-- arch/arm/plat-omap/dsp/ipbuf.h | 11 +- arch/arm/plat-omap/dsp/mblog.c | 17 +- arch/arm/plat-omap/dsp/proclist.h | 2 +- arch/arm/plat-omap/dsp/task.c | 589 ++++++++++++++++--------- arch/arm/plat-omap/dsp/taskwatch.c | 9 +- arch/arm/plat-omap/dsp/uaccess_dsp.S | 2 +- arch/arm/plat-omap/dsp/uaccess_dsp.h | 2 +- arch/arm/plat-omap/mcbsp.c | 3 +- include/asm-arm/arch-omap/dsp.h | 18 +- include/asm-arm/arch-omap/dsp_common.h | 7 +- 21 files changed, 1603 insertions(+), 679 deletions(-) diff --git a/arch/arm/plat-omap/dsp/dsp.h b/arch/arm/plat-omap/dsp/dsp.h index 6282a281503..0a4876630f7 100644 --- a/arch/arm/plat-omap/dsp/dsp.h +++ b/arch/arm/plat-omap/dsp/dsp.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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" @@ -31,6 +31,7 @@ #ifdef OLD_BINARY_SUPPORT #define MBREV_3_0 0x0017 +#define MBREV_3_2 0x0018 #endif #define DSP_INIT_PAGE 0xfff000 @@ -38,6 +39,22 @@ #define IDLEPG_BASE 0xfffe00 #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_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox @@ -49,8 +66,22 @@ #define TASKDEV_MAX 254 #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 +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 { unsigned short cmd_l:8; @@ -79,26 +110,32 @@ struct mb_exarg { extern void dsp_mb_start(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, int try_cnt); -extern int __mbsend(struct mbcmd *mb); -extern int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, - int recovery_flag); -#define dsp_mbsend(mb) __dsp_mbsend(mb, NULL, 0) -#define dsp_mbsend_recovery(mb) __dsp_mbsend(mb, NULL, 1) -#define dsp_mbsend_exarg(mb, arg) __dsp_mbsend(mb, arg, 0) -extern int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, - wait_queue_head_t *q); -#define dsp_mbsend_and_wait(mb, q) \ - __dsp_mbsend_and_wait(mb, NULL, q) -#define dsp_mbsend_and_wait_exarg(mb, arg, q) \ - __dsp_mbsend_and_wait(mb, arg, q) +extern int __mbcmd_send(struct mbcmd *mb); +extern int __dsp_mbcmd_send(struct mbcmd *mb, struct mb_exarg *arg, + int recovery_flag); +#define dsp_mbcmd_send(mb) __dsp_mbcmd_send(mb, NULL, 0) +#define dsp_mbcmd_send_exarg(mb, arg) __dsp_mbcmd_send(mb, arg, 0) +extern int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg, + wait_queue_head_t *q); +#define dsp_mbcmd_send_and_wait(mb, q) \ + __dsp_mbcmd_send_and_wait(mb, NULL, q) +#define dsp_mbcmd_send_and_wait_exarg(mb, arg, q) \ + __dsp_mbcmd_send_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_stop(void); -extern int ipbuf_config(unsigned short ln, unsigned short lsz, - unsigned long adr); +extern int ipbuf_config(unsigned short ln, unsigned short lsz, void *base); +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 void unuse_ipbuf_nowait(unsigned short bid); extern void unuse_ipbuf(unsigned short bid); @@ -110,6 +147,8 @@ extern void balance_ipbuf(void); (ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \ } while(0) +extern int mbx_revision; + extern int dsp_is_ready(void); extern int dspuncfg(void); extern void dsp_runlevel(unsigned char level); @@ -125,16 +164,24 @@ extern int dsp_rmdev(char *name); extern int dsp_tadd(unsigned char minor, unsigned long adr); extern int dsp_tdel(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 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_disable(void *adr); -extern int __dsp_mem_enable(void *adr); -extern int __dsp_mem_disable(void *adr); +extern void dsp_mem_disable(void *adr); +extern void dsp_mem_usecount_clear(void); +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 void dsp_mem_start(void); +extern void dsp_mem_stop(void); extern void dsp_twch_start(void); extern void dsp_twch_stop(void); @@ -165,14 +212,9 @@ extern const struct cmdinfo *cmdinfo[]; #define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name) extern char *subcmd_name(struct mbcmd *mb); -enum mblog_dir { - MBLOG_DIR_AD, - MBLOG_DIR_DA, -}; - -extern void mblog_add(struct mbcmd *mb, enum mblog_dir dir); +extern void mblog_add(struct mbcmd *mb, enum arm_dsp_dir dir); #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 */ #define mblog_printcmd(mb, dir) do {} while(0) #endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ diff --git a/arch/arm/plat-omap/dsp/dsp_common.c b/arch/arm/plat-omap/dsp/dsp_common.c index e24c1afbbad..a8b72ee81d1 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.c +++ b/arch/arm/plat-omap/dsp/dsp_common.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -40,14 +40,28 @@ struct clk *dsp_ck_handle; struct clk *api_ck_handle; -unsigned long dspmem_base, dspmem_size; -int dsp_runstat = RUNSTAT_RESET; -unsigned short dsp_icrmask = DSPREG_ICR_EMIF_IDLE_DOMAIN | - DSPREG_ICR_DPLL_IDLE_DOMAIN | - DSPREG_ICR_PER_IDLE_DOMAIN | - DSPREG_ICR_CACHE_IDLE_DOMAIN | - DSPREG_ICR_DMA_IDLE_DOMAIN | - DSPREG_ICR_CPU_IDLE_DOMAIN; +unsigned long dspmem_base, dspmem_size, + daram_base, daram_size, + saram_base, saram_size; + +struct cpustat { + struct semaphore sem; + enum e_cpustat stat; + 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) { @@ -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 */ -#define IDLE_TEXT_SIZE 28 -#define IDLE_TEXT(icr) { \ +#define GBL_IDLE_TEXT_SIZE 52 +#define GBL_IDLE_TEXT_INIT { \ + /* SAM */ \ + 0x3c, 0x4a, /* 0x3c4a: MOV 0x4, AR2 */ \ + 0xf4, 0x41, 0xfc, 0xff, /* 0xf441fcff: AND 0xfcff, *AR2 */ \ /* disable WDT */ \ - 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: mov AR3 0x3404 */ \ - 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: mov *AR3 0x00f5 */ \ - 0x9a, /* 0x9a: port */ \ - 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: mov *AR3 0x00a0 */ \ - 0x9a, /* 0x9a: port */ \ + 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 */ \ + /* *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 */ \ - 0x3c, 0x1b, /* 0x3c1b: mov AR3 0x1 */ \ - 0xe6, 0x61, (icr), /* 0xe661**: mov *AR3, icr */ \ - 0x9a, /* 0x9a: port */ \ + 0x3c, 0x1b, /* 0x3c1b: MOV AR3 0x1 */ \ + 0xfb, 0x61, (icrh), (icrl), /* 0xfb61****: MOV *AR3, icr */ \ + 0x9a, /* 0x9a: PORT */ \ /* idle and loop forever */ \ - 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: idle */ \ - 0x4a, 0x7a, /* 0x4a7a: b -6 (infinite loop) */ \ - 0x20, 0x20 /* 0x20: nop */ \ + 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: IDLE */ \ + 0x4a, 0x7a, /* 0x4a7a: B -6 (infinite loop) */ \ + 0x20, 0x20, 0x20 /* 0x20: nop */ \ } /* @@ -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; -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(); clk_use(api_ck_handle); /* * icr settings: * 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 & - ~(DSPREG_ICR_DMA_IDLE_DOMAIN | DSPREG_ICR_DPLL_IDLE_DOMAIN) & - 0xff; + icr_tmp = cpustat.icrmask & ~(DSPREG_ICR_DMA_IDLE_DOMAIN | + DSPREG_ICR_DPLL_IDLE_DOMAIN); + 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), - IDLE_TEXT_SIZE); + CPU_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); - clk_unuse(api_ck_handle); - udelay(10); /* to make things stable */ __dsp_run(); - dsp_runstat = RUNSTAT_IDLE; - preempt_enable(); - enable_irq(INT_DSP_MMU); + udelay(100); /* to make things stable */ + clk_unuse(api_ck_handle); } 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) return; idle_boot_base = adr; - if (size < IDLE_TEXT_SIZE) { + if ((size < GBL_IDLE_TEXT_SIZE) || + (size < CPU_IDLE_TEXT_SIZE)) { printk(KERN_ERR "omapdsp: size for idle program is not enough!\n"); 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; @@ -197,9 +272,10 @@ void omap_dsp_pm_resume(void) omap_writew(save_arm_idlect2, ARM_IDLECT2); /* Run DSP, if it was running */ - if (dsp_runstat != RUNSTAT_RESET) + if (cpustat.stat != CPUSTAT_RESET) __dsp_run(); } + static int init_done; static int __init omap_dsp_init(void) @@ -209,12 +285,20 @@ static int __init omap_dsp_init(void) if (cpu_is_omap1510()) { dspmem_base = OMAP1510_DSP_BASE; 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 #ifdef CONFIG_ARCH_OMAP16XX if (cpu_is_omap16xx()) { dspmem_base = OMAP16XX_DSP_BASE; 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 if (dspmem_size == 0) { @@ -243,31 +327,228 @@ static int __init omap_dsp_init(void) return 0; } -void omap_dsp_request_idle(void) +static void dsp_cpustat_update(void) { - if (dsp_runstat == RUNSTAT_RESET) { - if (!init_done) - omap_dsp_init(); - dsp_idle(); + if (!init_done) + omap_dsp_init(); + + 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); EXPORT_SYMBOL(omap_dsp_pm_suspend); 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 EXPORT_SYMBOL(dsp_ck_handle); EXPORT_SYMBOL(api_ck_handle); EXPORT_SYMBOL(dspmem_base); EXPORT_SYMBOL(dspmem_size); -EXPORT_SYMBOL(dsp_runstat); -EXPORT_SYMBOL(dsp_icrmask); +EXPORT_SYMBOL(daram_base); +EXPORT_SYMBOL(daram_size); +EXPORT_SYMBOL(saram_base); +EXPORT_SYMBOL(saram_size); EXPORT_SYMBOL(dsp_set_rstvect); -EXPORT_SYMBOL(dsp_idle); 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); #endif diff --git a/arch/arm/plat-omap/dsp/dsp_common.h b/arch/arm/plat-omap/dsp/dsp_common.h index a4b2610a39d..36034bd8ae4 100644 --- a/arch/arm/plat-omap/dsp/dsp_common.h +++ b/arch/arm/plat-omap/dsp/dsp_common.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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" @@ -52,28 +52,28 @@ * default setting: wordswap = all, byteswap = APIMEM only */ #define mpui_wordswap_on() \ - { \ + do { \ omap_writel( \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \ } while(0) #define mpui_wordswap_off() \ - { \ + do { \ omap_writel( \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \ } while(0) #define mpui_byteswap_on() \ - { \ + do { \ omap_writel( \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \ } while(0) #define mpui_byteswap_off() \ - { \ + do { \ omap_writel( \ (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \ @@ -83,13 +83,13 @@ * TC wordswap on / off */ #define tc_wordswap() \ - { \ + do { \ omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \ TC_ENDIANISM); \ } while(0) #define tc_noswap() \ - { \ + do { \ omap_writel(omap_readl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \ TC_ENDIANISM); \ } while(0) @@ -102,16 +102,31 @@ #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 RUNSTAT_RESET 0 -#define RUNSTAT_IDLE 1 -#define RUNSTAT_RUN 2 - extern struct clk *dsp_ck_handle; extern struct clk *api_ck_handle; -extern unsigned long dspmem_base, dspmem_size; -extern int dsp_runstat; -extern unsigned short dsp_icrmask; +extern unsigned long dspmem_base, dspmem_size, + daram_base, daram_size, + 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); -void dsp_idle(void); 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); diff --git a/arch/arm/plat-omap/dsp/dsp_core.c b/arch/arm/plat-omap/dsp/dsp_core.c index e86d3599a95..c0a06492f40 100644 --- a/arch/arm/plat-omap/dsp/dsp_core.c +++ b/arch/arm/plat-omap/dsp/dsp_core.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -55,17 +55,11 @@ enum mbseq_check_level { }; 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 @@ -78,7 +72,11 @@ extern void mbx1_bkyld(struct mbcmd *mb); extern void mbx1_bksndp(struct mbcmd *mb); extern void mbx1_bkreqp(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); +#endif extern void mbx1_suspend(struct mbcmd *mb); static void mbx1_kfunc(struct mbcmd *mb); extern void mbx1_tcfg(struct mbcmd *mb); @@ -100,7 +98,11 @@ static const struct cmdinfo cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp }, cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp }, 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 }, +#endif cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL }, cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL }, cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend }, @@ -129,7 +131,7 @@ const struct cmdinfo *cmdinfo[128] = { &cif_bksndp, &cif_bkreqp, &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, @@ -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, +#ifdef OLD_BINARY_SUPPORT + /* v3.3 obsolete */ /*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_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) #define print_mb_mmu_abort(mb) do {} while(0) #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; unsigned long flags; @@ -220,12 +227,13 @@ int __mbsend(struct mbcmd *mb) return -1; } - mb->seq = mbseq_send & 1; - mbseq_send++; - if (sync_seq) - sync_seq->ad_arm = mbseq_send; - mblog_add(mb, MBLOG_DIR_AD); - mblog_printcmd(mb, MBLOG_DIR_AD); + if (mbseq) { + mb->seq = mbseq->ad_arm; + mbseq->ad_arm++; + } else + mb->seq = 0; + mblog_add(mb, DIR_A2D); + mblog_printcmd(mb, DIR_A2D); omap_writew(mb_hw->data, MAILBOX_ARM2DSP1); omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b); @@ -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); int ret = 0; @@ -257,10 +265,18 @@ int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, int recovery_flag) if (arg) { /* we have extra argument */ 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) { printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n"); + dsp_mem_disable(ipbuf_sys_ad); ret = -EBUSY; goto out; } @@ -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->s = arg->tid; - if (__dsp_mem_disable(ipbuf_sys_ad) < 0) - goto out; + dsp_mem_disable(ipbuf_sys_ad); } - ret = __mbsend(mb); + ret = __mbcmd_send(mb); out: up(&mbsend_sem); return ret; } -int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, - wait_queue_head_t *q) +int __dsp_mbcmd_send_and_wait(struct mbcmd *mb, struct mb_exarg *arg, + wait_queue_head_t *q) { long current_state; DECLARE_WAITQUEUE(wait, current); @@ -288,36 +303,72 @@ int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, add_wait_queue(q, &wait); current_state = current->state; 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); remove_wait_queue(q, &wait); return -1; } - schedule(); + schedule_timeout(DSP_TIMEOUT); set_current_state(current_state); remove_wait_queue(q, &wait); 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) { - mbseq_send = 0; - mbseq_expect = 0; + mbx1_valid = 1; /* start interpreting */ + mbseq_expect_tmp = 0; } 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; } -/* - * dsp_mb_config() is called from mbx1 workqueue - */ -void dsp_mb_config(void *sync_seq_adr) +int dsp_mb_config(void *p) { - sync_seq = sync_seq_adr; - sync_seq->da_arm = mbseq_expect; + unsigned long flags; + + 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) mb = &mbq.mb[mbq.rp]; - mblog_add(mb, MBLOG_DIR_DA); - mblog_printcmd(mb, MBLOG_DIR_DA); + mblog_add(mb, DIR_D2A); + mblog_printcmd(mb, DIR_D2A); /* * call handler for each command @@ -386,7 +437,6 @@ static DECLARE_WORK(mbx1_work, (void (*)(void *))do_mbx1, NULL); /* * kernel function dispatcher */ -#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC extern void mbx1_fbctl_disable(void); 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); } } -#endif static void mbx1_kfunc(struct mbcmd *mb) { switch (mb->cmd_l) { -#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC case OMAP_DSP_MBCMD_KFUNC_FBCTL: mbx1_kfunc_fbctl(mb->data); break; -#endif default: printk(KERN_ERR @@ -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); #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) { case MBSEQ_CHECK_NONE: break; @@ -449,9 +500,7 @@ static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } - mbseq_expect++; - if (sync_seq) - sync_seq->da_arm = mbseq_expect; + (*mbseq_expect)++; mbq_inc(mbq.wp); if (mbq.wp == mbq.rp) { /* mbq is full */ @@ -585,6 +634,9 @@ static int __init dsp_drv_probe(struct device *dev) goto fail6; } + /* MMU interrupt is not enabled until DSP runs */ + disable_irq(INT_DSP_MMU); + #if 0 ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev); if (ret) { @@ -617,7 +669,7 @@ fail1: static int dsp_drv_remove(struct device *dev) { - __dsp_reset(); + dsp_cpustat_request(CPUSTAT_RESET); #if 0 free_irq(INT_MPUIO, dev); @@ -626,6 +678,9 @@ static int dsp_drv_remove(struct device *dev) free_irq(INT_D2A_MB2, dev); free_irq(INT_D2A_MB1, dev); + /* recover disable_depth */ + enable_irq(INT_DSP_MMU); + dspuncfg(); dsp_taskmod_exit(); mblog_exit(); diff --git a/arch/arm/plat-omap/dsp/dsp_ctl.c b/arch/arm/plat-omap/dsp/dsp_ctl.c index 985b852a8fd..4031cf8e85c 100644 --- a/arch/arm/plat-omap/dsp/dsp_ctl.c +++ b/arch/arm/plat-omap/dsp/dsp_ctl.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -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); extern struct device_attribute dev_attr_ipbuf; -static enum { +static enum cfgstat { CFG_ERR, CFG_READY, CFG_SUSPEND } cfgstat; -static int mbx_revision; +int mbx_revision; static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q); static unsigned short ioctl_wait_cmd; static DECLARE_MUTEX(ioctl_sem); @@ -62,33 +62,6 @@ static unsigned char n_stask; /* * 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 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); 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) { printk(KERN_ERR "omapdsp: register read error!\n"); @@ -128,7 +101,7 @@ static int dsp_regwrite(unsigned short cmd_l, unsigned short adr, }; mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); - dsp_mbsend_exarg(&mb, &arg); + dsp_mbcmd_send_exarg(&mb, &arg); return 0; } @@ -142,7 +115,7 @@ static int dsp_getvar(unsigned char varid, unsigned short *val, int sz) ioctl_wait_cmd = MBCMD(GETVAR); 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) { printk(KERN_ERR "omapdsp: variable read error!\n"); @@ -159,10 +132,7 @@ up_out: static int dsp_setvar(unsigned char varid, unsigned short val) { - struct mbcmd mb; - - mbcmd_set(mb, MBCMD(SETVAR), varid, val); - dsp_mbsend(&mb); + dsp_mbsend(MBCMD(SETVAR), varid, val); return 0; } @@ -182,6 +152,15 @@ static int dspcfg(void) 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_twch_start(); dsp_mem_start(); @@ -190,7 +169,7 @@ static int dspcfg(void) mbx_revision = -1; ioctl_wait_cmd = MBCMD(DSPCFG); 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) { printk(KERN_ERR "omapdsp: configuration error!\n"); @@ -199,16 +178,30 @@ static int dspcfg(void) 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) { up(&ioctl_sem); dspuncfg(); + dsp_mem_disable((void *)dspmem_base); return -EINVAL; } cfgstat = CFG_READY; /* 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; /* create runtime sysfs entries */ @@ -216,6 +209,7 @@ static int dspcfg(void) device_create_file(&dsp_device.dev, &dev_attr_ipbuf); up_out: + dsp_mem_disable((void *)dspmem_base); up(&ioctl_sem); return ret; } @@ -229,7 +223,7 @@ int dspuncfg(void) if (down_interruptible(&ioctl_sem)) return -ERESTARTSYS; - + /* FIXME: lock task module */ /* remove runtime sysfs entries */ @@ -238,7 +232,9 @@ int dspuncfg(void) dsp_mb_stop(); dsp_twch_stop(); + dsp_mem_stop(); dsp_err_stop(); + dsp_dbg_stop(); dsp_task_unconfig_all(); ipbuf_stop(); cfgstat = CFG_ERR; @@ -252,33 +248,76 @@ int dsp_is_ready(void) return (cfgstat == CFG_READY) ? 1 : 0; } -void dsp_runlevel(unsigned char level) +/* + * polls all tasks + */ +int dsp_poll(void) { 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) - dsp_mbsend_recovery(&mb); + dsp_mbsend_recovery(MBCMD(RUNLEVEL), level, 0); 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) { struct mbcmd mb; 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)) return -ERESTARTSYS; + cfgstat_save_suspend = cfgstat; if (!dsp_is_ready()) { - ret = -EINVAL; - goto up_out; + if (dsp_cpustat_get_stat() == CPUSTAT_RUN) { + 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); 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) { printk(KERN_ERR "omapdsp: DSP suspend error!\n"); @@ -287,6 +326,7 @@ int dsp_suspend(void) } udelay(100); +transition: cfgstat = CFG_SUSPEND; up_out: up(&ioctl_sem); @@ -295,29 +335,24 @@ up_out: int dsp_resume(void) { - if (cfgstat != CFG_SUSPEND) - return 0; + if (cfgstat != CFG_SUSPEND) { + printk(KERN_ERR "omapdsp: DSP is not in suspend state.\n"); + return -EINVAL; + } - cfgstat = CFG_READY; + cfgstat = cfgstat_save_suspend; return 0; } static void dsp_fbctl_enable(void) { -#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC - struct mbcmd mb; - - mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, - OMAP_DSP_MBCMD_FBCTL_ENABLE); - dsp_mbsend(&mb); -#endif + dsp_mbsend(MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, + OMAP_DSP_MBCMD_FBCTL_ENABLE); } static int dsp_fbctl_disable(void) { int ret = 0; - -#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC struct mbcmd mb; if (down_interruptible(&ioctl_sem)) @@ -326,13 +361,12 @@ static int dsp_fbctl_disable(void) ioctl_wait_cmd = MBCMD(KFUNC); mbcmd_set(mb, MBCMD(KFUNC), OMAP_DSP_MBCMD_KFUNC_FBCTL, 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) { printk(KERN_ERR "omapdsp: fb disable error!\n"); ret = -EINVAL; } up(&ioctl_sem); -#endif return ret; } @@ -350,19 +384,23 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, * command level 1: commands which don't need lock */ case OMAP_DSP_IOCTL_RUN: - dsp_run(); + dsp_cpustat_request(CPUSTAT_RUN); break; case OMAP_DSP_IOCTL_RESET: - dsp_reset(); + dsp_cpustat_request(CPUSTAT_RESET); break; case OMAP_DSP_IOCTL_SETRSTVECT: ret = dsp_set_rstvect((unsigned long)arg); break; - case OMAP_DSP_IOCTL_IDLE: - dsp_idle(); + case OMAP_DSP_IOCTL_CPU_IDLE: + dsp_cpustat_request(CPUSTAT_CPU_IDLE); + break; + + case OMAP_DSP_IOCTL_GBL_IDLE: + dsp_cpustat_request(CPUSTAT_GBL_IDLE); break; case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON: @@ -389,7 +427,7 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, return -EFAULT; mb.cmd = u_cmd.cmd; mb.data = u_cmd.data; - ret = dsp_mbsend((struct mbcmd *)&mb); + ret = dsp_mbcmd_send((struct mbcmd *)&mb); break; } @@ -425,20 +463,27 @@ static int dsp_ctl_ioctl(struct inode *inode, struct file *file, ret = dsp_task_count(); break; + case OMAP_DSP_IOCTL_POLL: + ret = dsp_poll(); + break; + case OMAP_DSP_IOCTL_FBDIS: ret = dsp_fbctl_disable(); break; + /* + * FIXME: cpu status control for suspend - resume + */ case OMAP_DSP_IOCTL_SUSPEND: if ((ret = dsp_suspend()) < 0) break; - dsp_reset(); + dsp_cpustat_request(CPUSTAT_RESET); break; case OMAP_DSP_IOCTL_RESUME: if ((ret = dsp_resume()) < 0) break; - dsp_run(); + dsp_cpustat_request(CPUSTAT_RUN); break; case OMAP_DSP_IOCTL_REGMEMR: @@ -547,7 +592,7 @@ void mbx1_dspcfg(struct mbcmd *mb) { unsigned char last = mb->cmd_l & 0x80; unsigned char cfgcmd = mb->cmd_l & 0x7f; - static unsigned long tmp_ipbuf_sys_da; + static unsigned long tmp_ipb_adr; /* mailbox protocol check */ if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) { @@ -563,7 +608,8 @@ void mbx1_dspcfg(struct mbcmd *mb) if (mbx_revision == OMAP_DSP_MBPROT_REVISION) return; #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 "mbx: ***** old DSP binary *****\n" " Please update your DSP application.\n"); @@ -576,7 +622,7 @@ void mbx1_dspcfg(struct mbcmd *mb) " expected=0x%04x, received=0x%04x\n", OMAP_DSP_MBPROT_REVISION, mb->data); mbx_revision = -1; - goto abort; + goto abort1; } } @@ -601,15 +647,15 @@ void mbx1_dspcfg(struct mbcmd *mb) switch (cfgcmd) { case OMAP_DSP_MBCMD_DSPCFG_SYSADRH: - tmp_ipbuf_sys_da = (unsigned long)mb->data << 16; + tmp_ipb_adr = (unsigned long)mb->data << 16; break; case OMAP_DSP_MBCMD_DSPCFG_SYSADRL: - tmp_ipbuf_sys_da |= mb->data; + tmp_ipb_adr |= mb->data; break; case OMAP_DSP_MBCMD_DSPCFG_ABORT: - goto abort; + goto abort1; default: printk(KERN_ERR @@ -619,24 +665,23 @@ void mbx1_dspcfg(struct mbcmd *mb) } if (last) { - unsigned long badr; + void *badr; unsigned short bln; unsigned short bsz; 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 */ - if (tmp_ipbuf_sys_da & 0x1) { - printk(KERN_ERR - "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); + ipb_sys_da = dspword_to_virt(tmp_ipb_adr); + if (ipbuf_sys_config(ipb_sys_da, DIR_D2A) < 0) + goto abort1; if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n"); - return; + goto abort1; } /* * read configuration data on system IPBUF @@ -646,47 +691,95 @@ void mbx1_dspcfg(struct mbcmd *mb) if (mbx_revision == OMAP_DSP_MBPROT_REVISION) { #endif buf = ipbuf_sys_da->d; - n_stask = buf[0]; - bln = buf[1]; - bsz = buf[2]; - badr = MKLONG(buf[3], buf[4]); - /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[5], buf[6])); */ - ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[7], buf[8])); - sync_seq = dspword_to_virt(MKLONG(buf[9], buf[10])); + 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 = 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 + } 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) { buf = ipbuf_sys_da->d; - n_stask = buf[0]; - bln = buf[1]; - bsz = buf[2]; - badr = MKLONG(buf[3], buf[4]); - /* bkeep = buf[5]; */ - /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[6], buf[67)); */ - ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[8], buf[9])); - sync_seq = dspword_to_virt(MKLONG(buf[10], buf[11])); + n_stask = buf[0]; + bln = buf[1]; + bsz = buf[2]; + badr = MKVIRT(buf[3], buf[4]); + /* bkeep = buf[5]; */ + /* ipb_sys_da = MKVIRT(buf[6], buf[7]); */ + ipb_sys_ad = MKVIRT(buf[8], buf[9]); + mbseq = MKVIRT(buf[10], buf[11]); + dbg_buf = NULL; + dbg_buf_sz = 0; + dbg_line_sz = 0; + mem_syncp = NULL; } else /* should not occur */ - goto abort; -#endif - - /* ipbuf_config() should be done in interrupt routine. */ - if (ipbuf_config(bln, bsz, badr) < 0) - goto abort; + goto abort1; +#endif /* OLD_BINARY_SUPPORT */ - 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; wake_up_interruptible(&ioctl_wait_q); } return; -abort: +abort2: + ipbuf_stop(); +abort1: wake_up_interruptible(&ioctl_wait_q); 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) { if (!waitqueue_active(&ioctl_wait_q) || @@ -743,7 +836,7 @@ void mbx1_getvar(struct mbcmd *mb) for (i = 0; i < 5; i++) { varread_val[i] = buf[i]; } - ipbuf_sys_da->s = OMAP_DSP_TID_FREE; + release_ipbuf_pvt(ipbuf_sys_da); break; } } @@ -765,51 +858,54 @@ static ssize_t ifver_show(struct device *dev, struct device_attribute *attr, * * 3.2: sysfs / udev support * 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. * - * len += sprintf(buf, "3.1\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.3\n"); return len; } 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) { -#if 0 - if (dsp_is_ready()) { - int ret; - unsigned short val; + return sprintf(buf, "%s\n", cpustat_name(dsp_cpustat_get_stat())); +} - if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_ICRMASK, &val, 1)) < 0) - return ret; - if (val != dsp_icrmask) - printk(KERN_WARNING - "omapdsp: icrmask value is inconsistent!\n"); - } -#endif - return sprintf(buf, "0x%04x\n", dsp_icrmask); +static struct device_attribute dev_attr_cpustat = __ATTR_RO(cpustat); + +static ssize_t icrmask_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "0x%04x\n", dsp_cpustat_get_icrmask()); } static ssize_t icrmask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + unsigned short mask; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - dsp_icrmask = simple_strtol(buf, NULL, 16); + mask = simple_strtol(buf, NULL, 16); + dsp_cpustat_set_icrmask(mask); 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) return ret; } @@ -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); */ -#ifdef CONFIG_FB_OMAP_EXTERNAL_LCDC void mbx1_fbctl_disable(void) { if (!waitqueue_active(&ioctl_wait_q) || @@ -861,7 +956,6 @@ void mbx1_fbctl_disable(void) ioctl_wait_cmd = 0; wake_up_interruptible(&ioctl_wait_q); } -#endif #ifdef CONFIG_PROC_FS /* for backward compatibility */ @@ -902,6 +996,7 @@ struct file_operations dsp_ctl_fops = { void __init dsp_ctl_init(void) { 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); #ifdef CONFIG_PROC_FS dsp_ctl_create_proc(); @@ -911,6 +1006,7 @@ void __init dsp_ctl_init(void) void dsp_ctl_exit(void) { 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); #ifdef CONFIG_PROC_FS dsp_ctl_remove_proc(); diff --git a/arch/arm/plat-omap/dsp/dsp_ctl_core.c b/arch/arm/plat-omap/dsp/dsp_ctl_core.c index 88df7cbba4b..6eb85920b6e 100644 --- a/arch/arm/plat-omap/dsp/dsp_ctl_core.c +++ b/arch/arm/plat-omap/dsp/dsp_ctl_core.c @@ -21,14 +21,13 @@ * along with this program; if not, write to the Free Software * 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 #include #include #include -#include #include #include #include "hardware_dsp.h" @@ -75,13 +74,12 @@ static struct file_operations dsp_ctl_core_fops = { static const struct dev_list { unsigned int minor; char *devname; - char *devfs_name; umode_t mode; } dev_list[] = { - {CTL_MINOR, "dspctl", "dspctl/ctl", S_IRUSR | S_IWUSR}, - {MEM_MINOR, "dspmem", "dspctl/mem", S_IRUSR | S_IWUSR | S_IRGRP}, - {TWCH_MINOR, "dsptwch", "dspctl/twch", S_IRUSR | S_IWUSR | S_IRGRP}, - {ERR_MINOR, "dsperr", "dspctl/err", S_IRUSR | S_IRGRP}, + {CTL_MINOR, "dspctl", S_IRUSR | S_IWUSR}, + {MEM_MINOR, "dspmem", S_IRUSR | S_IWUSR | S_IRGRP}, + {TWCH_MINOR, "dsptwch", S_IRUSR | S_IWUSR | S_IRGRP}, + {ERR_MINOR, "dsperr", S_IRUSR | S_IRGRP}, }; 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"); - devfs_mk_dir("dspctl"); for (i = 0; i < ARRAY_SIZE(dev_list); i++) { class_device_create(dsp_ctl_class, MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor), 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; @@ -118,12 +112,10 @@ void dsp_ctl_core_exit(void) int i; for (i = 0; i < ARRAY_SIZE(dev_list); i++) { - devfs_remove(dev_list[i].devfs_name); class_device_destroy(dsp_ctl_class, MKDEV(OMAP_DSP_CTL_MAJOR, dev_list[i].minor)); } - devfs_remove("dspctl"); class_destroy(dsp_ctl_class); unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl"); diff --git a/arch/arm/plat-omap/dsp/dsp_mem.c b/arch/arm/plat-omap/dsp/dsp_mem.c index 972e54c52cb..afae8ac6072 100644 --- a/arch/arm/plat-omap/dsp/dsp_mem.c +++ b/arch/arm/plat-omap/dsp/dsp_mem.c @@ -22,7 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Toshihiro Kobayashi - * 2005/02/17: DSP Gateway version 3.2 + * 2005/06/09: DSP Gateway version 3.3 */ #include @@ -42,8 +42,8 @@ #include #include #include +#include #include "uaccess_dsp.h" -#include "ipbuf.h" #include "dsp.h" #define SZ_1MB 0x100000 @@ -99,9 +99,12 @@ enum exmap_type { struct exmap_tbl { unsigned int valid:1; unsigned int cntnu:1; /* grouping */ + int usecount; /* reference count by mmap */ enum exmap_type type; - void *buf; - void *vadr; + void *buf; /* virtual address of the buffer, + * i.e. 0xc0000000 - */ + void *vadr; /* DSP shadow space, + * i.e. 0xe0000000 - 0xe0ffffff */ unsigned int order; }; #define DSPMMU_TLB_LINES 32 @@ -112,6 +115,7 @@ static int dsp_exunmap(unsigned long dspadr); static void *dspvect_page; static unsigned long dsp_fault_adr; +static struct mem_sync_struct mem_sync; static __inline__ unsigned long lineup_offset(unsigned long adr, unsigned long ref, @@ -125,6 +129,47 @@ static __inline__ unsigned long lineup_offset(unsigned long adr, 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(): * reserve or release kernel memory for exmap(). @@ -262,11 +307,21 @@ static unsigned long dsp_mem_get_dma_pages(unsigned int 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 page *page, *ps, *pe; 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) { case ORDER_1MB: pool = &kmem_pool_1M; @@ -358,6 +413,7 @@ static void exmap_clear_armmmu(unsigned long virt, unsigned long size) static int exmap_valid(void *vadr, size_t len) { + /* exmap_sem should be held before calling this function */ int i; start: @@ -389,6 +445,107 @@ start: 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() * returns physical address, and sets len to valid length @@ -744,12 +901,13 @@ found_free: goto fail; } - exmap_ent->buf = buf; - exmap_ent->vadr = _vadr; - exmap_ent->order = order; - exmap_ent->valid = 1; - exmap_ent->cntnu = cntnu; - exmap_ent->type = type; + exmap_ent->buf = buf; + exmap_ent->vadr = _vadr; + exmap_ent->order = order; + exmap_ent->valid = 1; + exmap_ent->cntnu = cntnu; + exmap_ent->type = type; + exmap_ent->usecount = 0; if ((_size -= unit) == 0) { /* normal completion */ up_write(&exmap_sem); @@ -812,6 +970,14 @@ static int dsp_exunmap(unsigned long dspadr) return -EINVAL; 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 */ dsp_mmu_clear_tlb(dspadr); @@ -871,11 +1037,6 @@ static void exmap_flush(void) /* flush TLB */ flush_tlb_kernel_range(dspmem_base + dspmem_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); } @@ -998,11 +1159,12 @@ static void dsp_mmu_init(void) phys = __pa(dspvect_page); virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */ exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); - exmap_tbl[0].buf = dspvect_page; - exmap_tbl[0].vadr = virt; - exmap_tbl[0].order = 0; - exmap_tbl[0].valid = 1; - exmap_tbl[0].cntnu = 0; + exmap_tbl[0].buf = dspvect_page; + exmap_tbl[0].vadr = virt; + exmap_tbl[0].usecount = 0; + exmap_tbl[0].order = 0; + exmap_tbl[0].valid = 1; + exmap_tbl[0].cntnu = 0; /* DSP TLB initialization */ set_tlb_lock(0, 0); @@ -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, * we send PM mailbox commands so that DSP DMA domain won't go in idle * 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; - -int dsp_mem_enable(void *adr) +static int intmem_enable(void) { - struct mbcmd mb; - int ret; + int ret = 0; - if (is_dsp_internal_mem(adr)) { - if (dsp_is_ready() && (!dsp_mem_en_count) && - (dsp_icrmask & 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; -} + if (dsp_is_ready()) + ret = dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); -int dsp_mem_disable(void *adr) -{ - struct mbcmd mb; - int ret; + return ret; +} - if (is_dsp_internal_mem(adr)) { - if (dsp_is_ready() && dsp_mem_en_count) { - mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, - DSPREG_ICR_DMA_IDLE_DOMAIN); - if ((ret = dsp_mbsend(&mb)) < 0) - return ret; - dsp_mem_en_count--; - } - } else - up_read(&exmap_sem); - return 0; +static void intmem_disable(void) { + if (dsp_is_ready()) + dsp_mbsend(MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); } -int __dsp_mem_enable(void *adr) +/* + * dsp_mem_enable() / disable() + */ +int intmem_usecount; + +int dsp_mem_enable(void *adr) { - struct mbcmd mb; - int ret; + int ret = 0; if (is_dsp_internal_mem(adr)) { - if (dsp_is_ready() && (!dsp_mem_en_count) && - (dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) { - 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++; - } + if (intmem_usecount++ == 0) + ret = omap_dsp_request_mem(); } else 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 (dsp_is_ready() && dsp_mem_en_count) { - mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, - DSPREG_ICR_DMA_IDLE_DOMAIN); - if ((ret = __mbsend(&mb)) < 0) - return ret; - dsp_mem_en_count--; - } + if (--intmem_usecount == 0) + omap_dsp_release_mem(); } else 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, read = size - p; if (copy_to_user(buf, vadr, read)) { read = -EFAULT; - goto finish; + goto out; } *ppos += read; -finish: +out: clk_unuse(api_ck_handle); return read; } @@ -1157,39 +1297,37 @@ static ssize_t exmem_read(struct file *file, char *buf, size_t count, { unsigned long p = *ppos; void *vadr = dspbyte_to_virt(p); - ssize_t ret; - down_read(&exmap_sem); if (!exmap_valid(vadr, count)) { printk(KERN_ERR "omapdsp: DSP address %08lx / size %08x " "is not valid!\n", p, count); - ret = -EFAULT; - goto up_out; + return -EFAULT; } if (count > DSPSPACE_SIZE - p) count = DSPSPACE_SIZE - p; - if (copy_to_user(buf, vadr, count)) { - ret = -EFAULT; - goto up_out; - } + if (copy_to_user(buf, vadr, count)) + return -EFAULT; *ppos += count; - up_read(&exmap_sem); return count; - -up_out: - up_read(&exmap_sem); - return ret; } static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count, 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)) - return intmem_read(file, buf, count, ppos); + ret = intmem_read(file, buf, count, ppos); 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, @@ -1208,10 +1346,10 @@ static ssize_t intmem_write(struct file *file, const char *buf, size_t count, written = size - p; if (copy_from_user(vadr, buf, written)) { written = -EFAULT; - goto finish; + goto out; } *ppos += written; -finish: +out: clk_unuse(api_ck_handle); return written; } @@ -1221,39 +1359,37 @@ static ssize_t exmem_write(struct file *file, const char *buf, size_t count, { unsigned long p = *ppos; void *vadr = dspbyte_to_virt(p); - ssize_t ret; - down_read(&exmap_sem); if (!exmap_valid(vadr, count)) { printk(KERN_ERR "omapdsp: DSP address %08lx / size %08x " "is not valid!\n", p, count); - ret = -EFAULT; - goto up_out; + return -EFAULT; } if (count > DSPSPACE_SIZE - p) count = DSPSPACE_SIZE - p; - if (copy_from_user(vadr, buf, count)) { - ret = -EFAULT; - goto up_out; - } + if (copy_from_user(vadr, buf, count)) + return -EFAULT; *ppos += count; - up_read(&exmap_sem); 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, 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)) - return intmem_write(file, buf, count, ppos); + ret = intmem_write(file, buf, count, ppos); 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, @@ -1325,15 +1461,12 @@ static int dsp_mem_open(struct inode *inode, struct file *file) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; - if (dsp_mem_enable((void *)dspmem_base) < 0) - return -EBUSY; return 0; } static int dsp_mem_release(struct inode *inode, struct file *file) { - dsp_mem_disable((void *)dspmem_base); return 0; } @@ -1414,16 +1547,16 @@ static ssize_t exmap_show(struct device *dev, struct device_attribute *attr, down_read(&exmap_sem); 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 */ for (i = 0; i < DSPMMU_TLB_LINES; i++) { struct exmap_tbl *ent = &exmap_tbl[i]; /* 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, ent->valid ? 'v' : ' ', ent->cntnu ? 'c' : ' ', - ent->vadr, ent->buf, ent->order); + ent->vadr, ent->buf, ent->order, ent->usecount); } up_read(&exmap_sem); @@ -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 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 */ @@ -1516,9 +1662,11 @@ irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* FIXME */ dsp_err_mmu_set(dsp_fault_adr); } else { + disable_irq(INT_DSP_MMU); + __dsp_mmu_itack(); printk(KERN_INFO "Resetting DSP...\n"); - __dsp_reset(); - clk_unuse(api_ck_handle); + dsp_cpustat_request(CPUSTAT_RESET); + enable_irq(INT_DSP_MMU); /* * if we enable followings, semaphore lock should be avoided. * @@ -1547,7 +1695,13 @@ struct file_operations dsp_mem_fops = { 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) @@ -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_exmap); + device_create_file(&dsp_device.dev, &dev_attr_kmem_pool); return 0; } @@ -1581,19 +1736,18 @@ void dsp_mem_exit(void) if (dspvect_page != NULL) { 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); dspvect_page = NULL; - virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE); - pmdp = pmd_offset(pgd_offset_k(virt), virt); - ptep = pte_offset_kernel(pmdp, 0); - pmd_clear(pmdp); - pte_free_kernel(ptep); + up_read(&exmap_sem); } 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_kmem_pool); } diff --git a/arch/arm/plat-omap/dsp/error.c b/arch/arm/plat-omap/dsp/error.c index ac6d8d84d9b..dd7d7c4594b 100644 --- a/arch/arm/plat-omap/dsp/error.c +++ b/arch/arm/plat-omap/dsp/error.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -138,15 +138,22 @@ int dsp_err_wdt_isset(void) /* * 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; errcnt++; - wdtval = mb->data; + wdtval = data; 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_fatal(unsigned char tid); @@ -174,6 +181,10 @@ void mbx1_err(struct mbcmd *mb) tid = mb->data & 0x00ff; mbx1_err_fatal(tid); break; + + case OMAP_DSP_EID_WDT: + mbx1_err_wdt(mb->data); + break; } } diff --git a/arch/arm/plat-omap/dsp/fifo.h b/arch/arm/plat-omap/dsp/fifo.h index 0f890697810..46fc33ccc80 100644 --- a/arch/arm/plat-omap/dsp/fifo.h +++ b/arch/arm/plat-omap/dsp/fifo.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 { diff --git a/arch/arm/plat-omap/dsp/hardware_dsp.h b/arch/arm/plat-omap/dsp/hardware_dsp.h index 4c70dd1ccf8..b27d0858790 100644 --- a/arch/arm/plat-omap/dsp/hardware_dsp.h +++ b/arch/arm/plat-omap/dsp/hardware_dsp.h @@ -21,12 +21,25 @@ * along with this program; if not, write to the Free Software * 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 #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 !! */ @@ -186,6 +199,7 @@ /* * DSP ICR */ +#define DSPREG_ICR_RESERVED_BITS 0xffc0 #define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020 #define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010 #define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008 diff --git a/arch/arm/plat-omap/dsp/ipbuf.c b/arch/arm/plat-omap/dsp/ipbuf.c index 305ce689172..ebb482b05f0 100644 --- a/arch/arm/plat-omap/dsp/ipbuf.c +++ b/arch/arm/plat-omap/dsp/ipbuf.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -38,51 +38,51 @@ struct ipbuf **ipbuf; struct ipbcfg ipbcfg; struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; static struct ipblink ipb_free = IPBLINK_INIT; +static int ipbuf_sys_hold_mem_active; void ipbuf_stop(void) { + int i; + + spin_lock(&ipb_free.lock); + INIT_IPBLINK(&ipb_free); + spin_unlock(&ipb_free.lock); + ipbcfg.ln = 0; if (ipbuf) { kfree(ipbuf); ipbuf = NULL; } + for (i = 0; i < ipbuf_sys_hold_mem_active; i++) { + dsp_mem_disable((void *)daram_base); + } + ipbuf_sys_hold_mem_active = 0; } -/* - * ipbuf_config() is called by mailbox workqueue - */ -int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr) +int ipbuf_config(unsigned short ln, unsigned short lsz, void *base) { - void *base; unsigned long lsz_byte = ((unsigned long)lsz) << 1; size_t size; int ret = 0; int i; - spin_lock(&ipb_free.lock); - INIT_IPBLINK(&ipb_free); - spin_unlock(&ipb_free.lock); - /* * global IPBUF */ - if (adr & 0x1) { + if (((unsigned long)base) & 0x3) { printk(KERN_ERR - "mbx: global ipbuf address (0x%08lx) is odd number!\n", - adr); + "omapdsp: global ipbuf address(0x%p) is not " + "32-bit aligned!\n", base); return -EINVAL; } size = lsz_byte * ln; - if (adr + size > DSPSPACE_SIZE) { - printk(KERN_ERR - "mbx: ipbuf address (0x%08lx) and size (0x%08x) is " - "illegal!\n", adr, size); + if (dsp_address_validate(base, size, "global ipbuf") < 0) return -EINVAL; - } - base = dspword_to_virt(adr); + ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL); 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; } for (i = 0; i < ln; i++) { @@ -101,20 +101,75 @@ int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr) "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n" " @0x%p, size=0x%08lx\n", i, top, lsz_byte); ret = -EINVAL; + goto free_out; } } ipbcfg.ln = ln; ipbcfg.lsz = lsz; - ipbcfg.adr = adr; + ipbcfg.base = base; ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */ ipbcfg.cnt_full = 0; printk(KERN_INFO "omapdsp: IPBUF configuration\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; + +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) { unsigned short bid; - if (ipblink_empty(&ipb_free)) { - /* FIXME: wait on queue when not available. */ + if (dsp_mem_enable_ipbuf() < 0) return OMAP_DSP_BID_NULL; - } - /* - * FIXME: dsp_enable_dspmem! - */ 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; ipbuf[bid]->la = tid; /* lock */ ipblink_del_top(&ipb_free, ipbuf); +out: spin_unlock(&ipb_free.lock); + dsp_mem_disable_ipbuf(); return bid; } @@ -161,12 +219,10 @@ void release_ipbuf(unsigned short bid) static int try_yld(unsigned short bid) { - struct mbcmd mb; int status; ipbuf[bid]->sa = OMAP_DSP_TID_ANON; - mbcmd_set(mb, MBCMD(BKYLD), 0, bid); - status = dsp_mbsend(&mb); + status = dsp_mbsend(MBCMD(BKYLD), 0, bid); if (status < 0) { /* DSP is busy and ARM keeps this line. */ release_ipbuf(bid); diff --git a/arch/arm/plat-omap/dsp/ipbuf.h b/arch/arm/plat-omap/dsp/ipbuf.h index c70f7964a29..77826f443d2 100644 --- a/arch/arm/plat-omap/dsp/ipbuf.h +++ b/arch/arm/plat-omap/dsp/ipbuf.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 { @@ -43,13 +43,13 @@ struct ipbuf_p { struct ipbuf_sys { unsigned short s; /* sync word */ - unsigned short d[15]; /* data */ + unsigned short d[31]; /* data */ }; struct ipbcfg { unsigned short ln; unsigned short lsz; - unsigned long adr; + void *base; unsigned short bsycnt; unsigned long cnt_full; /* count of IPBFULL error */ }; @@ -72,8 +72,8 @@ extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; enable_irq(INT_D2A_MB1); \ } while(0) -#define dsp_mem_enable_ipbuf() dsp_mem_enable(dspword_to_virt(ipbcfg.adr)) -#define dsp_mem_disable_ipbuf() dsp_mem_disable(dspword_to_virt(ipbcfg.adr)) +#define dsp_mem_enable_ipbuf() dsp_mem_enable(ipbcfg.base) +#define dsp_mem_disable_ipbuf() dsp_mem_disable(ipbcfg.base) struct ipblink { spinlock_t lock; @@ -89,6 +89,7 @@ struct ipblink { #define INIT_IPBLINK(link) \ do { \ + spin_lock_init(&(link)->lock); \ (link)->top = OMAP_DSP_BID_NULL; \ (link)->tail = OMAP_DSP_BID_NULL; \ } while(0) diff --git a/arch/arm/plat-omap/dsp/mblog.c b/arch/arm/plat-omap/dsp/mblog.c index 69d42c82f20..a4e7cd05417 100644 --- a/arch/arm/plat-omap/dsp/mblog.c +++ b/arch/arm/plat-omap/dsp/mblog.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -98,6 +98,7 @@ char *subcmd_name(struct mbcmd *mb) (cmd_l == EID(BADTCTL)) ? "BADTCTL": (cmd_l == EID(BADPARAM)) ? "BADPARAM": (cmd_l == EID(FATAL)) ? "FATAL": + (cmd_l == EID(WDT)) ? "WDT": (cmd_l == EID(NOMEM)) ? "NOMEM": (cmd_l == EID(NORES)) ? "NORES": (cmd_l == EID(IPBFULL)) ? "IPBFULL": @@ -124,7 +125,7 @@ struct mblogent { unsigned long jiffies; unsigned short cmd; unsigned short data; - enum mblog_dir dir; + enum arm_dsp_dir dir; }; static struct { @@ -134,7 +135,7 @@ static struct { struct mblogent ent[MBLOG_DEPTH]; } 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 mblogent *ent; @@ -148,11 +149,11 @@ void mblog_add(struct mbcmd *mb, enum mblog_dir dir) if (mblog.cnt < 0xffffffff) mblog.cnt++; switch (dir) { - case MBLOG_DIR_AD: + case DIR_A2D: if (mblog.cnt_ad < 0xffffffff) mblog.cnt_ad++; break; - case MBLOG_DIR_DA: + case DIR_D2A: if (mblog.cnt_da < 0xffffffff) mblog.cnt_da++; break; @@ -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]; len += sprintf(buf + len, - (ent->dir == MBLOG_DIR_AD) ? + (ent->dir == DIR_A2D) ? "%08lx %d %04x %04x ": "%08lx %d %04x %04x ", ent->jiffies, mb.sw.seq, ent->cmd, ent->data); @@ -230,13 +231,13 @@ done: static struct device_attribute dev_attr_mblog = __ATTR_RO(mblog); #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]; char *dir_str; char *subname; - dir_str = (dir == MBLOG_DIR_AD) ? "sending" : "receiving"; + dir_str = (dir == DIR_A2D) ? "sending" : "receiving"; switch (ci->cmd_l_type) { case CMD_L_TYPE_SUBCMD: if ((subname = subcmd_name(mb)) == NULL) diff --git a/arch/arm/plat-omap/dsp/proclist.h b/arch/arm/plat-omap/dsp/proclist.h index 723e5b09d27..7214317686d 100644 --- a/arch/arm/plat-omap/dsp/proclist.h +++ b/arch/arm/plat-omap/dsp/proclist.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 { diff --git a/arch/arm/plat-omap/dsp/task.c b/arch/arm/plat-omap/dsp/task.c index fe028a09e8f..e5c60dde437 100644 --- a/arch/arm/plat-omap/dsp/task.c +++ b/arch/arm/plat-omap/dsp/task.c @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -49,16 +48,32 @@ #include "fifo.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. * ATTACHED: task is attached. * GARBAGE: task is detached. waiting for all processes to close this device. * ADDREQ: requesting for tadd * DELREQ: requesting for tdel. no process is opening this device. - * KILLREQ: requesting for tkill. * 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 bus_type *bus; @@ -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_attach_task(struct taskdev *dev, struct dsptask *task); 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, char *buf); @@ -345,23 +361,27 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) { unsigned short ttyp; struct mbcmd mb; + int ret; - dsptask[tid] = task; task->tid = tid; + dsptask[tid] = task; /* TCFG request */ task->state = TASK_STATE_CFGREQ; - if (down_interruptible(&cfg_sem)) - return -ERESTARTSYS; + if (down_interruptible(&cfg_sem)) { + ret = -ERESTARTSYS; + goto fail_out; + } cfg_cmd = MBCMD(TCFG); 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; up(&cfg_sem); if (task->state != TASK_STATE_READY) { printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid); - return -EINVAL; + ret = -EINVAL; + goto fail_out; } if (strlen(task->name) <= 1) @@ -370,35 +390,49 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ttyp = task->ttyp; + /* + * task info sanity check + */ + /* task type check */ 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); + ret = -EINVAL; + goto fail_out; } /* private buffer address check */ - if (sndtyp_pvt(ttyp)) { - void *p = task->rcvdt.bk.ipbuf_pvt_r; - - if ((unsigned long)p & 0x1) { - printk(KERN_ERR - "mbx: private ipbuf (DSP->ARM) address (0x%p) " - "is odd number!\n", p); - return -EINVAL; - } + if (sndtyp_pvt(ttyp) && + (ipbuf_p_validate(task->rcvdt.bk.ipbuf_pvt_r, DIR_D2A) < 0)) { + ret = -EINVAL; + goto fail_out; } - - if (rcvtyp_pvt(ttyp)) { - void *p = task->ipbuf_pvt_w; - - if ((unsigned long)p & 0x1) { - printk(KERN_ERR - "mbx: private ipbuf (ARM->DSP) address (0x%p) " - "is odd number!\n", p); - return -EINVAL; - } + if (rcvtyp_pvt(ttyp) && + (ipbuf_p_validate(task->ipbuf_pvt_w, DIR_A2D) < 0)) { + ret = -EINVAL; + goto fail_out; + } + + /* mmap buffer configuration check */ + if ((task->map_length > 0) && + ((!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 */ if (sndtyp_wd(ttyp)) { /* word */ @@ -410,11 +444,11 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) printk(KERN_ERR "omapdsp: unable to allocate receive buffer. " "(%d bytes for %s)\n", fifosz, task->name); - return -ENOMEM; + ret = -ENOMEM; + goto fail_out; } } else { /* block */ - spin_lock_init(&task->rcvdt.bk.link.lock); INIT_IPBLINK(&task->rcvdt.bk.link); task->rcvdt.bk.rp = 0; } @@ -426,14 +460,15 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid) ipbcfg.lsz*2; /* passive block */ return 0; + +fail_out: + dsptask[tid] = NULL; + return ret; } static void dsp_task_init(struct dsptask *task) { - struct mbcmd mb; - - mbcmd_set(mb, MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT); - dsp_mbsend(&mb); + dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT); } int dsp_task_config_all(unsigned char n) @@ -558,11 +593,22 @@ int dsp_taskmod_busy(void) for (minor = 0; minor < TASKDEV_MAX; minor++) { dev = taskdev[minor]; - if (dev && - ((dev->usecount > 0) || - (dev->state == OMAP_DSP_DEVSTATE_ADDREQ) || - (dev->state == OMAP_DSP_DEVSTATE_DELREQ))) + if (dev == NULL) + continue; + if (dev->usecount > 0) { + printk("dsp_taskmod_busy(): %s: usecount=%d\n", + dev->name, dev->usecount); 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; } @@ -704,13 +750,19 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, ret = -ERESTARTSYS; goto up_out; } - base = dspword_to_virt(MKLONG(ipbp->ah, ipbp->al)); - src = base + rcvdt->rp; + base = MKVIRT(ipbp->ah, ipbp->al); + 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) { ret = -ERESTARTSYS; goto pv_out1; } - bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp; + src = base + rcvdt->rp; if (bkcnt > count) { if (copy_to_user_dsp(buf, src, count)) { ret = -EFAULT; @@ -813,7 +865,7 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count, devstate_unlock(dev); 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)) { ret = -ERESTARTSYS; @@ -868,7 +920,7 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, devstate_unlock(dev); 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)) { ret = -ERESTARTSYS; @@ -896,12 +948,17 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, ret = -ERESTARTSYS; 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) { ret = -ERESTARTSYS; goto pv_out1; } - rcvcnt = ((unsigned long)ipbp->c) * 2; if (count > rcvcnt) count = rcvcnt; 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, { unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); struct taskdev *dev = taskdev[minor]; - struct mbcmd mb; unsigned short wd; int have_devstate_lock = 0; int ret = 0; @@ -1013,9 +1069,8 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf, goto up_out; } - mbcmd_set(mb, MBCMD(WDSND), dev->task->tid, wd); 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); goto up_out; } @@ -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); struct taskdev *dev = taskdev[minor]; - struct mbcmd mb; int have_devstate_lock = 0; int ret = 0; @@ -1102,7 +1156,12 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, ret = -ERESTARTSYS; 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) { ret = -ERESTARTSYS; goto pv_out1; @@ -1113,9 +1172,8 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf, } ipbp->c = count/2; ipbp->s = dev->task->tid; - mbcmd_set(mb, MBCMD(BKSNDP), dev->task->tid, 0); 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)) dev->task->wsz = 0; ret = count; @@ -1145,9 +1203,8 @@ pv_out1: } ipbp->c = count/2; ipbp->sa = dev->task->tid; - mbcmd_set(mb, MBCMD(BKSND), dev->task->tid, bid); 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)) dev->task->wsz = 0; ret = count; @@ -1226,6 +1283,9 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, * reserved for backward compatibility * 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; interactive = 0; } else if (cmd < 0x8000) { @@ -1315,7 +1375,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, dev->task->tctl_stat = -ERESTARTSYS; 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)) { ret = -ERESTARTSYS; goto up_out; @@ -1330,7 +1390,7 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file, goto unlock_out; } } else { - dsp_mbsend_exarg(&mb, mbargp); + dsp_mbcmd_send_exarg(&mb, mbargp); ret = 0; } @@ -1341,18 +1401,42 @@ up_out: 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 * 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) { return NOPAGE_SIGBUS; } 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) @@ -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) return -ERESTARTSYS; 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 @@ -1430,6 +1499,9 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) } while (req_len); 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: devstate_unlock(dev); return ret; @@ -1441,12 +1513,8 @@ static int dsp_task_open(struct inode *inode, struct file *file) struct taskdev *dev; int ret = 0; - if (minor >= TASKDEV_MAX) - return -ENODEV; - dev = taskdev[minor]; - if (dev == NULL) + if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) return -ENODEV; - if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK | OMAP_DSP_DEVSTATE_ATTACHED) < 0) return -ERESTARTSYS; @@ -1457,15 +1525,20 @@ static int dsp_task_open(struct inode *inode, struct file *file) } #endif - if (dev->state == OMAP_DSP_DEVSTATE_NOTASK) { + if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) { dev->state = OMAP_DSP_DEVSTATE_ADDREQ; /* wake up twch daemon for tadd */ dsp_twch_touch(); devstate_unlock(dev); 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; - if (dev->state == OMAP_DSP_DEVSTATE_ADDFAIL) { + } + if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) { printk(KERN_ERR "omapdsp: task attach failed for %s!\n", dev->name); ret = -EBUSY; @@ -1496,10 +1569,10 @@ static int dsp_task_release(struct inode *inode, struct file *file) /* state_lock covers usecount, proc_list as well. */ spin_lock(&dev->state_lock); - /* state can be ATTACHED, KILLREQ or GARBAGE here. */ - switch (dev->state) { + /* state can be ATTACHED, KILLING or GARBAGE here. */ + switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) { - case OMAP_DSP_DEVSTATE_KILLREQ: + case OMAP_DSP_DEVSTATE_KILLING: dev->usecount--; break; @@ -1582,11 +1655,10 @@ int dsp_rmdev(char *name) static int dsp_rmdev_minor(unsigned char minor) { struct taskdev *dev = taskdev[minor]; - struct dsptask *task = dev->task; spin_lock(&dev->state_lock); - switch (dev->state) { + switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) { case OMAP_DSP_DEVSTATE_NOTASK: /* fine */ @@ -1598,6 +1670,7 @@ static int dsp_rmdev_minor(unsigned char minor) siginfo_t info; struct proc_list *pl; + dev->state = OMAP_DSP_DEVSTATE_KILLING; info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = SI_KERNEL; @@ -1605,12 +1678,10 @@ static int dsp_rmdev_minor(unsigned char minor) list_for_each_entry(pl, &dev->proc_list, list_head) { send_sig_info(SIGBUS, &info, pl->tsk); } - taskdev_detach_task(dev); - dsp_task_unconfig(task); - kfree(task); - dev->state = OMAP_DSP_DEVSTATE_GARBAGE; + spin_unlock(&dev->state_lock); + dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL); + goto invalidate; } - break; case OMAP_DSP_DEVSTATE_ADDREQ: /* open() is waiting. drain it. */ @@ -1624,7 +1695,9 @@ static int dsp_rmdev_minor(unsigned char minor) wake_up_interruptible_all(&dev->state_wait_q); 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_ADDFAIL: /* transient state. wait for a moment. */ @@ -1634,12 +1707,13 @@ static int dsp_rmdev_minor(unsigned char minor) spin_unlock(&dev->state_lock); +invalidate: /* wait for some time and hope the state is settled */ 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 - "omapdsp: illegal device state on rmdev %s.\n", - dev->name); + "omapdsp: illegal device state (%s) on rmdev %s.\n", + devstate_name(dev->state), dev->name); } dev->state = OMAP_DSP_DEVSTATE_INVALID; devstate_unlock(dev); @@ -1656,7 +1730,6 @@ struct file_operations dsp_task_fops = { .ioctl = dsp_task_ioctl, .open = dsp_task_open, .release = dsp_task_release, - .mmap = dsp_task_mmap, }; static void dsptask_dev_release(struct device *dev) @@ -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); class_device_create(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, 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); spin_lock_init(&dev->state_lock); @@ -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_devstate); device_remove_file(&dev->dev, &dev_attr_proc_list); - class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor)); - devfs_remove("dsptask%d", minor); device_unregister(&dev->dev); proc_list_flush(&dev->proc_list); taskdev[minor] = NULL; @@ -1736,6 +1805,8 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) dev->fops.write = rcvtyp_wd(ttyp) ? dsp_task_write_wd: /* 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_ttyp); @@ -1781,7 +1852,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) struct dsptask *task; struct mbcmd mb; struct mb_exarg arg; - unsigned char tid; + unsigned char tid, tid_response; unsigned short argv[2]; int ret = minor; @@ -1790,16 +1861,17 @@ int dsp_tadd(unsigned char minor, unsigned long adr) "omapdsp: no task device with minor %d\n", minor); return -EINVAL; } - /* - * we don't need to lock state_lock because - * only tadd is allowed when devstate is ADDREQ. - */ - if (dev->state != OMAP_DSP_DEVSTATE_ADDREQ) { + + spin_lock(&dev->state_lock); + if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) { printk(KERN_ERR - "omapdsp: taskdev %s is not requesting for tadd.\n", - dev->name); + "omapdsp: taskdev %s is not requesting for tadd. " + "(state is %s)\n", dev->name, devstate_name(dev->state)); + spin_unlock(&dev->state_lock); return -EINVAL; } + dev->state = OMAP_DSP_DEVSTATE_ADDING; + spin_unlock(&dev->state_lock); if (adr == OMAP_DSP_TADD_ABORTADR) { /* aborting tadd intentionally */ @@ -1828,7 +1900,8 @@ int dsp_tadd(unsigned char minor, unsigned long adr) arg.argc = 2; 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; cfg_tid = OMAP_DSP_TID_ANON; @@ -1847,7 +1920,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) } if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) { ret = -ENOMEM; - goto fail_out; + goto del_out; } memset(task, 0, sizeof(struct dsptask)); @@ -1860,9 +1933,7 @@ int dsp_tadd(unsigned char minor, unsigned long adr) "omapdsp: task name (%s) doesn't match with " "device name (%s).\n", task->name, dev->name); ret = -EINVAL; - dev->state = OMAP_DSP_DEVSTATE_DELREQ; - dsp_twch_touch(); - return -EINVAL; + goto free_out; } dsp_task_init(task); @@ -1873,6 +1944,30 @@ int dsp_tadd(unsigned char minor, unsigned long adr) free_out: 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: dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; wake_up_interruptible_all(&dev->state_wait_q); @@ -1882,64 +1977,31 @@ fail_out: int dsp_tdel(unsigned char minor) { 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)) { printk(KERN_ERR "omapdsp: no task device with minor %d\n", minor); return -EINVAL; } - /* - * we don't need to lock state_lock because - * only tdel is allowed when devstate is DELREQ. - */ - if (dev->state != OMAP_DSP_DEVSTATE_DELREQ) { + spin_lock(&dev->state_lock); + if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) { printk(KERN_ERR - "omapdsp: taskdev %s is not requesting for tdel.\n", - dev->name); + "omapdsp: taskdev %s is not requesting for tdel. " + "(state is %s)\n", dev->name, devstate_name(dev->state)); + spin_unlock(&dev->state_lock); return -EINVAL; } + dev->state = OMAP_DSP_DEVSTATE_DELING; + spin_unlock(&dev->state_lock); - task = dev->task; - 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; + return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE); } int dsp_tkill(unsigned char minor) { struct taskdev *dev; - struct dsptask *task; - struct mbcmd mb; - unsigned char tid, tid_response; siginfo_t info; struct proc_list *pl; - int ret = minor; if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { printk(KERN_ERR @@ -1947,14 +2009,14 @@ int dsp_tkill(unsigned char minor) return -EINVAL; } spin_lock(&dev->state_lock); - if (dev->state != OMAP_DSP_DEVSTATE_ATTACHED) { + if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) { printk(KERN_ERR "omapdsp: task has not been attached for taskdev %s\n", dev->name); spin_unlock(&dev->state_lock); return -EINVAL; } - dev->state = OMAP_DSP_DEVSTATE_KILLREQ; + dev->state = OMAP_DSP_DEVSTATE_KILLING; info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = SI_KERNEL; @@ -1964,17 +2026,33 @@ int dsp_tkill(unsigned char minor) } 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; tid = task->tid; if (down_interruptible(&cfg_sem)) { - tid_response = OMAP_DSP_TID_ANON; - ret = -ERESTARTSYS; - goto detach_out; + if (type == OMAP_DSP_MBCMD_TDEL_SAFE) { + dev->state = OMAP_DSP_DEVSTATE_DELREQ; + return -ERESTARTSYS; + } else { + tid_response = OMAP_DSP_TID_ANON; + ret = -ERESTARTSYS; + goto detach_out; + } } cfg_tid = OMAP_DSP_TID_ANON; cfg_cmd = MBCMD(TDEL); - mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL); - dsp_mbsend_and_wait(&mb, &cfg_wait_q); + mbcmd_set(mb, MBCMD(TDEL), tid, type); + dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q); tid_response = cfg_tid; cfg_tid = OMAP_DSP_TID_ANON; cfg_cmd = 0; @@ -1985,9 +2063,11 @@ detach_out: dsp_task_unconfig(task); kfree(task); - if (tid_response != tid) - printk(KERN_ERR "omapdsp: tkill failed!\n"); - + if (tid_response != tid) { + printk(KERN_ERR "omapdsp: %s failed!\n", + (type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill"); + ret = -EINVAL; + } spin_lock(&dev->state_lock); dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE : OMAP_DSP_DEVSTATE_NOTASK; @@ -2000,10 +2080,14 @@ detach_out: /* * state inquiry */ -long taskdev_state(unsigned char minor) +long taskdev_state_stale(unsigned char minor) { - return taskdev[minor] ? taskdev[minor]->state : - OMAP_DSP_DEVSTATE_NOTASK; + if (taskdev[minor]) { + 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) { unsigned char tid = mb->cmd_l; 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; volatile unsigned short *buf; int i; @@ -2289,25 +2370,29 @@ void mbx1_tcfg(struct mbcmd *mb) if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) { printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n"); - return; + goto out; } /* * read configuration data on system IPBUF */ buf = ipbuf_sys_da->d; - task->ttyp = buf[0]; - tmp_ipbp_r = MKLONG(buf[1], buf[2]); - tmp_ipbp_w = MKLONG(buf[3], buf[4]); - tmp_mapstart = MKLONG(buf[5], buf[6]); - tmp_maplen = MKLONG(buf[7], buf[8]); - tmp_tnm = MKLONG(buf[9], buf[10]); - - 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); - task->map_length = tmp_maplen << 1; /* word -> byte */ - tnm = dspword_to_virt(tmp_tnm); + task->ttyp = buf[0]; + task->rcvdt.bk.ipbuf_pvt_r = MKVIRT(buf[1], buf[2]); + task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]); + task->map_base = MKVIRT(buf[5], buf[6]); + task->map_length = MKLONG(buf[7], buf[8]) << 1; /* word -> byte */ + tnm = MKVIRT(buf[9], buf[10]); + release_ipbuf_pvt(ipbuf_sys_da); + + /* + * copy task name string + */ + 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++) { /* avoiding byte access */ unsigned short tmp = tnm[i]; @@ -2317,8 +2402,8 @@ void mbx1_tcfg(struct mbcmd *mb) } task->name[OMAP_DSP_TNM_LEN-1] = '\0'; - release_ipbuf_pvt(ipbuf_sys_da); task->state = TASK_STATE_READY; +out: wake_up_interruptible(&cfg_wait_q); } @@ -2368,7 +2453,117 @@ void mbx1_err_fatal(unsigned char tid) 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) +{ + 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; char s[80], *s_end = &s[79], *p; @@ -2388,7 +2583,13 @@ void mbx1_dbg(struct mbcmd *mb) } buf = ipbuf_sys_da->d; 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; for (i = 0; i < cnt; i++) { unsigned short tmp; @@ -2421,8 +2622,9 @@ void mbx1_dbg(struct mbcmd *mb) } release_ipbuf_pvt(ipbuf_sys_da); + dsp_mem_disable(src); } - +#endif /* OLD_BINARY_SUPPORT */ /* * sysfs files @@ -2434,17 +2636,6 @@ static ssize_t devname_show(struct device *d, struct device_attribute *attr, 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, char *buf) { @@ -2622,14 +2813,12 @@ int __init dsp_taskmod_init(void) return -EINVAL; } dsp_task_class = class_create(THIS_MODULE, "dsptask"); - devfs_mk_dir("dsptask"); return 0; } void dsp_taskmod_exit(void) { - devfs_remove("dsptask"); class_destroy(dsp_task_class); driver_unregister(&dsptask_driver); bus_unregister(&dsptask_bus); diff --git a/arch/arm/plat-omap/dsp/taskwatch.c b/arch/arm/plat-omap/dsp/taskwatch.c index fb96c784946..b09c59d51d8 100644 --- a/arch/arm/plat-omap/dsp/taskwatch.c +++ b/arch/arm/plat-omap/dsp/taskwatch.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -83,7 +83,12 @@ static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count, count = devcount * sizeof(long); change_cnt = 0; 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)) diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.S b/arch/arm/plat-omap/dsp/uaccess_dsp.S index 07639038d29..3257b705064 100644 --- a/arch/arm/plat-omap/dsp/uaccess_dsp.S +++ b/arch/arm/plat-omap/dsp/uaccess_dsp.S @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 diff --git a/arch/arm/plat-omap/dsp/uaccess_dsp.h b/arch/arm/plat-omap/dsp/uaccess_dsp.h index d1f445340bd..2217a1042e5 100644 --- a/arch/arm/plat-omap/dsp/uaccess_dsp.h +++ b/arch/arm/plat-omap/dsp/uaccess_dsp.h @@ -22,7 +22,7 @@ * along with this program; if not, write to the Free Software * 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 diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f4fc4a87c29..51b8a5bcc7c 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -191,7 +191,7 @@ static int omap_mcbsp_check(unsigned int id) static void omap_mcbsp_dsp_request(void) { if (cpu_is_omap1510() || cpu_is_omap16xx()) { - omap_dsp_request_idle(); + omap_dsp_request_mem(); clk_use(mcbsp_dsp_ck); clk_use(mcbsp_api_ck); @@ -210,6 +210,7 @@ static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_free(void) { if (cpu_is_omap1510() || cpu_is_omap16xx()) { + omap_dsp_release_mem(); clk_unuse(mcbsp_dspxor_ck); clk_unuse(mcbsp_dsp_ck); clk_unuse(mcbsp_api_ck); diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h index a4a17ba1514..57bf4f39ca5 100644 --- a/include/asm-arm/arch-omap/dsp.h +++ b/include/asm-arm/arch-omap/dsp.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -34,14 +34,16 @@ #define OMAP_DSP_IOCTL_RESET 1 #define OMAP_DSP_IOCTL_RUN 2 #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_OFF 6 #define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7 #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_DSPUNCFG 11 #define OMAP_DSP_IOCTL_TASKCNT 12 +#define OMAP_DSP_IOCTL_POLL 13 #define OMAP_DSP_IOCTL_REGMEMR 40 #define OMAP_DSP_IOCTL_REGMEMW 41 #define OMAP_DSP_IOCTL_REGIOR 42 @@ -97,8 +99,12 @@ struct omap_dsp_mapinfo { #define OMAP_DSP_DEVSTATE_INVALID 0x00000008 #define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100 #define OMAP_DSP_DEVSTATE_DELREQ 0x00000200 -#define OMAP_DSP_DEVSTATE_KILLREQ 0x00000400 #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 { unsigned char minor; @@ -133,7 +139,7 @@ struct omap_dsp_varinfo { 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_WDREQ 0x11 @@ -144,7 +150,8 @@ struct omap_dsp_varinfo { #define OMAP_DSP_MBCMD_BKREQP 0x25 #define OMAP_DSP_MBCMD_TCTL 0x30 #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_PM 0x52 #define OMAP_DSP_MBCMD_SUSPEND 0x53 @@ -217,6 +224,7 @@ struct omap_dsp_varinfo { #define OMAP_DSP_EID_NOMEM 0xc0 #define OMAP_DSP_EID_NORES 0xc1 #define OMAP_DSP_EID_IPBFULL 0xc2 +#define OMAP_DSP_EID_WDT 0xd0 #define OMAP_DSP_EID_TASKNOTRDY 0xe0 #define OMAP_DSP_EID_TASKBSY 0xe1 #define OMAP_DSP_EID_TASKERR 0xef diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h index 9931e325ebc..4fcce694405 100644 --- a/include/asm-arm/arch-omap/dsp_common.h +++ b/include/asm-arm/arch-omap/dsp_common.h @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * 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 @@ -29,6 +29,9 @@ void omap_dsp_pm_suspend(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 */ -- 2.41.1