diff options
author | Brian Swetland <swetland@google.com> | 2009-04-26 21:38:49 -0400 |
---|---|---|
committer | Daniel Walker <dwalker@codeaurora.org> | 2010-05-12 12:15:01 -0400 |
commit | 5b0f5a3f6084397194a8b556cdca572ad8e14f05 (patch) | |
tree | 1835a38df270d648ab55af164885389ec9579581 /arch/arm/mach-msm/smd.c | |
parent | 4d4fb2660ddd2d8131ebc3314e4c648fc0f4b8dd (diff) |
msm: smd: initial support for smd v2
- support both v2 and v1 style smd channels
- support both v2 and v1 smsm shared state
- update smsm state defines and smem item enum
- prep work for dealing with smd to qdsp6
- simplify some smem access to minimize use of smem_alloc() at runtime
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 | 426 |
1 files changed, 258 insertions, 168 deletions
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c index 78031c0a6db3..f731ddeaa25c 100644 --- a/arch/arm/mach-msm/smd.c +++ b/arch/arm/mach-msm/smd.c | |||
@@ -46,10 +46,26 @@ enum { | |||
46 | 46 | ||
47 | static int msm_smd_debug_mask; | 47 | static int msm_smd_debug_mask; |
48 | 48 | ||
49 | struct shared_info | ||
50 | { | ||
51 | int ready; | ||
52 | unsigned state_apps; | ||
53 | unsigned state_modem; | ||
54 | }; | ||
55 | |||
56 | static unsigned dummy_state_apps; | ||
57 | static unsigned dummy_state_modem; | ||
58 | |||
59 | static struct shared_info smd_info = { | ||
60 | .state_apps = (unsigned) &dummy_state_apps, | ||
61 | .state_modem = (unsigned) &dummy_state_modem, | ||
62 | }; | ||
63 | |||
49 | module_param_named(debug_mask, msm_smd_debug_mask, | 64 | module_param_named(debug_mask, msm_smd_debug_mask, |
50 | int, S_IRUGO | S_IWUSR | S_IWGRP); | 65 | int, S_IRUGO | S_IWUSR | S_IWGRP); |
51 | 66 | ||
52 | void *smem_find(unsigned id, unsigned size); | 67 | void *smem_find(unsigned id, unsigned size); |
68 | static void *smem_item(unsigned id, unsigned *size); | ||
53 | static void smd_diag(void); | 69 | static void smd_diag(void); |
54 | 70 | ||
55 | static unsigned last_heap_free = 0xffffffff; | 71 | static unsigned last_heap_free = 0xffffffff; |
@@ -61,11 +77,16 @@ static inline void notify_other_smsm(void) | |||
61 | writel(1, MSM_A2M_INT(5)); | 77 | writel(1, MSM_A2M_INT(5)); |
62 | } | 78 | } |
63 | 79 | ||
64 | static inline void notify_other_smd(void) | 80 | static inline void notify_modem_smd(void) |
65 | { | 81 | { |
66 | writel(1, MSM_A2M_INT(0)); | 82 | writel(1, MSM_A2M_INT(0)); |
67 | } | 83 | } |
68 | 84 | ||
85 | static inline void notify_dsp_smd(void) | ||
86 | { | ||
87 | writel(1, MSM_A2M_INT(8)); | ||
88 | } | ||
89 | |||
69 | static void smd_diag(void) | 90 | static void smd_diag(void) |
70 | { | 91 | { |
71 | char *x; | 92 | char *x; |
@@ -96,34 +117,25 @@ extern int (*msm_check_for_modem_crash)(void); | |||
96 | 117 | ||
97 | static int check_for_modem_crash(void) | 118 | static int check_for_modem_crash(void) |
98 | { | 119 | { |
99 | struct smsm_shared *smsm; | 120 | if (readl(smd_info.state_modem) & SMSM_RESET) { |
100 | |||
101 | smsm = smem_find(ID_SHARED_STATE, 2 * sizeof(struct smsm_shared)); | ||
102 | |||
103 | /* if the modem's not ready yet, we have to hope for the best */ | ||
104 | if (!smsm) | ||
105 | return 0; | ||
106 | |||
107 | if (smsm[1].state & SMSM_RESET) { | ||
108 | handle_modem_crash(); | 121 | handle_modem_crash(); |
109 | return -1; | 122 | return -1; |
110 | } else { | ||
111 | return 0; | ||
112 | } | 123 | } |
124 | return 0; | ||
113 | } | 125 | } |
114 | 126 | ||
115 | #define SMD_SS_CLOSED 0x00000000 | 127 | #define SMD_SS_CLOSED 0x00000000 |
116 | #define SMD_SS_OPENING 0x00000001 | 128 | #define SMD_SS_OPENING 0x00000001 |
117 | #define SMD_SS_OPENED 0x00000002 | 129 | #define SMD_SS_OPENED 0x00000002 |
118 | #define SMD_SS_FLUSHING 0x00000003 | 130 | #define SMD_SS_FLUSHING 0x00000003 |
119 | #define SMD_SS_CLOSING 0x00000004 | 131 | #define SMD_SS_CLOSING 0x00000004 |
120 | #define SMD_SS_RESET 0x00000005 | 132 | #define SMD_SS_RESET 0x00000005 |
121 | #define SMD_SS_RESET_OPENING 0x00000006 | 133 | #define SMD_SS_RESET_OPENING 0x00000006 |
122 | 134 | ||
123 | #define SMD_BUF_SIZE 8192 | 135 | #define SMD_BUF_SIZE 8192 |
124 | #define SMD_CHANNELS 64 | 136 | #define SMD_CHANNELS 64 |
125 | 137 | ||
126 | #define SMD_HEADER_SIZE 20 | 138 | #define SMD_HEADER_SIZE 20 |
127 | 139 | ||
128 | 140 | ||
129 | /* the spinlock is used to synchronize between the | 141 | /* the spinlock is used to synchronize between the |
@@ -160,21 +172,33 @@ struct smd_half_channel { | |||
160 | unsigned char fUNUSED; | 172 | unsigned char fUNUSED; |
161 | unsigned tail; | 173 | unsigned tail; |
162 | unsigned head; | 174 | unsigned head; |
163 | unsigned char data[SMD_BUF_SIZE]; | 175 | } __attribute__((packed)); |
164 | }; | ||
165 | 176 | ||
166 | struct smd_shared { | 177 | struct smd_shared_v1 { |
167 | struct smd_half_channel ch0; | 178 | struct smd_half_channel ch0; |
179 | unsigned char data0[SMD_BUF_SIZE]; | ||
168 | struct smd_half_channel ch1; | 180 | struct smd_half_channel ch1; |
181 | unsigned char data1[SMD_BUF_SIZE]; | ||
169 | }; | 182 | }; |
170 | 183 | ||
184 | struct smd_shared_v2 { | ||
185 | struct smd_half_channel ch0; | ||
186 | struct smd_half_channel ch1; | ||
187 | }; | ||
188 | |||
171 | struct smd_channel { | 189 | struct smd_channel { |
172 | volatile struct smd_half_channel *send; | 190 | volatile struct smd_half_channel *send; |
173 | volatile struct smd_half_channel *recv; | 191 | volatile struct smd_half_channel *recv; |
174 | struct list_head ch_list; | 192 | unsigned char *send_data; |
193 | unsigned char *recv_data; | ||
175 | 194 | ||
195 | unsigned fifo_mask; | ||
196 | unsigned fifo_size; | ||
176 | unsigned current_packet; | 197 | unsigned current_packet; |
177 | unsigned n; | 198 | unsigned n; |
199 | |||
200 | struct list_head ch_list; | ||
201 | |||
178 | void *priv; | 202 | void *priv; |
179 | void (*notify)(void *priv, unsigned flags); | 203 | void (*notify)(void *priv, unsigned flags); |
180 | 204 | ||
@@ -185,22 +209,35 @@ struct smd_channel { | |||
185 | 209 | ||
186 | void (*update_state)(smd_channel_t *ch); | 210 | void (*update_state)(smd_channel_t *ch); |
187 | unsigned last_state; | 211 | unsigned last_state; |
212 | void (*notify_other_cpu)(void); | ||
213 | unsigned type; | ||
188 | 214 | ||
189 | char name[32]; | 215 | char name[32]; |
190 | struct platform_device pdev; | 216 | struct platform_device pdev; |
191 | }; | 217 | }; |
192 | 218 | ||
193 | static LIST_HEAD(smd_ch_closed_list); | 219 | static LIST_HEAD(smd_ch_closed_list); |
194 | static LIST_HEAD(smd_ch_list); | 220 | static LIST_HEAD(smd_ch_list); /* todo: per-target lists */ |
195 | 221 | ||
196 | static unsigned char smd_ch_allocated[64]; | 222 | static unsigned char smd_ch_allocated[64]; |
197 | static struct work_struct probe_work; | 223 | static struct work_struct probe_work; |
198 | 224 | ||
225 | #define SMD_TYPE_MASK 0x0FF | ||
226 | #define SMD_TYPE_APPS_MODEM 0x000 | ||
227 | #define SMD_TYPE_APPS_DSP 0x001 | ||
228 | #define SMD_TYPE_MODEM_DSP 0x002 | ||
229 | |||
230 | #define SMD_KIND_MASK 0xF00 | ||
231 | #define SMD_KIND_UNKNOWN 0x000 | ||
232 | #define SMD_KIND_STREAM 0x100 | ||
233 | #define SMD_KIND_PACKET 0x200 | ||
234 | |||
199 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); | 235 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type); |
200 | 236 | ||
201 | static void smd_channel_probe_worker(struct work_struct *work) | 237 | static void smd_channel_probe_worker(struct work_struct *work) |
202 | { | 238 | { |
203 | struct smd_alloc_elm *shared; | 239 | struct smd_alloc_elm *shared; |
240 | unsigned type; | ||
204 | unsigned n; | 241 | unsigned n; |
205 | 242 | ||
206 | shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); | 243 | shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); |
@@ -215,9 +252,12 @@ static void smd_channel_probe_worker(struct work_struct *work) | |||
215 | continue; | 252 | continue; |
216 | if (!shared[n].name[0]) | 253 | if (!shared[n].name[0]) |
217 | continue; | 254 | continue; |
218 | smd_alloc_channel(shared[n].name, | 255 | type = shared[n].ctype & SMD_TYPE_MASK; |
219 | shared[n].cid, | 256 | if ((type == SMD_TYPE_APPS_MODEM) || |
220 | shared[n].ctype); | 257 | (type == SMD_TYPE_APPS_DSP)) |
258 | smd_alloc_channel(shared[n].name, | ||
259 | shared[n].cid, | ||
260 | shared[n].ctype); | ||
221 | smd_ch_allocated[n] = 1; | 261 | smd_ch_allocated[n] = 1; |
222 | } | 262 | } |
223 | } | 263 | } |
@@ -247,14 +287,14 @@ static char *chstate(unsigned n) | |||
247 | /* how many bytes are available for reading */ | 287 | /* how many bytes are available for reading */ |
248 | static int smd_stream_read_avail(struct smd_channel *ch) | 288 | static int smd_stream_read_avail(struct smd_channel *ch) |
249 | { | 289 | { |
250 | return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1); | 290 | return (ch->recv->head - ch->recv->tail) & ch->fifo_mask; |
251 | } | 291 | } |
252 | 292 | ||
253 | /* how many bytes we are free to write */ | 293 | /* how many bytes we are free to write */ |
254 | static int smd_stream_write_avail(struct smd_channel *ch) | 294 | static int smd_stream_write_avail(struct smd_channel *ch) |
255 | { | 295 | { |
256 | return (SMD_BUF_SIZE - 1) - | 296 | return ch->fifo_mask - |
257 | ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1)); | 297 | ((ch->send->head - ch->send->tail) & ch->fifo_mask); |
258 | } | 298 | } |
259 | 299 | ||
260 | static int smd_packet_read_avail(struct smd_channel *ch) | 300 | static int smd_packet_read_avail(struct smd_channel *ch) |
@@ -286,19 +326,19 @@ static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) | |||
286 | { | 326 | { |
287 | unsigned head = ch->recv->head; | 327 | unsigned head = ch->recv->head; |
288 | unsigned tail = ch->recv->tail; | 328 | unsigned tail = ch->recv->tail; |
289 | *ptr = (void *) (ch->recv->data + tail); | 329 | *ptr = (void *) (ch->recv_data + tail); |
290 | 330 | ||
291 | if (tail <= head) | 331 | if (tail <= head) |
292 | return head - tail; | 332 | return head - tail; |
293 | else | 333 | else |
294 | return SMD_BUF_SIZE - tail; | 334 | return ch->fifo_size - tail; |
295 | } | 335 | } |
296 | 336 | ||
297 | /* advance the fifo read pointer after data from ch_read_buffer is consumed */ | 337 | /* advance the fifo read pointer after data from ch_read_buffer is consumed */ |
298 | static void ch_read_done(struct smd_channel *ch, unsigned count) | 338 | static void ch_read_done(struct smd_channel *ch, unsigned count) |
299 | { | 339 | { |
300 | BUG_ON(count > smd_stream_read_avail(ch)); | 340 | BUG_ON(count > smd_stream_read_avail(ch)); |
301 | ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1); | 341 | ch->recv->tail = (ch->recv->tail + count) & ch->fifo_mask; |
302 | ch->recv->fTAIL = 1; | 342 | ch->recv->fTAIL = 1; |
303 | } | 343 | } |
304 | 344 | ||
@@ -360,15 +400,15 @@ static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) | |||
360 | { | 400 | { |
361 | unsigned head = ch->send->head; | 401 | unsigned head = ch->send->head; |
362 | unsigned tail = ch->send->tail; | 402 | unsigned tail = ch->send->tail; |
363 | *ptr = (void *) (ch->send->data + head); | 403 | *ptr = (void *) (ch->send_data + head); |
364 | 404 | ||
365 | if (head < tail) { | 405 | if (head < tail) { |
366 | return tail - head - 1; | 406 | return tail - head - 1; |
367 | } else { | 407 | } else { |
368 | if (tail == 0) | 408 | if (tail == 0) |
369 | return SMD_BUF_SIZE - head - 1; | 409 | return ch->fifo_size - head - 1; |
370 | else | 410 | else |
371 | return SMD_BUF_SIZE - head; | 411 | return ch->fifo_size - head; |
372 | } | 412 | } |
373 | } | 413 | } |
374 | 414 | ||
@@ -378,24 +418,24 @@ static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) | |||
378 | static void ch_write_done(struct smd_channel *ch, unsigned count) | 418 | static void ch_write_done(struct smd_channel *ch, unsigned count) |
379 | { | 419 | { |
380 | BUG_ON(count > smd_stream_write_avail(ch)); | 420 | BUG_ON(count > smd_stream_write_avail(ch)); |
381 | ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1); | 421 | ch->send->head = (ch->send->head + count) & ch->fifo_mask; |
382 | ch->send->fHEAD = 1; | 422 | ch->send->fHEAD = 1; |
383 | } | 423 | } |
384 | 424 | ||
385 | static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n) | 425 | static void ch_set_state(struct smd_channel *ch, unsigned n) |
386 | { | 426 | { |
387 | if (n == SMD_SS_OPENED) { | 427 | if (n == SMD_SS_OPENED) { |
388 | hc->fDSR = 1; | 428 | ch->send->fDSR = 1; |
389 | hc->fCTS = 1; | 429 | ch->send->fCTS = 1; |
390 | hc->fCD = 1; | 430 | ch->send->fCD = 1; |
391 | } else { | 431 | } else { |
392 | hc->fDSR = 0; | 432 | ch->send->fDSR = 0; |
393 | hc->fCTS = 0; | 433 | ch->send->fCTS = 0; |
394 | hc->fCD = 0; | 434 | ch->send->fCD = 0; |
395 | } | 435 | } |
396 | hc->state = n; | 436 | ch->send->state = n; |
397 | hc->fSTATE = 1; | 437 | ch->send->fSTATE = 1; |
398 | notify_other_smd(); | 438 | ch->notify_other_cpu(); |
399 | } | 439 | } |
400 | 440 | ||
401 | static void do_smd_probe(void) | 441 | static void do_smd_probe(void) |
@@ -420,7 +460,7 @@ static void smd_state_change(struct smd_channel *ch, | |||
420 | ch->recv->tail = 0; | 460 | ch->recv->tail = 0; |
421 | case SMD_SS_OPENED: | 461 | case SMD_SS_OPENED: |
422 | if (ch->send->state != SMD_SS_OPENED) | 462 | if (ch->send->state != SMD_SS_OPENED) |
423 | hc_set_state(ch->send, SMD_SS_OPENED); | 463 | ch_set_state(ch, SMD_SS_OPENED); |
424 | ch->notify(ch->priv, SMD_EVENT_OPEN); | 464 | ch->notify(ch->priv, SMD_EVENT_OPEN); |
425 | break; | 465 | break; |
426 | case SMD_SS_FLUSHING: | 466 | case SMD_SS_FLUSHING: |
@@ -431,7 +471,7 @@ static void smd_state_change(struct smd_channel *ch, | |||
431 | } | 471 | } |
432 | } | 472 | } |
433 | 473 | ||
434 | static irqreturn_t smd_irq_handler(int irq, void *data) | 474 | static void handle_smd_irq(struct list_head *list, void (*notify)(void)) |
435 | { | 475 | { |
436 | unsigned long flags; | 476 | unsigned long flags; |
437 | struct smd_channel *ch; | 477 | struct smd_channel *ch; |
@@ -440,7 +480,7 @@ static irqreturn_t smd_irq_handler(int irq, void *data) | |||
440 | unsigned tmp; | 480 | unsigned tmp; |
441 | 481 | ||
442 | spin_lock_irqsave(&smd_lock, flags); | 482 | spin_lock_irqsave(&smd_lock, flags); |
443 | list_for_each_entry(ch, &smd_ch_list, ch_list) { | 483 | list_for_each_entry(ch, list, ch_list) { |
444 | ch_flags = 0; | 484 | ch_flags = 0; |
445 | if (ch_is_open(ch)) { | 485 | if (ch_is_open(ch)) { |
446 | if (ch->recv->fHEAD) { | 486 | if (ch->recv->fHEAD) { |
@@ -468,9 +508,14 @@ static irqreturn_t smd_irq_handler(int irq, void *data) | |||
468 | } | 508 | } |
469 | } | 509 | } |
470 | if (do_notify) | 510 | if (do_notify) |
471 | notify_other_smd(); | 511 | notify(); |
472 | spin_unlock_irqrestore(&smd_lock, flags); | 512 | spin_unlock_irqrestore(&smd_lock, flags); |
473 | do_smd_probe(); | 513 | do_smd_probe(); |
514 | } | ||
515 | |||
516 | static irqreturn_t smd_irq_handler(int irq, void *data) | ||
517 | { | ||
518 | handle_smd_irq(&smd_ch_list, notify_modem_smd); | ||
474 | return IRQ_HANDLED; | 519 | return IRQ_HANDLED; |
475 | } | 520 | } |
476 | 521 | ||
@@ -553,12 +598,19 @@ void smd_kick(smd_channel_t *ch) | |||
553 | ch->notify(ch->priv, SMD_EVENT_CLOSE); | 598 | ch->notify(ch->priv, SMD_EVENT_CLOSE); |
554 | } | 599 | } |
555 | ch->notify(ch->priv, SMD_EVENT_DATA); | 600 | ch->notify(ch->priv, SMD_EVENT_DATA); |
556 | notify_other_smd(); | 601 | ch->notify_other_cpu(); |
557 | spin_unlock_irqrestore(&smd_lock, flags); | 602 | spin_unlock_irqrestore(&smd_lock, flags); |
558 | } | 603 | } |
559 | 604 | ||
560 | static int smd_is_packet(int chn) | 605 | static int smd_is_packet(int chn, unsigned type) |
561 | { | 606 | { |
607 | type &= SMD_KIND_MASK; | ||
608 | if (type == SMD_KIND_PACKET) | ||
609 | return 1; | ||
610 | if (type == SMD_KIND_STREAM) | ||
611 | return 0; | ||
612 | |||
613 | /* older AMSS reports SMD_KIND_UNKNOWN always */ | ||
562 | if ((chn > 4) || (chn == 1)) | 614 | if ((chn > 4) || (chn == 1)) |
563 | return 1; | 615 | return 1; |
564 | else | 616 | else |
@@ -588,7 +640,7 @@ static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) | |||
588 | break; | 640 | break; |
589 | } | 641 | } |
590 | 642 | ||
591 | notify_other_smd(); | 643 | ch->notify_other_cpu(); |
592 | 644 | ||
593 | return orig_len - len; | 645 | return orig_len - len; |
594 | } | 646 | } |
@@ -621,7 +673,7 @@ static int smd_stream_read(smd_channel_t *ch, void *data, int len) | |||
621 | 673 | ||
622 | r = ch_read(ch, data, len); | 674 | r = ch_read(ch, data, len); |
623 | if (r > 0) | 675 | if (r > 0) |
624 | notify_other_smd(); | 676 | ch->notify_other_cpu(); |
625 | 677 | ||
626 | return r; | 678 | return r; |
627 | } | 679 | } |
@@ -639,7 +691,7 @@ static int smd_packet_read(smd_channel_t *ch, void *data, int len) | |||
639 | 691 | ||
640 | r = ch_read(ch, data, len); | 692 | r = ch_read(ch, data, len); |
641 | if (r > 0) | 693 | if (r > 0) |
642 | notify_other_smd(); | 694 | ch->notify_other_cpu(); |
643 | 695 | ||
644 | spin_lock_irqsave(&smd_lock, flags); | 696 | spin_lock_irqsave(&smd_lock, flags); |
645 | ch->current_packet -= r; | 697 | ch->current_packet -= r; |
@@ -649,28 +701,73 @@ static int smd_packet_read(smd_channel_t *ch, void *data, int len) | |||
649 | return r; | 701 | return r; |
650 | } | 702 | } |
651 | 703 | ||
652 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) | 704 | static int smd_alloc_v2(struct smd_channel *ch) |
653 | { | 705 | { |
654 | struct smd_channel *ch; | 706 | struct smd_shared_v2 *shared2; |
655 | struct smd_shared *shared; | 707 | void *buffer; |
708 | unsigned buffer_sz; | ||
656 | 709 | ||
657 | shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared)); | 710 | shared2 = smem_alloc(SMEM_SMD_BASE_ID + ch->n, sizeof(*shared2)); |
658 | if (!shared) { | 711 | buffer = smem_item(SMEM_SMD_FIFO_BASE_ID + ch->n, &buffer_sz); |
659 | pr_err("smd_alloc_channel() cid %d does not exist\n", cid); | 712 | |
660 | return; | 713 | if (!buffer) |
714 | return -1; | ||
715 | |||
716 | /* buffer must be a power-of-two size */ | ||
717 | if (buffer_sz & (buffer_sz - 1)) | ||
718 | return -1; | ||
719 | |||
720 | buffer_sz /= 2; | ||
721 | ch->send = &shared2->ch0; | ||
722 | ch->recv = &shared2->ch1; | ||
723 | ch->send_data = buffer; | ||
724 | ch->recv_data = buffer + buffer_sz; | ||
725 | ch->fifo_size = buffer_sz; | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int smd_alloc_v1(struct smd_channel *ch) | ||
730 | { | ||
731 | struct smd_shared_v1 *shared1; | ||
732 | shared1 = smem_alloc(ID_SMD_CHANNELS + ch->n, sizeof(*shared1)); | ||
733 | if (!shared1) { | ||
734 | pr_err("smd_alloc_channel() cid %d does not exist\n", ch->n); | ||
735 | return -1; | ||
661 | } | 736 | } |
737 | ch->send = &shared1->ch0; | ||
738 | ch->recv = &shared1->ch1; | ||
739 | ch->send_data = shared1->data0; | ||
740 | ch->recv_data = shared1->data1; | ||
741 | ch->fifo_size = SMD_BUF_SIZE; | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | |||
746 | static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) | ||
747 | { | ||
748 | struct smd_channel *ch; | ||
662 | 749 | ||
663 | ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); | 750 | ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); |
664 | if (ch == 0) { | 751 | if (ch == 0) { |
665 | pr_err("smd_alloc_channel() out of memory\n"); | 752 | pr_err("smd_alloc_channel() out of memory\n"); |
666 | return; | 753 | return; |
667 | } | 754 | } |
668 | |||
669 | ch->send = &shared->ch0; | ||
670 | ch->recv = &shared->ch1; | ||
671 | ch->n = cid; | 755 | ch->n = cid; |
672 | 756 | ||
673 | if (smd_is_packet(cid)) { | 757 | if (smd_alloc_v2(ch) && smd_alloc_v1(ch)) { |
758 | kfree(ch); | ||
759 | return; | ||
760 | } | ||
761 | |||
762 | ch->fifo_mask = ch->fifo_size - 1; | ||
763 | ch->type = type; | ||
764 | |||
765 | if ((type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) | ||
766 | ch->notify_other_cpu = notify_modem_smd; | ||
767 | else | ||
768 | ch->notify_other_cpu = notify_dsp_smd; | ||
769 | |||
770 | if (smd_is_packet(cid, type)) { | ||
674 | ch->read = smd_packet_read; | 771 | ch->read = smd_packet_read; |
675 | ch->write = smd_packet_write; | 772 | ch->write = smd_packet_write; |
676 | ch->read_avail = smd_packet_read_avail; | 773 | ch->read_avail = smd_packet_read_avail; |
@@ -684,14 +781,17 @@ static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) | |||
684 | ch->update_state = update_stream_state; | 781 | ch->update_state = update_stream_state; |
685 | } | 782 | } |
686 | 783 | ||
687 | memcpy(ch->name, "SMD_", 4); | 784 | if ((type & 0xff) == 0) |
785 | memcpy(ch->name, "SMD_", 4); | ||
786 | else | ||
787 | memcpy(ch->name, "DSP_", 4); | ||
688 | memcpy(ch->name + 4, name, 20); | 788 | memcpy(ch->name + 4, name, 20); |
689 | ch->name[23] = 0; | 789 | ch->name[23] = 0; |
690 | ch->pdev.name = ch->name; | 790 | ch->pdev.name = ch->name; |
691 | ch->pdev.id = -1; | 791 | ch->pdev.id = -1; |
692 | 792 | ||
693 | pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n", | 793 | pr_info("smd_alloc_channel() cid=%02d size=%05d '%s'\n", |
694 | ch->name, ch->n, shared); | 794 | ch->n, ch->fifo_size, ch->name); |
695 | 795 | ||
696 | mutex_lock(&smd_creation_mutex); | 796 | mutex_lock(&smd_creation_mutex); |
697 | list_add(&ch->ch_list, &smd_ch_closed_list); | 797 | list_add(&ch->ch_list, &smd_ch_closed_list); |
@@ -759,9 +859,9 @@ int smd_open(const char *name, smd_channel_t **_ch, | |||
759 | */ | 859 | */ |
760 | if (ch->recv->state == SMD_SS_CLOSING) { | 860 | if (ch->recv->state == SMD_SS_CLOSING) { |
761 | ch->send->head = 0; | 861 | ch->send->head = 0; |
762 | hc_set_state(ch->send, SMD_SS_OPENING); | 862 | ch_set_state(ch, SMD_SS_OPENING); |
763 | } else { | 863 | } else { |
764 | hc_set_state(ch->send, SMD_SS_OPENED); | 864 | ch_set_state(ch, SMD_SS_OPENED); |
765 | } | 865 | } |
766 | spin_unlock_irqrestore(&smd_lock, flags); | 866 | spin_unlock_irqrestore(&smd_lock, flags); |
767 | smd_kick(ch); | 867 | smd_kick(ch); |
@@ -781,7 +881,7 @@ int smd_close(smd_channel_t *ch) | |||
781 | spin_lock_irqsave(&smd_lock, flags); | 881 | spin_lock_irqsave(&smd_lock, flags); |
782 | ch->notify = do_nothing_notify; | 882 | ch->notify = do_nothing_notify; |
783 | list_del(&ch->ch_list); | 883 | list_del(&ch->ch_list); |
784 | hc_set_state(ch->send, SMD_SS_CLOSED); | 884 | ch_set_state(ch, SMD_SS_CLOSED); |
785 | spin_unlock_irqrestore(&smd_lock, flags); | 885 | spin_unlock_irqrestore(&smd_lock, flags); |
786 | 886 | ||
787 | mutex_lock(&smd_creation_mutex); | 887 | mutex_lock(&smd_creation_mutex); |
@@ -834,7 +934,7 @@ void *smem_alloc(unsigned id, unsigned size) | |||
834 | return smem_find(id, size); | 934 | return smem_find(id, size); |
835 | } | 935 | } |
836 | 936 | ||
837 | static void *_smem_find(unsigned id, unsigned *size) | 937 | static void *smem_item(unsigned id, unsigned *size) |
838 | { | 938 | { |
839 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | 939 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; |
840 | struct smem_heap_entry *toc = shared->heap_toc; | 940 | struct smem_heap_entry *toc = shared->heap_toc; |
@@ -845,6 +945,8 @@ static void *_smem_find(unsigned id, unsigned *size) | |||
845 | if (toc[id].allocated) { | 945 | if (toc[id].allocated) { |
846 | *size = toc[id].size; | 946 | *size = toc[id].size; |
847 | return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset); | 947 | return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset); |
948 | } else { | ||
949 | *size = 0; | ||
848 | } | 950 | } |
849 | 951 | ||
850 | return 0; | 952 | return 0; |
@@ -855,7 +957,7 @@ void *smem_find(unsigned id, unsigned size_in) | |||
855 | unsigned size; | 957 | unsigned size; |
856 | void *ptr; | 958 | void *ptr; |
857 | 959 | ||
858 | ptr = _smem_find(id, &size); | 960 | ptr = smem_item(id, &size); |
859 | if (!ptr) | 961 | if (!ptr) |
860 | return 0; | 962 | return 0; |
861 | 963 | ||
@@ -872,38 +974,20 @@ void *smem_find(unsigned id, unsigned size_in) | |||
872 | static irqreturn_t smsm_irq_handler(int irq, void *data) | 974 | static irqreturn_t smsm_irq_handler(int irq, void *data) |
873 | { | 975 | { |
874 | unsigned long flags; | 976 | unsigned long flags; |
875 | struct smsm_shared *smsm; | 977 | unsigned apps, modm; |
876 | 978 | ||
877 | spin_lock_irqsave(&smem_lock, flags); | 979 | spin_lock_irqsave(&smem_lock, flags); |
878 | smsm = smem_alloc(ID_SHARED_STATE, | ||
879 | 2 * sizeof(struct smsm_shared)); | ||
880 | 980 | ||
881 | if (smsm == 0) { | 981 | apps = readl(smd_info.state_apps); |
882 | pr_info("<SM NO STATE>\n"); | 982 | modm = readl(smd_info.state_modem); |
883 | } else { | ||
884 | unsigned apps = smsm[0].state; | ||
885 | unsigned modm = smsm[1].state; | ||
886 | |||
887 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
888 | pr_info("<SM %08x %08x>\n", apps, modm); | ||
889 | if (modm & SMSM_RESET) { | ||
890 | handle_modem_crash(); | ||
891 | } else { | ||
892 | apps |= SMSM_INIT; | ||
893 | if (modm & SMSM_SMDINIT) | ||
894 | apps |= SMSM_SMDINIT; | ||
895 | if (modm & SMSM_RPCINIT) | ||
896 | apps |= SMSM_RPCINIT; | ||
897 | } | ||
898 | 983 | ||
899 | if (smsm[0].state != apps) { | 984 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) |
900 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | 985 | pr_info("<SM %08x %08x>\n", apps, modm); |
901 | pr_info("<SM %08x NOTIFY>\n", apps); | 986 | if (modm & SMSM_RESET) { |
902 | smsm[0].state = apps; | 987 | handle_modem_crash(); |
903 | do_smd_probe(); | ||
904 | notify_other_smsm(); | ||
905 | } | ||
906 | } | 988 | } |
989 | do_smd_probe(); | ||
990 | |||
907 | spin_unlock_irqrestore(&smem_lock, flags); | 991 | spin_unlock_irqrestore(&smem_lock, flags); |
908 | return IRQ_HANDLED; | 992 | return IRQ_HANDLED; |
909 | } | 993 | } |
@@ -911,55 +995,42 @@ static irqreturn_t smsm_irq_handler(int irq, void *data) | |||
911 | int smsm_change_state(uint32_t clear_mask, uint32_t set_mask) | 995 | int smsm_change_state(uint32_t clear_mask, uint32_t set_mask) |
912 | { | 996 | { |
913 | unsigned long flags; | 997 | unsigned long flags; |
914 | struct smsm_shared *smsm; | 998 | unsigned state; |
999 | |||
1000 | if (!smd_info.ready) | ||
1001 | return -EIO; | ||
915 | 1002 | ||
916 | spin_lock_irqsave(&smem_lock, flags); | 1003 | spin_lock_irqsave(&smem_lock, flags); |
917 | 1004 | ||
918 | smsm = smem_alloc(ID_SHARED_STATE, | 1005 | if (readl(smd_info.state_modem) & SMSM_RESET) |
919 | 2 * sizeof(struct smsm_shared)); | 1006 | handle_modem_crash(); |
920 | 1007 | ||
921 | if (smsm) { | 1008 | state = (readl(smd_info.state_apps) & ~clear_mask) | set_mask; |
922 | if (smsm[1].state & SMSM_RESET) | 1009 | writel(state, smd_info.state_apps); |
923 | handle_modem_crash(); | 1010 | |
924 | smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask; | 1011 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) |
925 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | 1012 | pr_info("smsm_change_state %x\n", state); |
926 | pr_info("smsm_change_state %x\n", | 1013 | notify_other_smsm(); |
927 | smsm[0].state); | ||
928 | notify_other_smsm(); | ||
929 | } | ||
930 | 1014 | ||
931 | spin_unlock_irqrestore(&smem_lock, flags); | 1015 | spin_unlock_irqrestore(&smem_lock, flags); |
932 | 1016 | ||
933 | if (smsm == NULL) { | ||
934 | pr_err("smsm_change_state <SM NO STATE>\n"); | ||
935 | return -EIO; | ||
936 | } | ||
937 | return 0; | 1017 | return 0; |
938 | } | 1018 | } |
939 | 1019 | ||
940 | uint32_t smsm_get_state(void) | 1020 | uint32_t smsm_get_state(void) |
941 | { | 1021 | { |
942 | unsigned long flags; | 1022 | unsigned long flags; |
943 | struct smsm_shared *smsm; | ||
944 | uint32_t rv; | 1023 | uint32_t rv; |
945 | 1024 | ||
946 | spin_lock_irqsave(&smem_lock, flags); | 1025 | spin_lock_irqsave(&smem_lock, flags); |
947 | 1026 | ||
948 | smsm = smem_alloc(ID_SHARED_STATE, | 1027 | rv = readl(smd_info.state_modem); |
949 | 2 * sizeof(struct smsm_shared)); | ||
950 | |||
951 | if (smsm) | ||
952 | rv = smsm[1].state; | ||
953 | else | ||
954 | rv = 0; | ||
955 | 1028 | ||
956 | if (rv & SMSM_RESET) | 1029 | if (rv & SMSM_RESET) |
957 | handle_modem_crash(); | 1030 | handle_modem_crash(); |
958 | 1031 | ||
959 | spin_unlock_irqrestore(&smem_lock, flags); | 1032 | spin_unlock_irqrestore(&smem_lock, flags); |
960 | 1033 | ||
961 | if (smsm == NULL) | ||
962 | pr_err("smsm_get_state <SM NO STATE>\n"); | ||
963 | return rv; | 1034 | return rv; |
964 | } | 1035 | } |
965 | 1036 | ||
@@ -1069,6 +1140,25 @@ int smd_core_init(void) | |||
1069 | int r; | 1140 | int r; |
1070 | pr_info("smd_core_init()\n"); | 1141 | pr_info("smd_core_init()\n"); |
1071 | 1142 | ||
1143 | /* wait for essential items to be initialized */ | ||
1144 | for (;;) { | ||
1145 | unsigned size; | ||
1146 | void *state; | ||
1147 | state = smem_item(SMEM_SMSM_SHARED_STATE, &size); | ||
1148 | if (size == SMSM_V1_SIZE) { | ||
1149 | smd_info.state_apps = state + SMSM_V1_STATE_APPS; | ||
1150 | smd_info.state_modem = state + SMSM_V1_STATE_MODEM; | ||
1151 | break; | ||
1152 | } | ||
1153 | if (size == SMSM_V2_SIZE) { | ||
1154 | smd_info.state_apps = state + SMSM_V2_STATE_APPS; | ||
1155 | smd_info.state_modem = state + SMSM_V2_STATE_MODEM; | ||
1156 | break; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | smd_info.ready = 1; | ||
1161 | |||
1072 | r = request_irq(INT_A9_M2A_0, smd_irq_handler, | 1162 | r = request_irq(INT_A9_M2A_0, smd_irq_handler, |
1073 | IRQF_TRIGGER_RISING, "smd_dev", 0); | 1163 | IRQF_TRIGGER_RISING, "smd_dev", 0); |
1074 | if (r < 0) | 1164 | if (r < 0) |
@@ -1087,11 +1177,12 @@ int smd_core_init(void) | |||
1087 | if (r < 0) | 1177 | if (r < 0) |
1088 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); | 1178 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); |
1089 | 1179 | ||
1090 | /* we may have missed a signal while booting -- fake | 1180 | /* check for any SMD channels that may already exist */ |
1091 | * an interrupt to make sure we process any existing | 1181 | do_smd_probe(); |
1092 | * state | 1182 | |
1093 | */ | 1183 | /* indicate that we're up and running */ |
1094 | smsm_irq_handler(0, 0); | 1184 | writel(SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT, smd_info.state_apps); |
1185 | notify_other_smsm(); | ||
1095 | 1186 | ||
1096 | pr_info("smd_core_init() done\n"); | 1187 | pr_info("smd_core_init() done\n"); |
1097 | 1188 | ||
@@ -1100,15 +1191,16 @@ int smd_core_init(void) | |||
1100 | 1191 | ||
1101 | #if defined(CONFIG_DEBUG_FS) | 1192 | #if defined(CONFIG_DEBUG_FS) |
1102 | 1193 | ||
1103 | static int dump_ch(char *buf, int max, int n, | 1194 | static int dump_ch(char *buf, int max, struct smd_channel *ch) |
1104 | struct smd_half_channel *s, | ||
1105 | struct smd_half_channel *r) | ||
1106 | { | 1195 | { |
1196 | volatile struct smd_half_channel *s = ch->send; | ||
1197 | volatile struct smd_half_channel *r = ch->recv; | ||
1198 | |||
1107 | return scnprintf( | 1199 | return scnprintf( |
1108 | buf, max, | 1200 | buf, max, |
1109 | "ch%02d:" | 1201 | "ch%02d:" |
1110 | " %8s(%04d/%04d) %c%c%c%c%c%c%c <->" | 1202 | " %8s(%05d/%05d) %c%c%c%c%c%c%c <->" |
1111 | " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n, | 1203 | " %8s(%05d/%05d) %c%c%c%c%c%c%c\n", ch->n, |
1112 | chstate(s->state), s->tail, s->head, | 1204 | chstate(s->state), s->tail, s->head, |
1113 | s->fDSR ? 'D' : 'd', | 1205 | s->fDSR ? 'D' : 'd', |
1114 | s->fCTS ? 'C' : 'c', | 1206 | s->fCTS ? 'C' : 'c', |
@@ -1130,24 +1222,19 @@ static int dump_ch(char *buf, int max, int n, | |||
1130 | 1222 | ||
1131 | static int debug_read_stat(char *buf, int max) | 1223 | static int debug_read_stat(char *buf, int max) |
1132 | { | 1224 | { |
1133 | struct smsm_shared *smsm; | ||
1134 | char *msg; | 1225 | char *msg; |
1135 | int i = 0; | 1226 | int i = 0; |
1136 | 1227 | ||
1137 | smsm = smem_find(ID_SHARED_STATE, | ||
1138 | 2 * sizeof(struct smsm_shared)); | ||
1139 | |||
1140 | msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); | 1228 | msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); |
1141 | 1229 | ||
1142 | if (smsm) { | 1230 | if (readl(smd_info.state_modem) & SMSM_RESET) |
1143 | if (smsm[1].state & SMSM_RESET) | 1231 | i += scnprintf(buf + i, max - i, |
1144 | i += scnprintf(buf + i, max - i, | 1232 | "smsm: ARM9 HAS CRASHED\n"); |
1145 | "smsm: ARM9 HAS CRASHED\n"); | 1233 | |
1146 | i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", | 1234 | i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n", |
1147 | smsm[0].state, smsm[1].state); | 1235 | readl(smd_info.state_modem), |
1148 | } else { | 1236 | readl(smd_info.state_apps)); |
1149 | i += scnprintf(buf + i, max - i, "smsm: cannot find\n"); | 1237 | |
1150 | } | ||
1151 | if (msg) { | 1238 | if (msg) { |
1152 | msg[SZ_DIAG_ERR_MSG - 1] = 0; | 1239 | msg[SZ_DIAG_ERR_MSG - 1] = 0; |
1153 | i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); | 1240 | i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg); |
@@ -1172,7 +1259,7 @@ static int debug_read_mem(char *buf, int max) | |||
1172 | if (toc[n].allocated == 0) | 1259 | if (toc[n].allocated == 0) |
1173 | continue; | 1260 | continue; |
1174 | i += scnprintf(buf + i, max - i, | 1261 | i += scnprintf(buf + i, max - i, |
1175 | "%04d: offsed %08x size %08x\n", | 1262 | "%04d: offset %08x size %08x\n", |
1176 | n, toc[n].offset, toc[n].size); | 1263 | n, toc[n].offset, toc[n].size); |
1177 | } | 1264 | } |
1178 | return i; | 1265 | return i; |
@@ -1180,16 +1267,16 @@ static int debug_read_mem(char *buf, int max) | |||
1180 | 1267 | ||
1181 | static int debug_read_ch(char *buf, int max) | 1268 | static int debug_read_ch(char *buf, int max) |
1182 | { | 1269 | { |
1183 | struct smd_shared *shared; | 1270 | struct smd_channel *ch; |
1184 | int n, i = 0; | 1271 | unsigned long flags; |
1272 | int i = 0; | ||
1185 | 1273 | ||
1186 | for (n = 0; n < SMD_CHANNELS; n++) { | 1274 | spin_lock_irqsave(&smd_lock, flags); |
1187 | shared = smem_find(ID_SMD_CHANNELS + n, | 1275 | list_for_each_entry(ch, &smd_ch_list, ch_list) |
1188 | sizeof(struct smd_shared)); | 1276 | i += dump_ch(buf + i, max - i, ch); |
1189 | if (shared == 0) | 1277 | list_for_each_entry(ch, &smd_ch_closed_list, ch_list) |
1190 | continue; | 1278 | i += dump_ch(buf + i, max - i, ch); |
1191 | i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1); | 1279 | spin_unlock_irqrestore(&smd_lock, flags); |
1192 | } | ||
1193 | 1280 | ||
1194 | return i; | 1281 | return i; |
1195 | } | 1282 | } |
@@ -1206,7 +1293,7 @@ static int debug_read_build_id(char *buf, int max) | |||
1206 | unsigned size; | 1293 | unsigned size; |
1207 | void *data; | 1294 | void *data; |
1208 | 1295 | ||
1209 | data = _smem_find(SMEM_HW_SW_BUILD_ID, &size); | 1296 | data = smem_item(SMEM_HW_SW_BUILD_ID, &size); |
1210 | if (!data) | 1297 | if (!data) |
1211 | return 0; | 1298 | return 0; |
1212 | 1299 | ||
@@ -1228,9 +1315,12 @@ static int debug_read_alloc_tbl(char *buf, int max) | |||
1228 | if (shared[n].ref_count == 0) | 1315 | if (shared[n].ref_count == 0) |
1229 | continue; | 1316 | continue; |
1230 | i += scnprintf(buf + i, max - i, | 1317 | i += scnprintf(buf + i, max - i, |
1231 | "%03d: %20s cid=%02d ctype=%d ref_count=%d\n", | 1318 | "%03d: %-20s cid=%02d type=%03d " |
1319 | "kind=%02d ref_count=%d\n", | ||
1232 | n, shared[n].name, shared[n].cid, | 1320 | n, shared[n].name, shared[n].cid, |
1233 | shared[n].ctype, shared[n].ref_count); | 1321 | shared[n].ctype & 0xff, |
1322 | (shared[n].ctype >> 8) & 0xf, | ||
1323 | shared[n].ref_count); | ||
1234 | } | 1324 | } |
1235 | 1325 | ||
1236 | return i; | 1326 | return i; |