diff options
author | Brian Swetland <swetland@google.com> | 2009-07-01 21:30:47 -0400 |
---|---|---|
committer | Daniel Walker <dwalker@codeaurora.org> | 2010-05-12 12:15:11 -0400 |
commit | 37521a3181123dc4a9584cc4b8572c08ea0a8274 (patch) | |
tree | 1e5571657f48baa7e2a8b5763fc33da583be878c /arch/arm/mach-msm/smd.c | |
parent | 03e00cd350c6636b5f2a9854609fea93a5c7b677 (diff) |
[ARM] msm: smd: add support for DSP SMD channels
- QSD8250 has a DSP that speaks SMD, in addition to the modem
- handle a separate list of modem vs dsp channels
- install dsp smd irq handler as necessary
Signed-off-by: Brian Swetland <swetland@google.com>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm/smd.c')
-rw-r--r-- | arch/arm/mach-msm/smd.c | 114 |
1 files changed, 68 insertions, 46 deletions
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 1aaee4d70863..a88a8fc05f86 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c | |||
@@ -35,6 +35,10 @@ | |||
35 | #include "smd_private.h" | 35 | #include "smd_private.h" |
36 | #include "proc_comm.h" | 36 | #include "proc_comm.h" |
37 | 37 | ||
38 | #if defined(CONFIG_ARCH_QSD8X50) | ||
39 | #define CONFIG_QDSP6 1 | ||
40 | #endif | ||
41 | |||
38 | void (*msm_hw_reset_hook)(void); | 42 | void (*msm_hw_reset_hook)(void); |
39 | 43 | ||
40 | #define MODULE_NAME "msm_smd" | 44 | #define MODULE_NAME "msm_smd" |
@@ -70,6 +74,9 @@ static unsigned last_heap_free = 0xffffffff; | |||
70 | static inline void notify_other_smsm(void) | 74 | static inline void notify_other_smsm(void) |
71 | { | 75 | { |
72 | writel(1, MSM_A2M_INT(5)); | 76 | writel(1, MSM_A2M_INT(5)); |
77 | #ifdef CONFIG_QDSP6 | ||
78 | writel(1, MSM_A2M_INT(8)); | ||
79 | #endif | ||
73 | } | 80 | } |
74 | 81 | ||
75 | static inline void notify_modem_smd(void) | 82 | static inline void notify_modem_smd(void) |
@@ -140,7 +147,8 @@ static DEFINE_MUTEX(smd_creation_mutex); | |||
140 | static int smd_initialized; | 147 | static int smd_initialized; |
141 | 148 | ||
142 | LIST_HEAD(smd_ch_closed_list); | 149 | LIST_HEAD(smd_ch_closed_list); |
143 | LIST_HEAD(smd_ch_list); /* todo: per-target lists */ | 150 | LIST_HEAD(smd_ch_list_modem); |
151 | LIST_HEAD(smd_ch_list_dsp); | ||
144 | 152 | ||
145 | static unsigned char smd_ch_allocated[64]; | 153 | static unsigned char smd_ch_allocated[64]; |
146 | static struct work_struct probe_work; | 154 | static struct work_struct probe_work; |
@@ -150,6 +158,7 @@ static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); | |||
150 | static void smd_channel_probe_worker(struct work_struct *work) | 158 | static void smd_channel_probe_worker(struct work_struct *work) |
151 | { | 159 | { |
152 | struct smd_alloc_elm *shared; | 160 | struct smd_alloc_elm *shared; |
161 | unsigned ctype; | ||
153 | unsigned type; | 162 | unsigned type; |
154 | unsigned n; | 163 | unsigned n; |
155 | 164 | ||
@@ -165,12 +174,19 @@ static void smd_channel_probe_worker(struct work_struct *work) | |||
165 | continue; | 174 | continue; |
166 | if (!shared[n].name[0]) | 175 | if (!shared[n].name[0]) |
167 | continue; | 176 | continue; |
177 | ctype = shared[n].ctype; | ||
178 | type = ctype & SMD_TYPE_MASK; | ||
179 | |||
180 | /* DAL channels are stream but neither the modem, | ||
181 | * nor the DSP correctly indicate this. Fixup manually. | ||
182 | */ | ||
183 | if (!memcmp(shared[n].name, "DAL", 3)) | ||
184 | ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM; | ||
185 | |||
168 | type = shared[n].ctype & SMD_TYPE_MASK; | 186 | type = shared[n].ctype & SMD_TYPE_MASK; |
169 | if ((type == SMD_TYPE_APPS_MODEM) || | 187 | if ((type == SMD_TYPE_APPS_MODEM) || |
170 | (type == SMD_TYPE_APPS_DSP)) | 188 | (type == SMD_TYPE_APPS_DSP)) |
171 | smd_alloc_channel(shared[n].name, | 189 | smd_alloc_channel(shared[n].name, shared[n].cid, ctype); |
172 | shared[n].cid, | ||
173 | shared[n].ctype); | ||
174 | smd_ch_allocated[n] = 1; | 190 | smd_ch_allocated[n] = 1; |
175 | } | 191 | } |
176 | } | 192 | } |
@@ -403,67 +419,59 @@ static void handle_smd_irq(struct list_head *list, void (*notify)(void)) | |||
403 | do_smd_probe(); | 419 | do_smd_probe(); |
404 | } | 420 | } |
405 | 421 | ||
406 | static irqreturn_t smd_irq_handler(int irq, void *data) | 422 | static irqreturn_t smd_modem_irq_handler(int irq, void *data) |
423 | { | ||
424 | handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); | ||
425 | return IRQ_HANDLED; | ||
426 | } | ||
427 | |||
428 | static irqreturn_t smd_dsp_irq_handler(int irq, void *data) | ||
407 | { | 429 | { |
408 | handle_smd_irq(&smd_ch_list, notify_modem_smd); | 430 | handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); |
409 | return IRQ_HANDLED; | 431 | return IRQ_HANDLED; |
410 | } | 432 | } |
411 | 433 | ||
412 | static void smd_fake_irq_handler(unsigned long arg) | 434 | static void smd_fake_irq_handler(unsigned long arg) |
413 | { | 435 | { |
414 | smd_irq_handler(0, NULL); | 436 | handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); |
437 | handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); | ||
415 | } | 438 | } |
416 | 439 | ||
417 | static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); | 440 | static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); |
418 | 441 | ||
442 | static inline int smd_need_int(struct smd_channel *ch) | ||
443 | { | ||
444 | if (ch_is_open(ch)) { | ||
445 | if (ch->recv->fHEAD || ch->recv->fTAIL || ch->recv->fSTATE) | ||
446 | return 1; | ||
447 | if (ch->recv->state != ch->last_state) | ||
448 | return 1; | ||
449 | } | ||
450 | return 0; | ||
451 | } | ||
452 | |||
419 | void smd_sleep_exit(void) | 453 | void smd_sleep_exit(void) |
420 | { | 454 | { |
421 | unsigned long flags; | 455 | unsigned long flags; |
422 | struct smd_channel *ch; | 456 | struct smd_channel *ch; |
423 | unsigned tmp; | ||
424 | int need_int = 0; | 457 | int need_int = 0; |
425 | 458 | ||
426 | spin_lock_irqsave(&smd_lock, flags); | 459 | spin_lock_irqsave(&smd_lock, flags); |
427 | list_for_each_entry(ch, &smd_ch_list, ch_list) { | 460 | list_for_each_entry(ch, &smd_ch_list_modem, ch_list) { |
428 | if (ch_is_open(ch)) { | 461 | if (smd_need_int(ch)) { |
429 | if (ch->recv->fHEAD) { | 462 | need_int = 1; |
430 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | 463 | break; |
431 | pr_info("smd_sleep_exit ch %d fHEAD " | 464 | } |
432 | "%x %x %x\n", | 465 | } |
433 | ch->n, ch->recv->fHEAD, | 466 | list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) { |
434 | ch->recv->head, ch->recv->tail); | 467 | if (smd_need_int(ch)) { |
435 | need_int = 1; | 468 | need_int = 1; |
436 | break; | 469 | break; |
437 | } | ||
438 | if (ch->recv->fTAIL) { | ||
439 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
440 | pr_info("smd_sleep_exit ch %d fTAIL " | ||
441 | "%x %x %x\n", | ||
442 | ch->n, ch->recv->fTAIL, | ||
443 | ch->send->head, ch->send->tail); | ||
444 | need_int = 1; | ||
445 | break; | ||
446 | } | ||
447 | if (ch->recv->fSTATE) { | ||
448 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
449 | pr_info("smd_sleep_exit ch %d fSTATE %x" | ||
450 | "\n", ch->n, ch->recv->fSTATE); | ||
451 | need_int = 1; | ||
452 | break; | ||
453 | } | ||
454 | tmp = ch->recv->state; | ||
455 | if (tmp != ch->last_state) { | ||
456 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
457 | pr_info("smd_sleep_exit ch %d " | ||
458 | "state %x != %x\n", | ||
459 | ch->n, tmp, ch->last_state); | ||
460 | need_int = 1; | ||
461 | break; | ||
462 | } | ||
463 | } | 470 | } |
464 | } | 471 | } |
465 | spin_unlock_irqrestore(&smd_lock, flags); | 472 | spin_unlock_irqrestore(&smd_lock, flags); |
466 | do_smd_probe(); | 473 | do_smd_probe(); |
474 | |||
467 | if (need_int) { | 475 | if (need_int) { |
468 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | 476 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) |
469 | pr_info("smd_sleep_exit need interrupt\n"); | 477 | pr_info("smd_sleep_exit need interrupt\n"); |
@@ -737,7 +745,11 @@ int smd_open(const char *name, smd_channel_t **_ch, | |||
737 | *_ch = ch; | 745 | *_ch = ch; |
738 | 746 | ||
739 | spin_lock_irqsave(&smd_lock, flags); | 747 | spin_lock_irqsave(&smd_lock, flags); |
740 | list_add(&ch->ch_list, &smd_ch_list); | 748 | |
749 | if ((ch->type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) | ||
750 | list_add(&ch->ch_list, &smd_ch_list_modem); | ||
751 | else | ||
752 | list_add(&ch->ch_list, &smd_ch_list_dsp); | ||
741 | 753 | ||
742 | /* If the remote side is CLOSING, we need to get it to | 754 | /* If the remote side is CLOSING, we need to get it to |
743 | * move to OPENING (which we'll do by moving from CLOSED to | 755 | * move to OPENING (which we'll do by moving from CLOSED to |
@@ -982,7 +994,7 @@ int smd_core_init(void) | |||
982 | 994 | ||
983 | smd_info.ready = 1; | 995 | smd_info.ready = 1; |
984 | 996 | ||
985 | r = request_irq(INT_A9_M2A_0, smd_irq_handler, | 997 | r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler, |
986 | IRQF_TRIGGER_RISING, "smd_dev", 0); | 998 | IRQF_TRIGGER_RISING, "smd_dev", 0); |
987 | if (r < 0) | 999 | if (r < 0) |
988 | return r; | 1000 | return r; |
@@ -1000,6 +1012,16 @@ int smd_core_init(void) | |||
1000 | if (r < 0) | 1012 | if (r < 0) |
1001 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); | 1013 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); |
1002 | 1014 | ||
1015 | #if defined(CONFIG_QDSP6) | ||
1016 | r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler, | ||
1017 | IRQF_TRIGGER_RISING, "smd_dsp", 0); | ||
1018 | if (r < 0) { | ||
1019 | free_irq(INT_A9_M2A_0, 0); | ||
1020 | free_irq(INT_A9_M2A_5, 0); | ||
1021 | return r; | ||
1022 | } | ||
1023 | #endif | ||
1024 | |||
1003 | /* check for any SMD channels that may already exist */ | 1025 | /* check for any SMD channels that may already exist */ |
1004 | do_smd_probe(); | 1026 | do_smd_probe(); |
1005 | 1027 | ||