aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-msm/smd.c
diff options
context:
space:
mode:
authorBrian Swetland <swetland@google.com>2008-09-29 19:00:48 -0400
committerDaniel Walker <dwalker@codeaurora.org>2010-05-12 12:14:52 -0400
commit2eb44eb9c8026f3f548bfbc903156b6aea54ed24 (patch)
tree77c5a94f893eba0f7aab3570fc74200fddface22 /arch/arm/mach-msm/smd.c
parent830d843b75338b94b7c769a2c3b59b04744a9323 (diff)
[ARM] msm: shared memory interface for baseband processor ipc
This code provides the low level interface to the "shared memory state machine" (smsm), and the virtual serial channels (smd), used to communicate with the baseband processor. Higher level transports (rpc, ethernet, AT command channel, etc) ride on top of this. Signed-off-by: Brian Swetland <swetland@google.com>
Diffstat (limited to 'arch/arm/mach-msm/smd.c')
-rw-r--r--arch/arm/mach-msm/smd.c1330
1 files changed, 1330 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
new file mode 100644
index 000000000000..64d12323995e
--- /dev/null
+++ b/arch/arm/mach-msm/smd.c
@@ -0,0 +1,1330 @@
1/* arch/arm/mach-msm/smd.c
2 *
3 * Copyright (C) 2007 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/platform_device.h>
18#include <linux/module.h>
19#include <linux/fs.h>
20#include <linux/cdev.h>
21#include <linux/device.h>
22#include <linux/wait.h>
23#include <linux/interrupt.h>
24#include <linux/irq.h>
25#include <linux/list.h>
26#include <linux/slab.h>
27#include <linux/debugfs.h>
28#include <linux/delay.h>
29#include <linux/io.h>
30
31#include <mach/msm_smd.h>
32#include <mach/msm_iomap.h>
33#include <mach/system.h>
34
35#include "smd_private.h"
36#include "proc_comm.h"
37
38void (*msm_hw_reset_hook)(void);
39
40#define MODULE_NAME "msm_smd"
41
42enum {
43 MSM_SMD_DEBUG = 1U << 0,
44 MSM_SMSM_DEBUG = 1U << 0,
45};
46
47static int msm_smd_debug_mask;
48
49module_param_named(debug_mask, msm_smd_debug_mask,
50 int, S_IRUGO | S_IWUSR | S_IWGRP);
51
52void *smem_find(unsigned id, unsigned size);
53static void smd_diag(void);
54
55static unsigned last_heap_free = 0xffffffff;
56
57#define MSM_A2M_INT(n) (MSM_CSR_BASE + 0x400 + (n) * 4)
58
59static inline void notify_other_smsm(void)
60{
61 writel(1, MSM_A2M_INT(5));
62}
63
64static inline void notify_other_smd(void)
65{
66 writel(1, MSM_A2M_INT(0));
67}
68
69static void smd_diag(void)
70{
71 char *x;
72
73 x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
74 if (x != 0) {
75 x[SZ_DIAG_ERR_MSG - 1] = 0;
76 pr_info("smem: DIAG '%s'\n", x);
77 }
78}
79
80/* call when SMSM_RESET flag is set in the A9's smsm_state */
81static void handle_modem_crash(void)
82{
83 pr_err("ARM9 has CRASHED\n");
84 smd_diag();
85
86 /* hard reboot if possible */
87 if (msm_hw_reset_hook)
88 msm_hw_reset_hook();
89
90 /* in this case the modem or watchdog should reboot us */
91 for (;;)
92 ;
93}
94
95extern int (*msm_check_for_modem_crash)(void);
96
97static int check_for_modem_crash(void)
98{
99 struct smsm_shared *smsm;
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();
109 return -1;
110 } else {
111 return 0;
112 }
113}
114
115#define SMD_SS_CLOSED 0x00000000
116#define SMD_SS_OPENING 0x00000001
117#define SMD_SS_OPENED 0x00000002
118#define SMD_SS_FLUSHING 0x00000003
119#define SMD_SS_CLOSING 0x00000004
120#define SMD_SS_RESET 0x00000005
121#define SMD_SS_RESET_OPENING 0x00000006
122
123#define SMD_BUF_SIZE 8192
124#define SMD_CHANNELS 64
125
126#define SMD_HEADER_SIZE 20
127
128
129/* the spinlock is used to synchronize between the
130** irq handler and code that mutates the channel
131** list or fiddles with channel state
132*/
133static DEFINE_SPINLOCK(smd_lock);
134static DEFINE_SPINLOCK(smem_lock);
135
136/* the mutex is used during open() and close()
137** operations to avoid races while creating or
138** destroying smd_channel structures
139*/
140static DEFINE_MUTEX(smd_creation_mutex);
141
142static int smd_initialized;
143
144struct smd_alloc_elm {
145 char name[20];
146 uint32_t cid;
147 uint32_t ctype;
148 uint32_t ref_count;
149};
150
151struct smd_half_channel {
152 unsigned state;
153 unsigned char fDSR;
154 unsigned char fCTS;
155 unsigned char fCD;
156 unsigned char fRI;
157 unsigned char fHEAD;
158 unsigned char fTAIL;
159 unsigned char fSTATE;
160 unsigned char fUNUSED;
161 unsigned tail;
162 unsigned head;
163 unsigned char data[SMD_BUF_SIZE];
164};
165
166struct smd_shared {
167 struct smd_half_channel ch0;
168 struct smd_half_channel ch1;
169};
170
171struct smd_channel {
172 volatile struct smd_half_channel *send;
173 volatile struct smd_half_channel *recv;
174 struct list_head ch_list;
175
176 unsigned current_packet;
177 unsigned n;
178 void *priv;
179 void (*notify)(void *priv, unsigned flags);
180
181 int (*read)(smd_channel_t *ch, void *data, int len);
182 int (*write)(smd_channel_t *ch, const void *data, int len);
183 int (*read_avail)(smd_channel_t *ch);
184 int (*write_avail)(smd_channel_t *ch);
185
186 void (*update_state)(smd_channel_t *ch);
187 unsigned last_state;
188
189 char name[32];
190 struct platform_device pdev;
191};
192
193static LIST_HEAD(smd_ch_closed_list);
194static LIST_HEAD(smd_ch_list);
195
196static unsigned char smd_ch_allocated[64];
197static struct work_struct probe_work;
198
199static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type);
200
201static void smd_channel_probe_worker(struct work_struct *work)
202{
203 struct smd_alloc_elm *shared;
204 unsigned n;
205
206 shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
207
208 for (n = 0; n < 64; n++) {
209 if (smd_ch_allocated[n])
210 continue;
211 if (!shared[n].ref_count)
212 continue;
213 if (!shared[n].name[0])
214 continue;
215 smd_alloc_channel(shared[n].name,
216 shared[n].cid,
217 shared[n].ctype);
218 smd_ch_allocated[n] = 1;
219 }
220}
221
222static char *chstate(unsigned n)
223{
224 switch (n) {
225 case SMD_SS_CLOSED:
226 return "CLOSED";
227 case SMD_SS_OPENING:
228 return "OPENING";
229 case SMD_SS_OPENED:
230 return "OPENED";
231 case SMD_SS_FLUSHING:
232 return "FLUSHING";
233 case SMD_SS_CLOSING:
234 return "CLOSING";
235 case SMD_SS_RESET:
236 return "RESET";
237 case SMD_SS_RESET_OPENING:
238 return "ROPENING";
239 default:
240 return "UNKNOWN";
241 }
242}
243
244/* how many bytes are available for reading */
245static int smd_stream_read_avail(struct smd_channel *ch)
246{
247 return (ch->recv->head - ch->recv->tail) & (SMD_BUF_SIZE - 1);
248}
249
250/* how many bytes we are free to write */
251static int smd_stream_write_avail(struct smd_channel *ch)
252{
253 return (SMD_BUF_SIZE - 1) -
254 ((ch->send->head - ch->send->tail) & (SMD_BUF_SIZE - 1));
255}
256
257static int smd_packet_read_avail(struct smd_channel *ch)
258{
259 if (ch->current_packet) {
260 int n = smd_stream_read_avail(ch);
261 if (n > ch->current_packet)
262 n = ch->current_packet;
263 return n;
264 } else {
265 return 0;
266 }
267}
268
269static int smd_packet_write_avail(struct smd_channel *ch)
270{
271 int n = smd_stream_write_avail(ch);
272 return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0;
273}
274
275static int ch_is_open(struct smd_channel *ch)
276{
277 return (ch->recv->state == SMD_SS_OPENED) &&
278 (ch->send->state == SMD_SS_OPENED);
279}
280
281/* provide a pointer and length to readable data in the fifo */
282static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr)
283{
284 unsigned head = ch->recv->head;
285 unsigned tail = ch->recv->tail;
286 *ptr = (void *) (ch->recv->data + tail);
287
288 if (tail <= head)
289 return head - tail;
290 else
291 return SMD_BUF_SIZE - tail;
292}
293
294/* advance the fifo read pointer after data from ch_read_buffer is consumed */
295static void ch_read_done(struct smd_channel *ch, unsigned count)
296{
297 BUG_ON(count > smd_stream_read_avail(ch));
298 ch->recv->tail = (ch->recv->tail + count) & (SMD_BUF_SIZE - 1);
299 ch->recv->fTAIL = 1;
300}
301
302/* basic read interface to ch_read_{buffer,done} used
303** by smd_*_read() and update_packet_state()
304** will read-and-discard if the _data pointer is null
305*/
306static int ch_read(struct smd_channel *ch, void *_data, int len)
307{
308 void *ptr;
309 unsigned n;
310 unsigned char *data = _data;
311 int orig_len = len;
312
313 while (len > 0) {
314 n = ch_read_buffer(ch, &ptr);
315 if (n == 0)
316 break;
317
318 if (n > len)
319 n = len;
320 if (_data)
321 memcpy(data, ptr, n);
322
323 data += n;
324 len -= n;
325 ch_read_done(ch, n);
326 }
327
328 return orig_len - len;
329}
330
331static void update_stream_state(struct smd_channel *ch)
332{
333 /* streams have no special state requiring updating */
334}
335
336static void update_packet_state(struct smd_channel *ch)
337{
338 unsigned hdr[5];
339 int r;
340
341 /* can't do anything if we're in the middle of a packet */
342 if (ch->current_packet != 0)
343 return;
344
345 /* don't bother unless we can get the full header */
346 if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE)
347 return;
348
349 r = ch_read(ch, hdr, SMD_HEADER_SIZE);
350 BUG_ON(r != SMD_HEADER_SIZE);
351
352 ch->current_packet = hdr[0];
353}
354
355/* provide a pointer and length to next free space in the fifo */
356static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr)
357{
358 unsigned head = ch->send->head;
359 unsigned tail = ch->send->tail;
360 *ptr = (void *) (ch->send->data + head);
361
362 if (head < tail) {
363 return tail - head - 1;
364 } else {
365 if (tail == 0)
366 return SMD_BUF_SIZE - head - 1;
367 else
368 return SMD_BUF_SIZE - head;
369 }
370}
371
372/* advace the fifo write pointer after freespace
373 * from ch_write_buffer is filled
374 */
375static void ch_write_done(struct smd_channel *ch, unsigned count)
376{
377 BUG_ON(count > smd_stream_write_avail(ch));
378 ch->send->head = (ch->send->head + count) & (SMD_BUF_SIZE - 1);
379 ch->send->fHEAD = 1;
380}
381
382static void hc_set_state(volatile struct smd_half_channel *hc, unsigned n)
383{
384 if (n == SMD_SS_OPENED) {
385 hc->fDSR = 1;
386 hc->fCTS = 1;
387 hc->fCD = 1;
388 } else {
389 hc->fDSR = 0;
390 hc->fCTS = 0;
391 hc->fCD = 0;
392 }
393 hc->state = n;
394 hc->fSTATE = 1;
395 notify_other_smd();
396}
397
398static void do_smd_probe(void)
399{
400 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
401 if (shared->heap_info.free_offset != last_heap_free) {
402 last_heap_free = shared->heap_info.free_offset;
403 schedule_work(&probe_work);
404 }
405}
406
407static void smd_state_change(struct smd_channel *ch,
408 unsigned last, unsigned next)
409{
410 ch->last_state = next;
411
412 pr_info("SMD: ch %d %s -> %s\n", ch->n,
413 chstate(last), chstate(next));
414
415 switch (next) {
416 case SMD_SS_OPENING:
417 ch->recv->tail = 0;
418 case SMD_SS_OPENED:
419 if (ch->send->state != SMD_SS_OPENED)
420 hc_set_state(ch->send, SMD_SS_OPENED);
421 ch->notify(ch->priv, SMD_EVENT_OPEN);
422 break;
423 case SMD_SS_FLUSHING:
424 case SMD_SS_RESET:
425 /* we should force them to close? */
426 default:
427 ch->notify(ch->priv, SMD_EVENT_CLOSE);
428 }
429}
430
431static irqreturn_t smd_irq_handler(int irq, void *data)
432{
433 unsigned long flags;
434 struct smd_channel *ch;
435 int do_notify = 0;
436 unsigned ch_flags;
437 unsigned tmp;
438
439 spin_lock_irqsave(&smd_lock, flags);
440 list_for_each_entry(ch, &smd_ch_list, ch_list) {
441 ch_flags = 0;
442 if (ch_is_open(ch)) {
443 if (ch->recv->fHEAD) {
444 ch->recv->fHEAD = 0;
445 ch_flags |= 1;
446 do_notify |= 1;
447 }
448 if (ch->recv->fTAIL) {
449 ch->recv->fTAIL = 0;
450 ch_flags |= 2;
451 do_notify |= 1;
452 }
453 if (ch->recv->fSTATE) {
454 ch->recv->fSTATE = 0;
455 ch_flags |= 4;
456 do_notify |= 1;
457 }
458 }
459 tmp = ch->recv->state;
460 if (tmp != ch->last_state)
461 smd_state_change(ch, ch->last_state, tmp);
462 if (ch_flags) {
463 ch->update_state(ch);
464 ch->notify(ch->priv, SMD_EVENT_DATA);
465 }
466 }
467 if (do_notify)
468 notify_other_smd();
469 spin_unlock_irqrestore(&smd_lock, flags);
470 do_smd_probe();
471 return IRQ_HANDLED;
472}
473
474static void smd_fake_irq_handler(unsigned long arg)
475{
476 smd_irq_handler(0, NULL);
477}
478
479static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0);
480
481void smd_sleep_exit(void)
482{
483 unsigned long flags;
484 struct smd_channel *ch;
485 unsigned tmp;
486 int need_int = 0;
487
488 spin_lock_irqsave(&smd_lock, flags);
489 list_for_each_entry(ch, &smd_ch_list, ch_list) {
490 if (ch_is_open(ch)) {
491 if (ch->recv->fHEAD) {
492 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
493 pr_info("smd_sleep_exit ch %d fHEAD "
494 "%x %x %x\n",
495 ch->n, ch->recv->fHEAD,
496 ch->recv->head, ch->recv->tail);
497 need_int = 1;
498 break;
499 }
500 if (ch->recv->fTAIL) {
501 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
502 pr_info("smd_sleep_exit ch %d fTAIL "
503 "%x %x %x\n",
504 ch->n, ch->recv->fTAIL,
505 ch->send->head, ch->send->tail);
506 need_int = 1;
507 break;
508 }
509 if (ch->recv->fSTATE) {
510 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
511 pr_info("smd_sleep_exit ch %d fSTATE %x"
512 "\n", ch->n, ch->recv->fSTATE);
513 need_int = 1;
514 break;
515 }
516 tmp = ch->recv->state;
517 if (tmp != ch->last_state) {
518 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
519 pr_info("smd_sleep_exit ch %d "
520 "state %x != %x\n",
521 ch->n, tmp, ch->last_state);
522 need_int = 1;
523 break;
524 }
525 }
526 }
527 spin_unlock_irqrestore(&smd_lock, flags);
528 do_smd_probe();
529 if (need_int) {
530 if (msm_smd_debug_mask & MSM_SMD_DEBUG)
531 pr_info("smd_sleep_exit need interrupt\n");
532 tasklet_schedule(&smd_fake_irq_tasklet);
533 }
534}
535
536
537void smd_kick(smd_channel_t *ch)
538{
539 unsigned long flags;
540 unsigned tmp;
541
542 spin_lock_irqsave(&smd_lock, flags);
543 ch->update_state(ch);
544 tmp = ch->recv->state;
545 if (tmp != ch->last_state) {
546 ch->last_state = tmp;
547 if (tmp == SMD_SS_OPENED)
548 ch->notify(ch->priv, SMD_EVENT_OPEN);
549 else
550 ch->notify(ch->priv, SMD_EVENT_CLOSE);
551 }
552 ch->notify(ch->priv, SMD_EVENT_DATA);
553 notify_other_smd();
554 spin_unlock_irqrestore(&smd_lock, flags);
555}
556
557static int smd_is_packet(int chn)
558{
559 if ((chn > 4) || (chn == 1))
560 return 1;
561 else
562 return 0;
563}
564
565static int smd_stream_write(smd_channel_t *ch, const void *_data, int len)
566{
567 void *ptr;
568 const unsigned char *buf = _data;
569 unsigned xfer;
570 int orig_len = len;
571
572 if (len < 0)
573 return -EINVAL;
574
575 while ((xfer = ch_write_buffer(ch, &ptr)) != 0) {
576 if (!ch_is_open(ch))
577 break;
578 if (xfer > len)
579 xfer = len;
580 memcpy(ptr, buf, xfer);
581 ch_write_done(ch, xfer);
582 len -= xfer;
583 buf += xfer;
584 if (len == 0)
585 break;
586 }
587
588 notify_other_smd();
589
590 return orig_len - len;
591}
592
593static int smd_packet_write(smd_channel_t *ch, const void *_data, int len)
594{
595 unsigned hdr[5];
596
597 if (len < 0)
598 return -EINVAL;
599
600 if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE))
601 return -ENOMEM;
602
603 hdr[0] = len;
604 hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;
605
606 smd_stream_write(ch, hdr, sizeof(hdr));
607 smd_stream_write(ch, _data, len);
608
609 return len;
610}
611
612static int smd_stream_read(smd_channel_t *ch, void *data, int len)
613{
614 int r;
615
616 if (len < 0)
617 return -EINVAL;
618
619 r = ch_read(ch, data, len);
620 if (r > 0)
621 notify_other_smd();
622
623 return r;
624}
625
626static int smd_packet_read(smd_channel_t *ch, void *data, int len)
627{
628 unsigned long flags;
629 int r;
630
631 if (len < 0)
632 return -EINVAL;
633
634 if (len > ch->current_packet)
635 len = ch->current_packet;
636
637 r = ch_read(ch, data, len);
638 if (r > 0)
639 notify_other_smd();
640
641 spin_lock_irqsave(&smd_lock, flags);
642 ch->current_packet -= r;
643 update_packet_state(ch);
644 spin_unlock_irqrestore(&smd_lock, flags);
645
646 return r;
647}
648
649static void smd_alloc_channel(const char *name, uint32_t cid, uint32_t type)
650{
651 struct smd_channel *ch;
652 struct smd_shared *shared;
653
654 shared = smem_alloc(ID_SMD_CHANNELS + cid, sizeof(*shared));
655 if (!shared) {
656 pr_err("smd_alloc_channel() cid %d does not exist\n", cid);
657 return;
658 }
659
660 ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);
661 if (ch == 0) {
662 pr_err("smd_alloc_channel() out of memory\n");
663 return;
664 }
665
666 ch->send = &shared->ch0;
667 ch->recv = &shared->ch1;
668 ch->n = cid;
669
670 if (smd_is_packet(cid)) {
671 ch->read = smd_packet_read;
672 ch->write = smd_packet_write;
673 ch->read_avail = smd_packet_read_avail;
674 ch->write_avail = smd_packet_write_avail;
675 ch->update_state = update_packet_state;
676 } else {
677 ch->read = smd_stream_read;
678 ch->write = smd_stream_write;
679 ch->read_avail = smd_stream_read_avail;
680 ch->write_avail = smd_stream_write_avail;
681 ch->update_state = update_stream_state;
682 }
683
684 memcpy(ch->name, "SMD_", 4);
685 memcpy(ch->name + 4, name, 20);
686 ch->name[23] = 0;
687 ch->pdev.name = ch->name;
688 ch->pdev.id = -1;
689
690 pr_info("smd_alloc_channel() '%s' cid=%d, shared=%p\n",
691 ch->name, ch->n, shared);
692
693 mutex_lock(&smd_creation_mutex);
694 list_add(&ch->ch_list, &smd_ch_closed_list);
695 mutex_unlock(&smd_creation_mutex);
696
697 platform_device_register(&ch->pdev);
698}
699
700static void do_nothing_notify(void *priv, unsigned flags)
701{
702}
703
704struct smd_channel *smd_get_channel(const char *name)
705{
706 struct smd_channel *ch;
707
708 mutex_lock(&smd_creation_mutex);
709 list_for_each_entry(ch, &smd_ch_closed_list, ch_list) {
710 if (!strcmp(name, ch->name)) {
711 list_del(&ch->ch_list);
712 mutex_unlock(&smd_creation_mutex);
713 return ch;
714 }
715 }
716 mutex_unlock(&smd_creation_mutex);
717
718 return NULL;
719}
720
721int smd_open(const char *name, smd_channel_t **_ch,
722 void *priv, void (*notify)(void *, unsigned))
723{
724 struct smd_channel *ch;
725 unsigned long flags;
726
727 if (smd_initialized == 0) {
728 pr_info("smd_open() before smd_init()\n");
729 return -ENODEV;
730 }
731
732 ch = smd_get_channel(name);
733 if (!ch)
734 return -ENODEV;
735
736 if (notify == 0)
737 notify = do_nothing_notify;
738
739 ch->notify = notify;
740 ch->current_packet = 0;
741 ch->last_state = SMD_SS_CLOSED;
742 ch->priv = priv;
743
744 *_ch = ch;
745
746 spin_lock_irqsave(&smd_lock, flags);
747 list_add(&ch->ch_list, &smd_ch_list);
748
749 /* If the remote side is CLOSING, we need to get it to
750 * move to OPENING (which we'll do by moving from CLOSED to
751 * OPENING) and then get it to move from OPENING to
752 * OPENED (by doing the same state change ourselves).
753 *
754 * Otherwise, it should be OPENING and we can move directly
755 * to OPENED so that it will follow.
756 */
757 if (ch->recv->state == SMD_SS_CLOSING) {
758 ch->send->head = 0;
759 hc_set_state(ch->send, SMD_SS_OPENING);
760 } else {
761 hc_set_state(ch->send, SMD_SS_OPENED);
762 }
763 spin_unlock_irqrestore(&smd_lock, flags);
764 smd_kick(ch);
765
766 return 0;
767}
768
769int smd_close(smd_channel_t *ch)
770{
771 unsigned long flags;
772
773 pr_info("smd_close(%p)\n", ch);
774
775 if (ch == 0)
776 return -1;
777
778 spin_lock_irqsave(&smd_lock, flags);
779 ch->notify = do_nothing_notify;
780 list_del(&ch->ch_list);
781 hc_set_state(ch->send, SMD_SS_CLOSED);
782 spin_unlock_irqrestore(&smd_lock, flags);
783
784 mutex_lock(&smd_creation_mutex);
785 list_add(&ch->ch_list, &smd_ch_closed_list);
786 mutex_unlock(&smd_creation_mutex);
787
788 return 0;
789}
790
791int smd_read(smd_channel_t *ch, void *data, int len)
792{
793 return ch->read(ch, data, len);
794}
795
796int smd_write(smd_channel_t *ch, const void *data, int len)
797{
798 return ch->write(ch, data, len);
799}
800
801int smd_read_avail(smd_channel_t *ch)
802{
803 return ch->read_avail(ch);
804}
805
806int smd_write_avail(smd_channel_t *ch)
807{
808 return ch->write_avail(ch);
809}
810
811int smd_wait_until_readable(smd_channel_t *ch, int bytes)
812{
813 return -1;
814}
815
816int smd_wait_until_writable(smd_channel_t *ch, int bytes)
817{
818 return -1;
819}
820
821int smd_cur_packet_size(smd_channel_t *ch)
822{
823 return ch->current_packet;
824}
825
826
827/* ------------------------------------------------------------------------- */
828
829void *smem_alloc(unsigned id, unsigned size)
830{
831 return smem_find(id, size);
832}
833
834static void *_smem_find(unsigned id, unsigned *size)
835{
836 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
837 struct smem_heap_entry *toc = shared->heap_toc;
838
839 if (id >= SMEM_NUM_ITEMS)
840 return 0;
841
842 if (toc[id].allocated) {
843 *size = toc[id].size;
844 return (void *) (MSM_SHARED_RAM_BASE + toc[id].offset);
845 }
846
847 return 0;
848}
849
850void *smem_find(unsigned id, unsigned size_in)
851{
852 unsigned size;
853 void *ptr;
854
855 ptr = _smem_find(id, &size);
856 if (!ptr)
857 return 0;
858
859 size_in = ALIGN(size_in, 8);
860 if (size_in != size) {
861 pr_err("smem_find(%d, %d): wrong size %d\n",
862 id, size_in, size);
863 return 0;
864 }
865
866 return ptr;
867}
868
869static irqreturn_t smsm_irq_handler(int irq, void *data)
870{
871 unsigned long flags;
872 struct smsm_shared *smsm;
873
874 spin_lock_irqsave(&smem_lock, flags);
875 smsm = smem_alloc(ID_SHARED_STATE,
876 2 * sizeof(struct smsm_shared));
877
878 if (smsm == 0) {
879 pr_info("<SM NO STATE>\n");
880 } else {
881 unsigned apps = smsm[0].state;
882 unsigned modm = smsm[1].state;
883
884 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
885 pr_info("<SM %08x %08x>\n", apps, modm);
886 if (modm & SMSM_RESET) {
887 handle_modem_crash();
888 } else {
889 apps |= SMSM_INIT;
890 if (modm & SMSM_SMDINIT)
891 apps |= SMSM_SMDINIT;
892 if (modm & SMSM_RPCINIT)
893 apps |= SMSM_RPCINIT;
894 }
895
896 if (smsm[0].state != apps) {
897 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
898 pr_info("<SM %08x NOTIFY>\n", apps);
899 smsm[0].state = apps;
900 do_smd_probe();
901 notify_other_smsm();
902 }
903 }
904 spin_unlock_irqrestore(&smem_lock, flags);
905 return IRQ_HANDLED;
906}
907
908int smsm_change_state(uint32_t clear_mask, uint32_t set_mask)
909{
910 unsigned long flags;
911 struct smsm_shared *smsm;
912
913 spin_lock_irqsave(&smem_lock, flags);
914
915 smsm = smem_alloc(ID_SHARED_STATE,
916 2 * sizeof(struct smsm_shared));
917
918 if (smsm) {
919 if (smsm[1].state & SMSM_RESET)
920 handle_modem_crash();
921 smsm[0].state = (smsm[0].state & ~clear_mask) | set_mask;
922 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
923 pr_info("smsm_change_state %x\n",
924 smsm[0].state);
925 notify_other_smsm();
926 }
927
928 spin_unlock_irqrestore(&smem_lock, flags);
929
930 if (smsm == NULL) {
931 pr_err("smsm_change_state <SM NO STATE>\n");
932 return -EIO;
933 }
934 return 0;
935}
936
937uint32_t smsm_get_state(void)
938{
939 unsigned long flags;
940 struct smsm_shared *smsm;
941 uint32_t rv;
942
943 spin_lock_irqsave(&smem_lock, flags);
944
945 smsm = smem_alloc(ID_SHARED_STATE,
946 2 * sizeof(struct smsm_shared));
947
948 if (smsm)
949 rv = smsm[1].state;
950 else
951 rv = 0;
952
953 if (rv & SMSM_RESET)
954 handle_modem_crash();
955
956 spin_unlock_irqrestore(&smem_lock, flags);
957
958 if (smsm == NULL)
959 pr_err("smsm_get_state <SM NO STATE>\n");
960 return rv;
961}
962
963int smsm_set_sleep_duration(uint32_t delay)
964{
965 uint32_t *ptr;
966
967 ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
968 if (ptr == NULL) {
969 pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n");
970 return -EIO;
971 }
972 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
973 pr_info("smsm_set_sleep_duration %d -> %d\n",
974 *ptr, delay);
975 *ptr = delay;
976 return 0;
977}
978
979int smsm_set_interrupt_info(struct smsm_interrupt_info *info)
980{
981 struct smsm_interrupt_info *ptr;
982
983 ptr = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*ptr));
984 if (ptr == NULL) {
985 pr_err("smsm_set_sleep_duration <SM NO INT_INFO>\n");
986 return -EIO;
987 }
988 if (msm_smd_debug_mask & MSM_SMSM_DEBUG)
989 pr_info("smsm_set_interrupt_info %x %x -> %x %x\n",
990 ptr->aArm_en_mask, ptr->aArm_interrupts_pending,
991 info->aArm_en_mask, info->aArm_interrupts_pending);
992 *ptr = *info;
993 return 0;
994}
995
996#define MAX_NUM_SLEEP_CLIENTS 64
997#define MAX_SLEEP_NAME_LEN 8
998
999#define NUM_GPIO_INT_REGISTERS 6
1000#define GPIO_SMEM_NUM_GROUPS 2
1001#define GPIO_SMEM_MAX_PC_INTERRUPTS 8
1002
1003struct tramp_gpio_save {
1004 unsigned int enable;
1005 unsigned int detect;
1006 unsigned int polarity;
1007};
1008
1009struct tramp_gpio_smem {
1010 uint16_t num_fired[GPIO_SMEM_NUM_GROUPS];
1011 uint16_t fired[GPIO_SMEM_NUM_GROUPS][GPIO_SMEM_MAX_PC_INTERRUPTS];
1012 uint32_t enabled[NUM_GPIO_INT_REGISTERS];
1013 uint32_t detection[NUM_GPIO_INT_REGISTERS];
1014 uint32_t polarity[NUM_GPIO_INT_REGISTERS];
1015};
1016
1017
1018void smsm_print_sleep_info(void)
1019{
1020 unsigned long flags;
1021 uint32_t *ptr;
1022 struct tramp_gpio_smem *gpio;
1023 struct smsm_interrupt_info *int_info;
1024
1025
1026 spin_lock_irqsave(&smem_lock, flags);
1027
1028 ptr = smem_alloc(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr));
1029 if (ptr)
1030 pr_info("SMEM_SMSM_SLEEP_DELAY: %x\n", *ptr);
1031
1032 ptr = smem_alloc(SMEM_SMSM_LIMIT_SLEEP, sizeof(*ptr));
1033 if (ptr)
1034 pr_info("SMEM_SMSM_LIMIT_SLEEP: %x\n", *ptr);
1035
1036 ptr = smem_alloc(SMEM_SLEEP_POWER_COLLAPSE_DISABLED, sizeof(*ptr));
1037 if (ptr)
1038 pr_info("SMEM_SLEEP_POWER_COLLAPSE_DISABLED: %x\n", *ptr);
1039
1040 int_info = smem_alloc(SMEM_SMSM_INT_INFO, sizeof(*int_info));
1041 if (int_info)
1042 pr_info("SMEM_SMSM_INT_INFO %x %x %x\n",
1043 int_info->aArm_en_mask,
1044 int_info->aArm_interrupts_pending,
1045 int_info->aArm_wakeup_reason);
1046
1047 gpio = smem_alloc(SMEM_GPIO_INT, sizeof(*gpio));
1048 if (gpio) {
1049 int i;
1050 for (i = 0; i < NUM_GPIO_INT_REGISTERS; i++)
1051 pr_info("SMEM_GPIO_INT: %d: e %x d %x p %x\n",
1052 i, gpio->enabled[i], gpio->detection[i],
1053 gpio->polarity[i]);
1054
1055 for (i = 0; i < GPIO_SMEM_NUM_GROUPS; i++)
1056 pr_info("SMEM_GPIO_INT: %d: f %d: %d %d...\n",
1057 i, gpio->num_fired[i], gpio->fired[i][0],
1058 gpio->fired[i][1]);
1059 }
1060
1061 spin_unlock_irqrestore(&smem_lock, flags);
1062}
1063
1064int smd_core_init(void)
1065{
1066 int r;
1067 pr_info("smd_core_init()\n");
1068
1069 r = request_irq(INT_A9_M2A_0, smd_irq_handler,
1070 IRQF_TRIGGER_RISING, "smd_dev", 0);
1071 if (r < 0)
1072 return r;
1073 r = enable_irq_wake(INT_A9_M2A_0);
1074 if (r < 0)
1075 pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n");
1076
1077 r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
1078 IRQF_TRIGGER_RISING, "smsm_dev", 0);
1079 if (r < 0) {
1080 free_irq(INT_A9_M2A_0, 0);
1081 return r;
1082 }
1083 r = enable_irq_wake(INT_A9_M2A_5);
1084 if (r < 0)
1085 pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n");
1086
1087 /* we may have missed a signal while booting -- fake
1088 * an interrupt to make sure we process any existing
1089 * state
1090 */
1091 smsm_irq_handler(0, 0);
1092
1093 pr_info("smd_core_init() done\n");
1094
1095 return 0;
1096}
1097
1098#if defined(CONFIG_DEBUG_FS)
1099
1100static int dump_ch(char *buf, int max, int n,
1101 struct smd_half_channel *s,
1102 struct smd_half_channel *r)
1103{
1104 return scnprintf(
1105 buf, max,
1106 "ch%02d:"
1107 " %8s(%04d/%04d) %c%c%c%c%c%c%c <->"
1108 " %8s(%04d/%04d) %c%c%c%c%c%c%c\n", n,
1109 chstate(s->state), s->tail, s->head,
1110 s->fDSR ? 'D' : 'd',
1111 s->fCTS ? 'C' : 'c',
1112 s->fCD ? 'C' : 'c',
1113 s->fRI ? 'I' : 'i',
1114 s->fHEAD ? 'W' : 'w',
1115 s->fTAIL ? 'R' : 'r',
1116 s->fSTATE ? 'S' : 's',
1117 chstate(r->state), r->tail, r->head,
1118 r->fDSR ? 'D' : 'd',
1119 r->fCTS ? 'R' : 'r',
1120 r->fCD ? 'C' : 'c',
1121 r->fRI ? 'I' : 'i',
1122 r->fHEAD ? 'W' : 'w',
1123 r->fTAIL ? 'R' : 'r',
1124 r->fSTATE ? 'S' : 's'
1125 );
1126}
1127
1128static int debug_read_stat(char *buf, int max)
1129{
1130 struct smsm_shared *smsm;
1131 char *msg;
1132 int i = 0;
1133
1134 smsm = smem_find(ID_SHARED_STATE,
1135 2 * sizeof(struct smsm_shared));
1136
1137 msg = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG);
1138
1139 if (smsm) {
1140 if (smsm[1].state & SMSM_RESET)
1141 i += scnprintf(buf + i, max - i,
1142 "smsm: ARM9 HAS CRASHED\n");
1143 i += scnprintf(buf + i, max - i, "smsm: a9: %08x a11: %08x\n",
1144 smsm[0].state, smsm[1].state);
1145 } else {
1146 i += scnprintf(buf + i, max - i, "smsm: cannot find\n");
1147 }
1148 if (msg) {
1149 msg[SZ_DIAG_ERR_MSG - 1] = 0;
1150 i += scnprintf(buf + i, max - i, "diag: '%s'\n", msg);
1151 }
1152 return i;
1153}
1154
1155static int debug_read_mem(char *buf, int max)
1156{
1157 unsigned n;
1158 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
1159 struct smem_heap_entry *toc = shared->heap_toc;
1160 int i = 0;
1161
1162 i += scnprintf(buf + i, max - i,
1163 "heap: init=%d free=%d remain=%d\n",
1164 shared->heap_info.initialized,
1165 shared->heap_info.free_offset,
1166 shared->heap_info.heap_remaining);
1167
1168 for (n = 0; n < SMEM_NUM_ITEMS; n++) {
1169 if (toc[n].allocated == 0)
1170 continue;
1171 i += scnprintf(buf + i, max - i,
1172 "%04d: offsed %08x size %08x\n",
1173 n, toc[n].offset, toc[n].size);
1174 }
1175 return i;
1176}
1177
1178static int debug_read_ch(char *buf, int max)
1179{
1180 struct smd_shared *shared;
1181 int n, i = 0;
1182
1183 for (n = 0; n < SMD_CHANNELS; n++) {
1184 shared = smem_find(ID_SMD_CHANNELS + n,
1185 sizeof(struct smd_shared));
1186 if (shared == 0)
1187 continue;
1188 i += dump_ch(buf + i, max - i, n, &shared->ch0, &shared->ch1);
1189 }
1190
1191 return i;
1192}
1193
1194static int debug_read_version(char *buf, int max)
1195{
1196 struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
1197 unsigned version = shared->version[VERSION_MODEM];
1198 return sprintf(buf, "%d.%d\n", version >> 16, version & 0xffff);
1199}
1200
1201static int debug_read_build_id(char *buf, int max)
1202{
1203 unsigned size;
1204 void *data;
1205
1206 data = _smem_find(SMEM_HW_SW_BUILD_ID, &size);
1207 if (!data)
1208 return 0;
1209
1210 if (size >= max)
1211 size = max;
1212 memcpy(buf, data, size);
1213
1214 return size;
1215}
1216
1217static int debug_read_alloc_tbl(char *buf, int max)
1218{
1219 struct smd_alloc_elm *shared;
1220 int n, i = 0;
1221
1222 shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64);
1223
1224 for (n = 0; n < 64; n++) {
1225 if (shared[n].ref_count == 0)
1226 continue;
1227 i += scnprintf(buf + i, max - i,
1228 "%03d: %20s cid=%02d ctype=%d ref_count=%d\n",
1229 n, shared[n].name, shared[n].cid,
1230 shared[n].ctype, shared[n].ref_count);
1231 }
1232
1233 return i;
1234}
1235
1236static int debug_boom(char *buf, int max)
1237{
1238 unsigned ms = 5000;
1239 msm_proc_comm(PCOM_RESET_MODEM, &ms, 0);
1240 return 0;
1241}
1242
1243#define DEBUG_BUFMAX 4096
1244static char debug_buffer[DEBUG_BUFMAX];
1245
1246static ssize_t debug_read(struct file *file, char __user *buf,
1247 size_t count, loff_t *ppos)
1248{
1249 int (*fill)(char *buf, int max) = file->private_data;
1250 int bsize = fill(debug_buffer, DEBUG_BUFMAX);
1251 return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
1252}
1253
1254static int debug_open(struct inode *inode, struct file *file)
1255{
1256 file->private_data = inode->i_private;
1257 return 0;
1258}
1259
1260static const struct file_operations debug_ops = {
1261 .read = debug_read,
1262 .open = debug_open,
1263};
1264
1265static void debug_create(const char *name, mode_t mode,
1266 struct dentry *dent,
1267 int (*fill)(char *buf, int max))
1268{
1269 debugfs_create_file(name, mode, dent, fill, &debug_ops);
1270}
1271
1272static void smd_debugfs_init(void)
1273{
1274 struct dentry *dent;
1275
1276 dent = debugfs_create_dir("smd", 0);
1277 if (IS_ERR(dent))
1278 return;
1279
1280 debug_create("ch", 0444, dent, debug_read_ch);
1281 debug_create("stat", 0444, dent, debug_read_stat);
1282 debug_create("mem", 0444, dent, debug_read_mem);
1283 debug_create("version", 0444, dent, debug_read_version);
1284 debug_create("tbl", 0444, dent, debug_read_alloc_tbl);
1285 debug_create("build", 0444, dent, debug_read_build_id);
1286 debug_create("boom", 0444, dent, debug_boom);
1287}
1288#else
1289static void smd_debugfs_init(void) {}
1290#endif
1291
1292static int __init msm_smd_probe(struct platform_device *pdev)
1293{
1294 pr_info("smd_init()\n");
1295
1296 INIT_WORK(&probe_work, smd_channel_probe_worker);
1297
1298 if (smd_core_init()) {
1299 pr_err("smd_core_init() failed\n");
1300 return -1;
1301 }
1302
1303 do_smd_probe();
1304
1305 msm_check_for_modem_crash = check_for_modem_crash;
1306
1307 smd_debugfs_init();
1308 smd_initialized = 1;
1309
1310 return 0;
1311}
1312
1313static struct platform_driver msm_smd_driver = {
1314 .probe = msm_smd_probe,
1315 .driver = {
1316 .name = MODULE_NAME,
1317 .owner = THIS_MODULE,
1318 },
1319};
1320
1321static int __init msm_smd_init(void)
1322{
1323 return platform_driver_register(&msm_smd_driver);
1324}
1325
1326module_init(msm_smd_init);
1327
1328MODULE_DESCRIPTION("MSM Shared Memory Core");
1329MODULE_AUTHOR("Brian Swetland <swetland@google.com>");
1330MODULE_LICENSE("GPL");