diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2015-03-13 14:09:34 -0400 |
---|---|---|
committer | Kumar Gala <galak@codeaurora.org> | 2015-03-27 12:31:02 -0400 |
commit | c0c89fafa289ea241ba3fb22d6f583f8089a719e (patch) | |
tree | 43e48055d1330a7fece805554b87f372d63e718d /arch/arm/mach-msm/smd.c | |
parent | 9eccca0843205f87c00404b663188b88eb248051 (diff) |
ARM: Remove mach-msm and associated ARM architecture code
The maintainers for mach-msm no longer have any plans to support
or test the platforms supported by this architecture[1]. Most likely
there aren't any active users of this code anyway, so let's
delete it.
[1] http://lkml.kernel.org/r/20150307031212.GA8434@fifo99.com
Cc: David Brown <davidb@codeaurora.org>
Cc: Bryan Huntsman <bryanh@codeaurora.org>
Cc: Daniel Walker <dwalker@fifo99.com>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Kumar Gala <galak@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm/smd.c')
-rw-r--r-- | arch/arm/mach-msm/smd.c | 1034 |
1 files changed, 0 insertions, 1034 deletions
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c deleted file mode 100644 index 7550f5a08956..000000000000 --- a/arch/arm/mach-msm/smd.c +++ /dev/null | |||
@@ -1,1034 +0,0 @@ | |||
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 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
18 | |||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/cdev.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/debugfs.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include <mach/msm_smd.h> | ||
33 | |||
34 | #include "smd_private.h" | ||
35 | #include "proc_comm.h" | ||
36 | |||
37 | #if defined(CONFIG_ARCH_QSD8X50) | ||
38 | #define CONFIG_QDSP6 1 | ||
39 | #endif | ||
40 | |||
41 | #define MODULE_NAME "msm_smd" | ||
42 | |||
43 | enum { | ||
44 | MSM_SMD_DEBUG = 1U << 0, | ||
45 | MSM_SMSM_DEBUG = 1U << 0, | ||
46 | }; | ||
47 | |||
48 | static int msm_smd_debug_mask; | ||
49 | |||
50 | struct shared_info { | ||
51 | int ready; | ||
52 | void __iomem *state; | ||
53 | }; | ||
54 | |||
55 | static unsigned dummy_state[SMSM_STATE_COUNT]; | ||
56 | |||
57 | static struct shared_info smd_info = { | ||
58 | /* FIXME: not a real __iomem pointer */ | ||
59 | .state = &dummy_state, | ||
60 | }; | ||
61 | |||
62 | module_param_named(debug_mask, msm_smd_debug_mask, | ||
63 | int, S_IRUGO | S_IWUSR | S_IWGRP); | ||
64 | |||
65 | static unsigned last_heap_free = 0xffffffff; | ||
66 | |||
67 | static inline void notify_other_smsm(void) | ||
68 | { | ||
69 | msm_a2m_int(5); | ||
70 | #ifdef CONFIG_QDSP6 | ||
71 | msm_a2m_int(8); | ||
72 | #endif | ||
73 | } | ||
74 | |||
75 | static inline void notify_modem_smd(void) | ||
76 | { | ||
77 | msm_a2m_int(0); | ||
78 | } | ||
79 | |||
80 | static inline void notify_dsp_smd(void) | ||
81 | { | ||
82 | msm_a2m_int(8); | ||
83 | } | ||
84 | |||
85 | static void smd_diag(void) | ||
86 | { | ||
87 | char *x; | ||
88 | |||
89 | x = smem_find(ID_DIAG_ERR_MSG, SZ_DIAG_ERR_MSG); | ||
90 | if (x != 0) { | ||
91 | x[SZ_DIAG_ERR_MSG - 1] = 0; | ||
92 | pr_debug("DIAG '%s'\n", x); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* call when SMSM_RESET flag is set in the A9's smsm_state */ | ||
97 | static void handle_modem_crash(void) | ||
98 | { | ||
99 | pr_err("ARM9 has CRASHED\n"); | ||
100 | smd_diag(); | ||
101 | |||
102 | /* in this case the modem or watchdog should reboot us */ | ||
103 | for (;;) | ||
104 | ; | ||
105 | } | ||
106 | |||
107 | uint32_t raw_smsm_get_state(enum smsm_state_item item) | ||
108 | { | ||
109 | return readl(smd_info.state + item * 4); | ||
110 | } | ||
111 | |||
112 | static int check_for_modem_crash(void) | ||
113 | { | ||
114 | if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) { | ||
115 | handle_modem_crash(); | ||
116 | return -1; | ||
117 | } | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* the spinlock is used to synchronize between the | ||
122 | * irq handler and code that mutates the channel | ||
123 | * list or fiddles with channel state | ||
124 | */ | ||
125 | DEFINE_SPINLOCK(smd_lock); | ||
126 | DEFINE_SPINLOCK(smem_lock); | ||
127 | |||
128 | /* the mutex is used during open() and close() | ||
129 | * operations to avoid races while creating or | ||
130 | * destroying smd_channel structures | ||
131 | */ | ||
132 | static DEFINE_MUTEX(smd_creation_mutex); | ||
133 | |||
134 | static int smd_initialized; | ||
135 | |||
136 | LIST_HEAD(smd_ch_closed_list); | ||
137 | LIST_HEAD(smd_ch_list_modem); | ||
138 | LIST_HEAD(smd_ch_list_dsp); | ||
139 | |||
140 | static unsigned char smd_ch_allocated[64]; | ||
141 | static struct work_struct probe_work; | ||
142 | |||
143 | /* how many bytes are available for reading */ | ||
144 | static int smd_stream_read_avail(struct smd_channel *ch) | ||
145 | { | ||
146 | return (ch->recv->head - ch->recv->tail) & ch->fifo_mask; | ||
147 | } | ||
148 | |||
149 | /* how many bytes we are free to write */ | ||
150 | static int smd_stream_write_avail(struct smd_channel *ch) | ||
151 | { | ||
152 | return ch->fifo_mask - | ||
153 | ((ch->send->head - ch->send->tail) & ch->fifo_mask); | ||
154 | } | ||
155 | |||
156 | static int smd_packet_read_avail(struct smd_channel *ch) | ||
157 | { | ||
158 | if (ch->current_packet) { | ||
159 | int n = smd_stream_read_avail(ch); | ||
160 | if (n > ch->current_packet) | ||
161 | n = ch->current_packet; | ||
162 | return n; | ||
163 | } else { | ||
164 | return 0; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static int smd_packet_write_avail(struct smd_channel *ch) | ||
169 | { | ||
170 | int n = smd_stream_write_avail(ch); | ||
171 | return n > SMD_HEADER_SIZE ? n - SMD_HEADER_SIZE : 0; | ||
172 | } | ||
173 | |||
174 | static int ch_is_open(struct smd_channel *ch) | ||
175 | { | ||
176 | return (ch->recv->state == SMD_SS_OPENED) && | ||
177 | (ch->send->state == SMD_SS_OPENED); | ||
178 | } | ||
179 | |||
180 | /* provide a pointer and length to readable data in the fifo */ | ||
181 | static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr) | ||
182 | { | ||
183 | unsigned head = ch->recv->head; | ||
184 | unsigned tail = ch->recv->tail; | ||
185 | *ptr = (void *) (ch->recv_data + tail); | ||
186 | |||
187 | if (tail <= head) | ||
188 | return head - tail; | ||
189 | else | ||
190 | return ch->fifo_size - tail; | ||
191 | } | ||
192 | |||
193 | /* advance the fifo read pointer after data from ch_read_buffer is consumed */ | ||
194 | static void ch_read_done(struct smd_channel *ch, unsigned count) | ||
195 | { | ||
196 | BUG_ON(count > smd_stream_read_avail(ch)); | ||
197 | ch->recv->tail = (ch->recv->tail + count) & ch->fifo_mask; | ||
198 | ch->send->fTAIL = 1; | ||
199 | } | ||
200 | |||
201 | /* basic read interface to ch_read_{buffer,done} used | ||
202 | * by smd_*_read() and update_packet_state() | ||
203 | * will read-and-discard if the _data pointer is null | ||
204 | */ | ||
205 | static int ch_read(struct smd_channel *ch, void *_data, int len) | ||
206 | { | ||
207 | void *ptr; | ||
208 | unsigned n; | ||
209 | unsigned char *data = _data; | ||
210 | int orig_len = len; | ||
211 | |||
212 | while (len > 0) { | ||
213 | n = ch_read_buffer(ch, &ptr); | ||
214 | if (n == 0) | ||
215 | break; | ||
216 | |||
217 | if (n > len) | ||
218 | n = len; | ||
219 | if (_data) | ||
220 | memcpy(data, ptr, n); | ||
221 | |||
222 | data += n; | ||
223 | len -= n; | ||
224 | ch_read_done(ch, n); | ||
225 | } | ||
226 | |||
227 | return orig_len - len; | ||
228 | } | ||
229 | |||
230 | static void update_stream_state(struct smd_channel *ch) | ||
231 | { | ||
232 | /* streams have no special state requiring updating */ | ||
233 | } | ||
234 | |||
235 | static void update_packet_state(struct smd_channel *ch) | ||
236 | { | ||
237 | unsigned hdr[5]; | ||
238 | int r; | ||
239 | |||
240 | /* can't do anything if we're in the middle of a packet */ | ||
241 | if (ch->current_packet != 0) | ||
242 | return; | ||
243 | |||
244 | /* don't bother unless we can get the full header */ | ||
245 | if (smd_stream_read_avail(ch) < SMD_HEADER_SIZE) | ||
246 | return; | ||
247 | |||
248 | r = ch_read(ch, hdr, SMD_HEADER_SIZE); | ||
249 | BUG_ON(r != SMD_HEADER_SIZE); | ||
250 | |||
251 | ch->current_packet = hdr[0]; | ||
252 | } | ||
253 | |||
254 | /* provide a pointer and length to next free space in the fifo */ | ||
255 | static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr) | ||
256 | { | ||
257 | unsigned head = ch->send->head; | ||
258 | unsigned tail = ch->send->tail; | ||
259 | *ptr = (void *) (ch->send_data + head); | ||
260 | |||
261 | if (head < tail) { | ||
262 | return tail - head - 1; | ||
263 | } else { | ||
264 | if (tail == 0) | ||
265 | return ch->fifo_size - head - 1; | ||
266 | else | ||
267 | return ch->fifo_size - head; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* advace the fifo write pointer after freespace | ||
272 | * from ch_write_buffer is filled | ||
273 | */ | ||
274 | static void ch_write_done(struct smd_channel *ch, unsigned count) | ||
275 | { | ||
276 | BUG_ON(count > smd_stream_write_avail(ch)); | ||
277 | ch->send->head = (ch->send->head + count) & ch->fifo_mask; | ||
278 | ch->send->fHEAD = 1; | ||
279 | } | ||
280 | |||
281 | static void ch_set_state(struct smd_channel *ch, unsigned n) | ||
282 | { | ||
283 | if (n == SMD_SS_OPENED) { | ||
284 | ch->send->fDSR = 1; | ||
285 | ch->send->fCTS = 1; | ||
286 | ch->send->fCD = 1; | ||
287 | } else { | ||
288 | ch->send->fDSR = 0; | ||
289 | ch->send->fCTS = 0; | ||
290 | ch->send->fCD = 0; | ||
291 | } | ||
292 | ch->send->state = n; | ||
293 | ch->send->fSTATE = 1; | ||
294 | ch->notify_other_cpu(); | ||
295 | } | ||
296 | |||
297 | static void do_smd_probe(void) | ||
298 | { | ||
299 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
300 | if (shared->heap_info.free_offset != last_heap_free) { | ||
301 | last_heap_free = shared->heap_info.free_offset; | ||
302 | schedule_work(&probe_work); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static void smd_state_change(struct smd_channel *ch, | ||
307 | unsigned last, unsigned next) | ||
308 | { | ||
309 | ch->last_state = next; | ||
310 | |||
311 | pr_debug("ch %d %d -> %d\n", ch->n, last, next); | ||
312 | |||
313 | switch (next) { | ||
314 | case SMD_SS_OPENING: | ||
315 | ch->recv->tail = 0; | ||
316 | case SMD_SS_OPENED: | ||
317 | if (ch->send->state != SMD_SS_OPENED) | ||
318 | ch_set_state(ch, SMD_SS_OPENED); | ||
319 | ch->notify(ch->priv, SMD_EVENT_OPEN); | ||
320 | break; | ||
321 | case SMD_SS_FLUSHING: | ||
322 | case SMD_SS_RESET: | ||
323 | /* we should force them to close? */ | ||
324 | default: | ||
325 | ch->notify(ch->priv, SMD_EVENT_CLOSE); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | static void handle_smd_irq(struct list_head *list, void (*notify)(void)) | ||
330 | { | ||
331 | unsigned long flags; | ||
332 | struct smd_channel *ch; | ||
333 | int do_notify = 0; | ||
334 | unsigned ch_flags; | ||
335 | unsigned tmp; | ||
336 | |||
337 | spin_lock_irqsave(&smd_lock, flags); | ||
338 | list_for_each_entry(ch, list, ch_list) { | ||
339 | ch_flags = 0; | ||
340 | if (ch_is_open(ch)) { | ||
341 | if (ch->recv->fHEAD) { | ||
342 | ch->recv->fHEAD = 0; | ||
343 | ch_flags |= 1; | ||
344 | do_notify |= 1; | ||
345 | } | ||
346 | if (ch->recv->fTAIL) { | ||
347 | ch->recv->fTAIL = 0; | ||
348 | ch_flags |= 2; | ||
349 | do_notify |= 1; | ||
350 | } | ||
351 | if (ch->recv->fSTATE) { | ||
352 | ch->recv->fSTATE = 0; | ||
353 | ch_flags |= 4; | ||
354 | do_notify |= 1; | ||
355 | } | ||
356 | } | ||
357 | tmp = ch->recv->state; | ||
358 | if (tmp != ch->last_state) | ||
359 | smd_state_change(ch, ch->last_state, tmp); | ||
360 | if (ch_flags) { | ||
361 | ch->update_state(ch); | ||
362 | ch->notify(ch->priv, SMD_EVENT_DATA); | ||
363 | } | ||
364 | } | ||
365 | if (do_notify) | ||
366 | notify(); | ||
367 | spin_unlock_irqrestore(&smd_lock, flags); | ||
368 | do_smd_probe(); | ||
369 | } | ||
370 | |||
371 | static irqreturn_t smd_modem_irq_handler(int irq, void *data) | ||
372 | { | ||
373 | handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); | ||
374 | return IRQ_HANDLED; | ||
375 | } | ||
376 | |||
377 | #if defined(CONFIG_QDSP6) | ||
378 | static irqreturn_t smd_dsp_irq_handler(int irq, void *data) | ||
379 | { | ||
380 | handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); | ||
381 | return IRQ_HANDLED; | ||
382 | } | ||
383 | #endif | ||
384 | |||
385 | static void smd_fake_irq_handler(unsigned long arg) | ||
386 | { | ||
387 | handle_smd_irq(&smd_ch_list_modem, notify_modem_smd); | ||
388 | handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd); | ||
389 | } | ||
390 | |||
391 | static DECLARE_TASKLET(smd_fake_irq_tasklet, smd_fake_irq_handler, 0); | ||
392 | |||
393 | static inline int smd_need_int(struct smd_channel *ch) | ||
394 | { | ||
395 | if (ch_is_open(ch)) { | ||
396 | if (ch->recv->fHEAD || ch->recv->fTAIL || ch->recv->fSTATE) | ||
397 | return 1; | ||
398 | if (ch->recv->state != ch->last_state) | ||
399 | return 1; | ||
400 | } | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | void smd_sleep_exit(void) | ||
405 | { | ||
406 | unsigned long flags; | ||
407 | struct smd_channel *ch; | ||
408 | int need_int = 0; | ||
409 | |||
410 | spin_lock_irqsave(&smd_lock, flags); | ||
411 | list_for_each_entry(ch, &smd_ch_list_modem, ch_list) { | ||
412 | if (smd_need_int(ch)) { | ||
413 | need_int = 1; | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | list_for_each_entry(ch, &smd_ch_list_dsp, ch_list) { | ||
418 | if (smd_need_int(ch)) { | ||
419 | need_int = 1; | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | spin_unlock_irqrestore(&smd_lock, flags); | ||
424 | do_smd_probe(); | ||
425 | |||
426 | if (need_int) { | ||
427 | if (msm_smd_debug_mask & MSM_SMD_DEBUG) | ||
428 | pr_info("smd_sleep_exit need interrupt\n"); | ||
429 | tasklet_schedule(&smd_fake_irq_tasklet); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | |||
434 | void smd_kick(smd_channel_t *ch) | ||
435 | { | ||
436 | unsigned long flags; | ||
437 | unsigned tmp; | ||
438 | |||
439 | spin_lock_irqsave(&smd_lock, flags); | ||
440 | ch->update_state(ch); | ||
441 | tmp = ch->recv->state; | ||
442 | if (tmp != ch->last_state) { | ||
443 | ch->last_state = tmp; | ||
444 | if (tmp == SMD_SS_OPENED) | ||
445 | ch->notify(ch->priv, SMD_EVENT_OPEN); | ||
446 | else | ||
447 | ch->notify(ch->priv, SMD_EVENT_CLOSE); | ||
448 | } | ||
449 | ch->notify(ch->priv, SMD_EVENT_DATA); | ||
450 | ch->notify_other_cpu(); | ||
451 | spin_unlock_irqrestore(&smd_lock, flags); | ||
452 | } | ||
453 | |||
454 | static int smd_is_packet(int chn, unsigned type) | ||
455 | { | ||
456 | type &= SMD_KIND_MASK; | ||
457 | if (type == SMD_KIND_PACKET) | ||
458 | return 1; | ||
459 | if (type == SMD_KIND_STREAM) | ||
460 | return 0; | ||
461 | |||
462 | /* older AMSS reports SMD_KIND_UNKNOWN always */ | ||
463 | if ((chn > 4) || (chn == 1)) | ||
464 | return 1; | ||
465 | else | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int smd_stream_write(smd_channel_t *ch, const void *_data, int len) | ||
470 | { | ||
471 | void *ptr; | ||
472 | const unsigned char *buf = _data; | ||
473 | unsigned xfer; | ||
474 | int orig_len = len; | ||
475 | |||
476 | if (len < 0) | ||
477 | return -EINVAL; | ||
478 | |||
479 | while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { | ||
480 | if (!ch_is_open(ch)) | ||
481 | break; | ||
482 | if (xfer > len) | ||
483 | xfer = len; | ||
484 | memcpy(ptr, buf, xfer); | ||
485 | ch_write_done(ch, xfer); | ||
486 | len -= xfer; | ||
487 | buf += xfer; | ||
488 | if (len == 0) | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | ch->notify_other_cpu(); | ||
493 | |||
494 | return orig_len - len; | ||
495 | } | ||
496 | |||
497 | static int smd_packet_write(smd_channel_t *ch, const void *_data, int len) | ||
498 | { | ||
499 | unsigned hdr[5]; | ||
500 | |||
501 | if (len < 0) | ||
502 | return -EINVAL; | ||
503 | |||
504 | if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE)) | ||
505 | return -ENOMEM; | ||
506 | |||
507 | hdr[0] = len; | ||
508 | hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0; | ||
509 | |||
510 | smd_stream_write(ch, hdr, sizeof(hdr)); | ||
511 | smd_stream_write(ch, _data, len); | ||
512 | |||
513 | return len; | ||
514 | } | ||
515 | |||
516 | static int smd_stream_read(smd_channel_t *ch, void *data, int len) | ||
517 | { | ||
518 | int r; | ||
519 | |||
520 | if (len < 0) | ||
521 | return -EINVAL; | ||
522 | |||
523 | r = ch_read(ch, data, len); | ||
524 | if (r > 0) | ||
525 | ch->notify_other_cpu(); | ||
526 | |||
527 | return r; | ||
528 | } | ||
529 | |||
530 | static int smd_packet_read(smd_channel_t *ch, void *data, int len) | ||
531 | { | ||
532 | unsigned long flags; | ||
533 | int r; | ||
534 | |||
535 | if (len < 0) | ||
536 | return -EINVAL; | ||
537 | |||
538 | if (len > ch->current_packet) | ||
539 | len = ch->current_packet; | ||
540 | |||
541 | r = ch_read(ch, data, len); | ||
542 | if (r > 0) | ||
543 | ch->notify_other_cpu(); | ||
544 | |||
545 | spin_lock_irqsave(&smd_lock, flags); | ||
546 | ch->current_packet -= r; | ||
547 | update_packet_state(ch); | ||
548 | spin_unlock_irqrestore(&smd_lock, flags); | ||
549 | |||
550 | return r; | ||
551 | } | ||
552 | |||
553 | static int smd_alloc_channel(const char *name, uint32_t cid, uint32_t type) | ||
554 | { | ||
555 | struct smd_channel *ch; | ||
556 | |||
557 | ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL); | ||
558 | if (ch == 0) { | ||
559 | pr_err("smd_alloc_channel() out of memory\n"); | ||
560 | return -1; | ||
561 | } | ||
562 | ch->n = cid; | ||
563 | |||
564 | if (_smd_alloc_channel(ch)) { | ||
565 | kfree(ch); | ||
566 | return -1; | ||
567 | } | ||
568 | |||
569 | ch->fifo_mask = ch->fifo_size - 1; | ||
570 | ch->type = type; | ||
571 | |||
572 | if ((type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) | ||
573 | ch->notify_other_cpu = notify_modem_smd; | ||
574 | else | ||
575 | ch->notify_other_cpu = notify_dsp_smd; | ||
576 | |||
577 | if (smd_is_packet(cid, type)) { | ||
578 | ch->read = smd_packet_read; | ||
579 | ch->write = smd_packet_write; | ||
580 | ch->read_avail = smd_packet_read_avail; | ||
581 | ch->write_avail = smd_packet_write_avail; | ||
582 | ch->update_state = update_packet_state; | ||
583 | } else { | ||
584 | ch->read = smd_stream_read; | ||
585 | ch->write = smd_stream_write; | ||
586 | ch->read_avail = smd_stream_read_avail; | ||
587 | ch->write_avail = smd_stream_write_avail; | ||
588 | ch->update_state = update_stream_state; | ||
589 | } | ||
590 | |||
591 | if ((type & 0xff) == 0) | ||
592 | memcpy(ch->name, "SMD_", 4); | ||
593 | else | ||
594 | memcpy(ch->name, "DSP_", 4); | ||
595 | memcpy(ch->name + 4, name, 20); | ||
596 | ch->name[23] = 0; | ||
597 | ch->pdev.name = ch->name; | ||
598 | ch->pdev.id = -1; | ||
599 | |||
600 | pr_debug("smd_alloc_channel() cid=%02d size=%05d '%s'\n", | ||
601 | ch->n, ch->fifo_size, ch->name); | ||
602 | |||
603 | mutex_lock(&smd_creation_mutex); | ||
604 | list_add(&ch->ch_list, &smd_ch_closed_list); | ||
605 | mutex_unlock(&smd_creation_mutex); | ||
606 | |||
607 | platform_device_register(&ch->pdev); | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static void smd_channel_probe_worker(struct work_struct *work) | ||
612 | { | ||
613 | struct smd_alloc_elm *shared; | ||
614 | unsigned ctype; | ||
615 | unsigned type; | ||
616 | unsigned n; | ||
617 | |||
618 | shared = smem_find(ID_CH_ALLOC_TBL, sizeof(*shared) * 64); | ||
619 | if (!shared) { | ||
620 | pr_err("cannot find allocation table\n"); | ||
621 | return; | ||
622 | } | ||
623 | for (n = 0; n < 64; n++) { | ||
624 | if (smd_ch_allocated[n]) | ||
625 | continue; | ||
626 | if (!shared[n].ref_count) | ||
627 | continue; | ||
628 | if (!shared[n].name[0]) | ||
629 | continue; | ||
630 | ctype = shared[n].ctype; | ||
631 | type = ctype & SMD_TYPE_MASK; | ||
632 | |||
633 | /* DAL channels are stream but neither the modem, | ||
634 | * nor the DSP correctly indicate this. Fixup manually. | ||
635 | */ | ||
636 | if (!memcmp(shared[n].name, "DAL", 3)) | ||
637 | ctype = (ctype & (~SMD_KIND_MASK)) | SMD_KIND_STREAM; | ||
638 | |||
639 | type = shared[n].ctype & SMD_TYPE_MASK; | ||
640 | if ((type == SMD_TYPE_APPS_MODEM) || | ||
641 | (type == SMD_TYPE_APPS_DSP)) | ||
642 | if (!smd_alloc_channel(shared[n].name, shared[n].cid, ctype)) | ||
643 | smd_ch_allocated[n] = 1; | ||
644 | } | ||
645 | } | ||
646 | |||
647 | static void do_nothing_notify(void *priv, unsigned flags) | ||
648 | { | ||
649 | } | ||
650 | |||
651 | struct smd_channel *smd_get_channel(const char *name) | ||
652 | { | ||
653 | struct smd_channel *ch; | ||
654 | |||
655 | mutex_lock(&smd_creation_mutex); | ||
656 | list_for_each_entry(ch, &smd_ch_closed_list, ch_list) { | ||
657 | if (!strcmp(name, ch->name)) { | ||
658 | list_del(&ch->ch_list); | ||
659 | mutex_unlock(&smd_creation_mutex); | ||
660 | return ch; | ||
661 | } | ||
662 | } | ||
663 | mutex_unlock(&smd_creation_mutex); | ||
664 | |||
665 | return NULL; | ||
666 | } | ||
667 | |||
668 | int smd_open(const char *name, smd_channel_t **_ch, | ||
669 | void *priv, void (*notify)(void *, unsigned)) | ||
670 | { | ||
671 | struct smd_channel *ch; | ||
672 | unsigned long flags; | ||
673 | |||
674 | if (smd_initialized == 0) { | ||
675 | pr_info("smd_open() before smd_init()\n"); | ||
676 | return -ENODEV; | ||
677 | } | ||
678 | |||
679 | ch = smd_get_channel(name); | ||
680 | if (!ch) | ||
681 | return -ENODEV; | ||
682 | |||
683 | if (notify == 0) | ||
684 | notify = do_nothing_notify; | ||
685 | |||
686 | ch->notify = notify; | ||
687 | ch->current_packet = 0; | ||
688 | ch->last_state = SMD_SS_CLOSED; | ||
689 | ch->priv = priv; | ||
690 | |||
691 | *_ch = ch; | ||
692 | |||
693 | spin_lock_irqsave(&smd_lock, flags); | ||
694 | |||
695 | if ((ch->type & SMD_TYPE_MASK) == SMD_TYPE_APPS_MODEM) | ||
696 | list_add(&ch->ch_list, &smd_ch_list_modem); | ||
697 | else | ||
698 | list_add(&ch->ch_list, &smd_ch_list_dsp); | ||
699 | |||
700 | /* If the remote side is CLOSING, we need to get it to | ||
701 | * move to OPENING (which we'll do by moving from CLOSED to | ||
702 | * OPENING) and then get it to move from OPENING to | ||
703 | * OPENED (by doing the same state change ourselves). | ||
704 | * | ||
705 | * Otherwise, it should be OPENING and we can move directly | ||
706 | * to OPENED so that it will follow. | ||
707 | */ | ||
708 | if (ch->recv->state == SMD_SS_CLOSING) { | ||
709 | ch->send->head = 0; | ||
710 | ch_set_state(ch, SMD_SS_OPENING); | ||
711 | } else { | ||
712 | ch_set_state(ch, SMD_SS_OPENED); | ||
713 | } | ||
714 | spin_unlock_irqrestore(&smd_lock, flags); | ||
715 | smd_kick(ch); | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | int smd_close(smd_channel_t *ch) | ||
721 | { | ||
722 | unsigned long flags; | ||
723 | |||
724 | if (ch == 0) | ||
725 | return -1; | ||
726 | |||
727 | spin_lock_irqsave(&smd_lock, flags); | ||
728 | ch->notify = do_nothing_notify; | ||
729 | list_del(&ch->ch_list); | ||
730 | ch_set_state(ch, SMD_SS_CLOSED); | ||
731 | spin_unlock_irqrestore(&smd_lock, flags); | ||
732 | |||
733 | mutex_lock(&smd_creation_mutex); | ||
734 | list_add(&ch->ch_list, &smd_ch_closed_list); | ||
735 | mutex_unlock(&smd_creation_mutex); | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | int smd_read(smd_channel_t *ch, void *data, int len) | ||
741 | { | ||
742 | return ch->read(ch, data, len); | ||
743 | } | ||
744 | |||
745 | int smd_write(smd_channel_t *ch, const void *data, int len) | ||
746 | { | ||
747 | return ch->write(ch, data, len); | ||
748 | } | ||
749 | |||
750 | int smd_write_atomic(smd_channel_t *ch, const void *data, int len) | ||
751 | { | ||
752 | unsigned long flags; | ||
753 | int res; | ||
754 | spin_lock_irqsave(&smd_lock, flags); | ||
755 | res = ch->write(ch, data, len); | ||
756 | spin_unlock_irqrestore(&smd_lock, flags); | ||
757 | return res; | ||
758 | } | ||
759 | |||
760 | int smd_read_avail(smd_channel_t *ch) | ||
761 | { | ||
762 | return ch->read_avail(ch); | ||
763 | } | ||
764 | |||
765 | int smd_write_avail(smd_channel_t *ch) | ||
766 | { | ||
767 | return ch->write_avail(ch); | ||
768 | } | ||
769 | |||
770 | int smd_wait_until_readable(smd_channel_t *ch, int bytes) | ||
771 | { | ||
772 | return -1; | ||
773 | } | ||
774 | |||
775 | int smd_wait_until_writable(smd_channel_t *ch, int bytes) | ||
776 | { | ||
777 | return -1; | ||
778 | } | ||
779 | |||
780 | int smd_cur_packet_size(smd_channel_t *ch) | ||
781 | { | ||
782 | return ch->current_packet; | ||
783 | } | ||
784 | |||
785 | |||
786 | /* ------------------------------------------------------------------------- */ | ||
787 | |||
788 | void *smem_alloc(unsigned id, unsigned size) | ||
789 | { | ||
790 | return smem_find(id, size); | ||
791 | } | ||
792 | |||
793 | void __iomem *smem_item(unsigned id, unsigned *size) | ||
794 | { | ||
795 | struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE; | ||
796 | struct smem_heap_entry *toc = shared->heap_toc; | ||
797 | |||
798 | if (id >= SMEM_NUM_ITEMS) | ||
799 | return NULL; | ||
800 | |||
801 | if (toc[id].allocated) { | ||
802 | *size = toc[id].size; | ||
803 | return (MSM_SHARED_RAM_BASE + toc[id].offset); | ||
804 | } else { | ||
805 | *size = 0; | ||
806 | } | ||
807 | |||
808 | return NULL; | ||
809 | } | ||
810 | |||
811 | void *smem_find(unsigned id, unsigned size_in) | ||
812 | { | ||
813 | unsigned size; | ||
814 | void *ptr; | ||
815 | |||
816 | ptr = smem_item(id, &size); | ||
817 | if (!ptr) | ||
818 | return 0; | ||
819 | |||
820 | size_in = ALIGN(size_in, 8); | ||
821 | if (size_in != size) { | ||
822 | pr_err("smem_find(%d, %d): wrong size %d\n", | ||
823 | id, size_in, size); | ||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | return ptr; | ||
828 | } | ||
829 | |||
830 | static irqreturn_t smsm_irq_handler(int irq, void *data) | ||
831 | { | ||
832 | unsigned long flags; | ||
833 | unsigned apps, modm; | ||
834 | |||
835 | spin_lock_irqsave(&smem_lock, flags); | ||
836 | |||
837 | apps = raw_smsm_get_state(SMSM_STATE_APPS); | ||
838 | modm = raw_smsm_get_state(SMSM_STATE_MODEM); | ||
839 | |||
840 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
841 | pr_info("<SM %08x %08x>\n", apps, modm); | ||
842 | if (modm & SMSM_RESET) | ||
843 | handle_modem_crash(); | ||
844 | |||
845 | do_smd_probe(); | ||
846 | |||
847 | spin_unlock_irqrestore(&smem_lock, flags); | ||
848 | return IRQ_HANDLED; | ||
849 | } | ||
850 | |||
851 | int smsm_change_state(enum smsm_state_item item, | ||
852 | uint32_t clear_mask, uint32_t set_mask) | ||
853 | { | ||
854 | void __iomem *addr = smd_info.state + item * 4; | ||
855 | unsigned long flags; | ||
856 | unsigned state; | ||
857 | |||
858 | if (!smd_info.ready) | ||
859 | return -EIO; | ||
860 | |||
861 | spin_lock_irqsave(&smem_lock, flags); | ||
862 | |||
863 | if (raw_smsm_get_state(SMSM_STATE_MODEM) & SMSM_RESET) | ||
864 | handle_modem_crash(); | ||
865 | |||
866 | state = (readl(addr) & ~clear_mask) | set_mask; | ||
867 | writel(state, addr); | ||
868 | |||
869 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
870 | pr_info("smsm_change_state %d %x\n", item, state); | ||
871 | notify_other_smsm(); | ||
872 | |||
873 | spin_unlock_irqrestore(&smem_lock, flags); | ||
874 | |||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | uint32_t smsm_get_state(enum smsm_state_item item) | ||
879 | { | ||
880 | unsigned long flags; | ||
881 | uint32_t rv; | ||
882 | |||
883 | spin_lock_irqsave(&smem_lock, flags); | ||
884 | |||
885 | rv = readl(smd_info.state + item * 4); | ||
886 | |||
887 | if (item == SMSM_STATE_MODEM && (rv & SMSM_RESET)) | ||
888 | handle_modem_crash(); | ||
889 | |||
890 | spin_unlock_irqrestore(&smem_lock, flags); | ||
891 | |||
892 | return rv; | ||
893 | } | ||
894 | |||
895 | #ifdef CONFIG_ARCH_MSM_SCORPION | ||
896 | |||
897 | int smsm_set_sleep_duration(uint32_t delay) | ||
898 | { | ||
899 | struct msm_dem_slave_data *ptr; | ||
900 | |||
901 | ptr = smem_find(SMEM_APPS_DEM_SLAVE_DATA, sizeof(*ptr)); | ||
902 | if (ptr == NULL) { | ||
903 | pr_err("smsm_set_sleep_duration <SM NO APPS_DEM_SLAVE_DATA>\n"); | ||
904 | return -EIO; | ||
905 | } | ||
906 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
907 | pr_info("smsm_set_sleep_duration %d -> %d\n", | ||
908 | ptr->sleep_time, delay); | ||
909 | ptr->sleep_time = delay; | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | #else | ||
914 | |||
915 | int smsm_set_sleep_duration(uint32_t delay) | ||
916 | { | ||
917 | uint32_t *ptr; | ||
918 | |||
919 | ptr = smem_find(SMEM_SMSM_SLEEP_DELAY, sizeof(*ptr)); | ||
920 | if (ptr == NULL) { | ||
921 | pr_err("smsm_set_sleep_duration <SM NO SLEEP_DELAY>\n"); | ||
922 | return -EIO; | ||
923 | } | ||
924 | if (msm_smd_debug_mask & MSM_SMSM_DEBUG) | ||
925 | pr_info("smsm_set_sleep_duration %d -> %d\n", | ||
926 | *ptr, delay); | ||
927 | *ptr = delay; | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | #endif | ||
932 | |||
933 | int smd_core_init(void) | ||
934 | { | ||
935 | int r; | ||
936 | |||
937 | /* wait for essential items to be initialized */ | ||
938 | for (;;) { | ||
939 | unsigned size; | ||
940 | void __iomem *state; | ||
941 | state = smem_item(SMEM_SMSM_SHARED_STATE, &size); | ||
942 | if (size == SMSM_V1_SIZE || size == SMSM_V2_SIZE) { | ||
943 | smd_info.state = state; | ||
944 | break; | ||
945 | } | ||
946 | } | ||
947 | |||
948 | smd_info.ready = 1; | ||
949 | |||
950 | r = request_irq(INT_A9_M2A_0, smd_modem_irq_handler, | ||
951 | IRQF_TRIGGER_RISING, "smd_dev", 0); | ||
952 | if (r < 0) | ||
953 | return r; | ||
954 | r = enable_irq_wake(INT_A9_M2A_0); | ||
955 | if (r < 0) | ||
956 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_0\n"); | ||
957 | |||
958 | r = request_irq(INT_A9_M2A_5, smsm_irq_handler, | ||
959 | IRQF_TRIGGER_RISING, "smsm_dev", 0); | ||
960 | if (r < 0) { | ||
961 | free_irq(INT_A9_M2A_0, 0); | ||
962 | return r; | ||
963 | } | ||
964 | r = enable_irq_wake(INT_A9_M2A_5); | ||
965 | if (r < 0) | ||
966 | pr_err("smd_core_init: enable_irq_wake failed for A9_M2A_5\n"); | ||
967 | |||
968 | #if defined(CONFIG_QDSP6) | ||
969 | r = request_irq(INT_ADSP_A11, smd_dsp_irq_handler, | ||
970 | IRQF_TRIGGER_RISING, "smd_dsp", 0); | ||
971 | if (r < 0) { | ||
972 | free_irq(INT_A9_M2A_0, 0); | ||
973 | free_irq(INT_A9_M2A_5, 0); | ||
974 | return r; | ||
975 | } | ||
976 | #endif | ||
977 | |||
978 | /* check for any SMD channels that may already exist */ | ||
979 | do_smd_probe(); | ||
980 | |||
981 | /* indicate that we're up and running */ | ||
982 | smsm_change_state(SMSM_STATE_APPS, | ||
983 | ~0, SMSM_INIT | SMSM_SMDINIT | SMSM_RPCINIT | SMSM_RUN); | ||
984 | #ifdef CONFIG_ARCH_MSM_SCORPION | ||
985 | smsm_change_state(SMSM_STATE_APPS_DEM, ~0, 0); | ||
986 | #endif | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static int msm_smd_probe(struct platform_device *pdev) | ||
992 | { | ||
993 | /* | ||
994 | * If we haven't waited for the ARM9 to boot up till now, | ||
995 | * then we need to wait here. Otherwise this should just | ||
996 | * return immediately. | ||
997 | */ | ||
998 | proc_comm_boot_wait(); | ||
999 | |||
1000 | INIT_WORK(&probe_work, smd_channel_probe_worker); | ||
1001 | |||
1002 | if (smd_core_init()) { | ||
1003 | pr_err("smd_core_init() failed\n"); | ||
1004 | return -1; | ||
1005 | } | ||
1006 | |||
1007 | do_smd_probe(); | ||
1008 | |||
1009 | msm_check_for_modem_crash = check_for_modem_crash; | ||
1010 | |||
1011 | msm_init_last_radio_log(THIS_MODULE); | ||
1012 | |||
1013 | smd_initialized = 1; | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | static struct platform_driver msm_smd_driver = { | ||
1019 | .probe = msm_smd_probe, | ||
1020 | .driver = { | ||
1021 | .name = MODULE_NAME, | ||
1022 | }, | ||
1023 | }; | ||
1024 | |||
1025 | static int __init msm_smd_init(void) | ||
1026 | { | ||
1027 | return platform_driver_register(&msm_smd_driver); | ||
1028 | } | ||
1029 | |||
1030 | module_init(msm_smd_init); | ||
1031 | |||
1032 | MODULE_DESCRIPTION("MSM Shared Memory Core"); | ||
1033 | MODULE_AUTHOR("Brian Swetland <swetland@google.com>"); | ||
1034 | MODULE_LICENSE("GPL"); | ||