PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/arm/mach-msm/dal.c

https://github.com/VorkTeam/vorkKernel-DESIRE
C | 603 lines | 453 code | 112 blank | 38 comment | 61 complexity | d54c0c8423b1db2a2573fb252436128d MD5 | raw file
  1. /* arch/arm/mach-msm/qdsp6/dal.c
  2. *
  3. * Copyright (C) 2009 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. #include <linux/kernel.h>
  17. #include <linux/slab.h>
  18. #include <linux/spinlock.h>
  19. #include <linux/mutex.h>
  20. #include <linux/list.h>
  21. #include <linux/sched.h>
  22. #include <linux/wait.h>
  23. #include <linux/errno.h>
  24. #include <linux/delay.h>
  25. #include <mach/msm_smd.h>
  26. #include <mach/msm_qdsp6_audio.h>
  27. #include "dal.h"
  28. #define DAL_TRACE 0
  29. struct dal_hdr {
  30. uint32_t length:16; /* message length (header inclusive) */
  31. uint32_t version:8; /* DAL protocol version */
  32. uint32_t priority:7;
  33. uint32_t async:1;
  34. uint32_t ddi:16; /* DDI method number */
  35. uint32_t prototype:8; /* DDI serialization format */
  36. uint32_t msgid:8; /* message id (DDI, ATTACH, DETACH, ...) */
  37. void *from;
  38. void *to;
  39. } __attribute__((packed));
  40. #define TRACE_DATA_MAX 128
  41. #define TRACE_LOG_MAX 32
  42. #define TRACE_LOG_MASK (TRACE_LOG_MAX - 1)
  43. struct dal_trace {
  44. unsigned timestamp;
  45. struct dal_hdr hdr;
  46. uint32_t data[TRACE_DATA_MAX];
  47. };
  48. #define DAL_HDR_SIZE (sizeof(struct dal_hdr))
  49. #define DAL_DATA_MAX 512
  50. #define DAL_MSG_MAX (DAL_HDR_SIZE + DAL_DATA_MAX)
  51. #define DAL_VERSION 0x11
  52. #define DAL_MSGID_DDI 0x00
  53. #define DAL_MSGID_ATTACH 0x01
  54. #define DAL_MSGID_DETACH 0x02
  55. #define DAL_MSGID_ASYNCH 0xC0
  56. #define DAL_MSGID_REPLY 0x80
  57. struct dal_channel {
  58. struct list_head list;
  59. struct list_head clients;
  60. /* synchronization for changing channel state,
  61. * adding/removing clients, smd callbacks, etc
  62. */
  63. spinlock_t lock;
  64. struct smd_channel *sch;
  65. char *name;
  66. /* events are delivered at IRQ context immediately, so
  67. * we only need one assembly buffer for the entire channel
  68. */
  69. struct dal_hdr hdr;
  70. unsigned char data[DAL_DATA_MAX];
  71. unsigned count;
  72. void *ptr;
  73. /* client which the current inbound message is for */
  74. struct dal_client *active;
  75. };
  76. struct dal_client {
  77. struct list_head list;
  78. struct dal_channel *dch;
  79. void *cookie;
  80. dal_event_func_t event;
  81. /* opaque handle for the far side */
  82. void *remote;
  83. /* dal rpc calls are fully synchronous -- only one call may be
  84. * active per client at a time
  85. */
  86. struct mutex write_lock;
  87. wait_queue_head_t wait;
  88. unsigned char data[DAL_DATA_MAX];
  89. void *reply;
  90. int reply_max;
  91. int status;
  92. unsigned msgid; /* msgid of expected reply */
  93. spinlock_t tr_lock;
  94. unsigned tr_head;
  95. unsigned tr_tail;
  96. struct dal_trace *tr_log;
  97. };
  98. static unsigned now(void)
  99. {
  100. struct timespec ts;
  101. ktime_get_ts(&ts);
  102. return (ts.tv_nsec / 1000000) + (ts.tv_sec * 1000);
  103. }
  104. void dal_trace(struct dal_client *c)
  105. {
  106. if (c->tr_log)
  107. return;
  108. c->tr_log = kzalloc(sizeof(struct dal_trace) * TRACE_LOG_MAX,
  109. GFP_KERNEL);
  110. }
  111. void dal_trace_print(struct dal_hdr *hdr, unsigned *data, int len, unsigned when)
  112. {
  113. int i;
  114. printk("DAL %08x -> %08x L=%03x A=%d D=%04x P=%02x M=%02x T=%d",
  115. (unsigned) hdr->from, (unsigned) hdr->to,
  116. hdr->length, hdr->async,
  117. hdr->ddi, hdr->prototype, hdr->msgid,
  118. when);
  119. len /= 4;
  120. for (i = 0; i < len; i++) {
  121. if (!(i & 7))
  122. printk("\n%03x", i * 4);
  123. printk(" %08x", data[i]);
  124. }
  125. printk("\n");
  126. }
  127. void dal_trace_dump(struct dal_client *c)
  128. {
  129. struct dal_trace *dt;
  130. unsigned n, len;
  131. if (!c->tr_log)
  132. return;
  133. for (n = c->tr_tail; n != c->tr_head; n = (n + 1) & TRACE_LOG_MASK) {
  134. dt = c->tr_log + n;
  135. len = dt->hdr.length - sizeof(dt->hdr);
  136. if (len > TRACE_DATA_MAX)
  137. len = TRACE_DATA_MAX;
  138. dal_trace_print(&dt->hdr, dt->data, len, dt->timestamp);
  139. }
  140. }
  141. static void dal_trace_log(struct dal_client *c,
  142. struct dal_hdr *hdr, void *data, unsigned len)
  143. {
  144. unsigned long flags;
  145. unsigned t, n;
  146. struct dal_trace *dt;
  147. t = now();
  148. if (len > TRACE_DATA_MAX)
  149. len = TRACE_DATA_MAX;
  150. spin_lock_irqsave(&c->tr_lock, flags);
  151. n = (c->tr_head + 1) & TRACE_LOG_MASK;
  152. if (c->tr_tail == n)
  153. c->tr_tail = (c->tr_tail + 1) & TRACE_LOG_MASK;
  154. dt = c->tr_log + n;
  155. dt->timestamp = t;
  156. memcpy(&dt->hdr, hdr, sizeof(struct dal_hdr));
  157. memcpy(dt->data, data, len);
  158. c->tr_head = n;
  159. spin_unlock_irqrestore(&c->tr_lock, flags);
  160. }
  161. static void dal_channel_notify(void *priv, unsigned event)
  162. {
  163. struct dal_channel *dch = priv;
  164. struct dal_hdr *hdr = &dch->hdr;
  165. struct dal_client *client;
  166. unsigned long flags;
  167. int len;
  168. int r;
  169. spin_lock_irqsave(&dch->lock, flags);
  170. again:
  171. if (dch->count == 0) {
  172. if (smd_read_avail(dch->sch) < DAL_HDR_SIZE)
  173. goto done;
  174. smd_read(dch->sch, hdr, DAL_HDR_SIZE);
  175. if (hdr->length < DAL_HDR_SIZE)
  176. goto done;
  177. if (hdr->length > DAL_MSG_MAX)
  178. panic("oversize message");
  179. dch->count = hdr->length - DAL_HDR_SIZE;
  180. /* locate the client this message is targeted to */
  181. list_for_each_entry(client, &dch->clients, list) {
  182. if (dch->hdr.to == client) {
  183. dch->active = client;
  184. dch->ptr = client->data;
  185. goto check_data;
  186. }
  187. }
  188. pr_err("$$$ receiving unknown message len = %d $$$\n",
  189. dch->count);
  190. dch->active = 0;
  191. dch->ptr = dch->data;
  192. }
  193. check_data:
  194. len = dch->count;
  195. if (len > 0) {
  196. if (smd_read_avail(dch->sch) < len)
  197. goto done;
  198. r = smd_read(dch->sch, dch->ptr, len);
  199. if (r != len)
  200. panic("invalid read");
  201. #if DAL_TRACE
  202. pr_info("dal recv %p <- %p %02x:%04x:%02x %d\n",
  203. hdr->to, hdr->from, hdr->msgid, hdr->ddi,
  204. hdr->prototype, hdr->length - sizeof(*hdr));
  205. print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, dch->ptr, len);
  206. #endif
  207. dch->count = 0;
  208. client = dch->active;
  209. if (!client) {
  210. pr_err("dal: message to %p discarded\n", dch->hdr.to);
  211. goto again;
  212. }
  213. if (client->tr_log)
  214. dal_trace_log(client, hdr, dch->ptr, len);
  215. if (hdr->msgid == DAL_MSGID_ASYNCH) {
  216. if (client->event)
  217. client->event(dch->ptr, len, client->cookie);
  218. else
  219. pr_err("dal: client %p has no event handler\n",
  220. client);
  221. goto again;
  222. }
  223. if (hdr->msgid == client->msgid) {
  224. if (!client->remote)
  225. client->remote = hdr->from;
  226. if (len > client->reply_max)
  227. len = client->reply_max;
  228. memcpy(client->reply, client->data, len);
  229. client->status = len;
  230. wake_up(&client->wait);
  231. goto again;
  232. }
  233. pr_err("dal: cannot find client %p\n", dch->hdr.to);
  234. goto again;
  235. }
  236. done:
  237. spin_unlock_irqrestore(&dch->lock, flags);
  238. }
  239. static LIST_HEAD(dal_channel_list);
  240. static DEFINE_MUTEX(dal_channel_list_lock);
  241. static struct dal_channel *dal_open_channel(const char *name)
  242. {
  243. struct dal_channel *dch;
  244. /* quick sanity check to avoid trying to talk to
  245. * some non-DAL channel...
  246. */
  247. if (strncmp(name, "DSP_DAL", 7) && strncmp(name, "SMD_DAL", 7))
  248. return 0;
  249. mutex_lock(&dal_channel_list_lock);
  250. list_for_each_entry(dch, &dal_channel_list, list) {
  251. if (!strcmp(dch->name, name))
  252. goto found_it;
  253. }
  254. dch = kzalloc(sizeof(*dch) + strlen(name) + 1, GFP_KERNEL);
  255. if (!dch)
  256. goto fail;
  257. dch->name = (char *) (dch + 1);
  258. strcpy(dch->name, name);
  259. spin_lock_init(&dch->lock);
  260. INIT_LIST_HEAD(&dch->clients);
  261. list_add(&dch->list, &dal_channel_list);
  262. found_it:
  263. if (!dch->sch) {
  264. if (smd_open(name, &dch->sch, dch, dal_channel_notify))
  265. dch = NULL;
  266. /* FIXME: wait for channel to open before returning */
  267. msleep(100);
  268. }
  269. fail:
  270. mutex_unlock(&dal_channel_list_lock);
  271. return dch;
  272. }
  273. int dal_call_raw(struct dal_client *client,
  274. struct dal_hdr *hdr,
  275. void *data, int data_len,
  276. void *reply, int reply_max)
  277. {
  278. struct dal_channel *dch = client->dch;
  279. unsigned long flags;
  280. client->reply = reply;
  281. client->reply_max = reply_max;
  282. client->msgid = hdr->msgid | DAL_MSGID_REPLY;
  283. client->status = -EBUSY;
  284. #if DAL_TRACE
  285. pr_info("dal send %p -> %p %02x:%04x:%02x %d\n",
  286. hdr->from, hdr->to, hdr->msgid, hdr->ddi,
  287. hdr->prototype, hdr->length - sizeof(*hdr));
  288. print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data, data_len);
  289. #endif
  290. if (client->tr_log)
  291. dal_trace_log(client, hdr, data, data_len);
  292. spin_lock_irqsave(&dch->lock, flags);
  293. /* FIXME: ensure entire message is written or none. */
  294. smd_write(dch->sch, hdr, sizeof(*hdr));
  295. smd_write(dch->sch, data, data_len);
  296. spin_unlock_irqrestore(&dch->lock, flags);
  297. if (!wait_event_timeout(client->wait, (client->status != -EBUSY), 5*HZ)) {
  298. dal_trace_dump(client);
  299. pr_err("dal: call timed out. dsp is probably dead.\n");
  300. dal_trace_print(hdr, data, data_len, 0);
  301. #if defined(CONFIG_MSM_QDSP6)
  302. q6audio_dsp_not_responding();
  303. #endif
  304. }
  305. return client->status;
  306. }
  307. int dal_call(struct dal_client *client,
  308. unsigned ddi, unsigned prototype,
  309. void *data, int data_len,
  310. void *reply, int reply_max)
  311. {
  312. struct dal_hdr hdr;
  313. int r;
  314. memset(&hdr, 0, sizeof(hdr));
  315. hdr.length = data_len + sizeof(hdr);
  316. hdr.version = DAL_VERSION;
  317. hdr.msgid = DAL_MSGID_DDI;
  318. hdr.ddi = ddi;
  319. hdr.prototype = prototype;
  320. hdr.from = client;
  321. hdr.to = client->remote;
  322. if (hdr.length > DAL_MSG_MAX)
  323. return -EINVAL;
  324. mutex_lock(&client->write_lock);
  325. r = dal_call_raw(client, &hdr, data, data_len, reply, reply_max);
  326. mutex_unlock(&client->write_lock);
  327. #if 0
  328. if ((r > 3) && (((uint32_t*) reply)[0] == 0)) {
  329. pr_info("dal call OK\n");
  330. } else {
  331. pr_info("dal call ERROR\n");
  332. }
  333. #endif
  334. return r;
  335. }
  336. struct dal_msg_attach {
  337. uint32_t device_id;
  338. char attach[64];
  339. char service_name[32];
  340. } __attribute__((packed));
  341. struct dal_reply_attach {
  342. uint32_t status;
  343. char name[64];
  344. };
  345. struct dal_client *dal_attach(uint32_t device_id, const char *name,
  346. dal_event_func_t func, void *cookie)
  347. {
  348. struct dal_hdr hdr;
  349. struct dal_msg_attach msg;
  350. struct dal_reply_attach reply;
  351. struct dal_channel *dch;
  352. struct dal_client *client;
  353. unsigned long flags;
  354. int r;
  355. dch = dal_open_channel(name);
  356. if (!dch)
  357. return 0;
  358. client = kzalloc(sizeof(*client), GFP_KERNEL);
  359. if (!client)
  360. return 0;
  361. client->dch = dch;
  362. client->event = func;
  363. client->cookie = cookie;
  364. mutex_init(&client->write_lock);
  365. spin_lock_init(&client->tr_lock);
  366. init_waitqueue_head(&client->wait);
  367. spin_lock_irqsave(&dch->lock, flags);
  368. list_add(&client->list, &dch->clients);
  369. spin_unlock_irqrestore(&dch->lock, flags);
  370. memset(&hdr, 0, sizeof(hdr));
  371. memset(&msg, 0, sizeof(msg));
  372. hdr.length = sizeof(hdr) + sizeof(msg);
  373. hdr.version = DAL_VERSION;
  374. hdr.msgid = DAL_MSGID_ATTACH;
  375. hdr.from = client;
  376. msg.device_id = device_id;
  377. r = dal_call_raw(client, &hdr, &msg, sizeof(msg),
  378. &reply, sizeof(reply));
  379. if ((r == sizeof(reply)) && (reply.status == 0)) {
  380. reply.name[63] = 0;
  381. pr_info("dal_attach: status = %d, name = '%s'\n",
  382. reply.status, reply.name);
  383. return client;
  384. }
  385. pr_err("dal_attach: failure\n");
  386. dal_detach(client);
  387. return 0;
  388. }
  389. int dal_detach(struct dal_client *client)
  390. {
  391. struct dal_channel *dch;
  392. unsigned long flags;
  393. mutex_lock(&client->write_lock);
  394. if (client->remote) {
  395. struct dal_hdr hdr;
  396. uint32_t data;
  397. memset(&hdr, 0, sizeof(hdr));
  398. hdr.length = sizeof(hdr) + sizeof(data);
  399. hdr.version = DAL_VERSION;
  400. hdr.msgid = DAL_MSGID_DETACH;
  401. hdr.from = client;
  402. hdr.to = client->remote;
  403. data = (uint32_t) client;
  404. dal_call_raw(client, &hdr, &data, sizeof(data),
  405. &data, sizeof(data));
  406. }
  407. dch = client->dch;
  408. spin_lock_irqsave(&dch->lock, flags);
  409. if (dch->active == client) {
  410. /* We have received a message header for this client
  411. * but not the body of the message. Ensure that when
  412. * the body arrives we don't write it into the now-closed
  413. * client. In *theory* this should never happen.
  414. */
  415. dch->active = 0;
  416. dch->ptr = dch->data;
  417. }
  418. list_del(&client->list);
  419. spin_unlock_irqrestore(&dch->lock, flags);
  420. mutex_unlock(&client->write_lock);
  421. kfree(client);
  422. return 0;
  423. }
  424. void *dal_get_remote_handle(struct dal_client *client)
  425. {
  426. return client->remote;
  427. }
  428. /* convenience wrappers */
  429. int dal_call_f0(struct dal_client *client, uint32_t ddi, uint32_t arg1)
  430. {
  431. uint32_t tmp = arg1;
  432. int res;
  433. res = dal_call(client, ddi, 0, &tmp, sizeof(tmp), &tmp, sizeof(tmp));
  434. if (res >= 4)
  435. return (int) tmp;
  436. return res;
  437. }
  438. int dal_call_f1(struct dal_client *client, uint32_t ddi, uint32_t arg1, uint32_t arg2)
  439. {
  440. uint32_t tmp[2];
  441. int res;
  442. tmp[0] = arg1;
  443. tmp[1] = arg2;
  444. res = dal_call(client, ddi, 1, tmp, sizeof(tmp), tmp, sizeof(uint32_t));
  445. if (res >= 4)
  446. return (int) tmp[0];
  447. return res;
  448. }
  449. int dal_call_f5(struct dal_client *client, uint32_t ddi, void *ibuf, uint32_t ilen)
  450. {
  451. uint32_t tmp[128];
  452. int res;
  453. int param_idx = 0;
  454. if (ilen + 4 > DAL_DATA_MAX)
  455. return -EINVAL;
  456. tmp[param_idx] = ilen;
  457. param_idx++;
  458. memcpy(&tmp[param_idx], ibuf, ilen);
  459. param_idx += DIV_ROUND_UP(ilen, 4);
  460. res = dal_call(client, ddi, 5, tmp, param_idx * 4, tmp, sizeof(tmp));
  461. if (res >= 4)
  462. return (int) tmp[0];
  463. return res;
  464. }
  465. int dal_call_f13(struct dal_client *client, uint32_t ddi, void *ibuf1,
  466. uint32_t ilen1, void *ibuf2, uint32_t ilen2, void *obuf,
  467. uint32_t olen)
  468. {
  469. uint32_t tmp[128];
  470. int res;
  471. int param_idx = 0;
  472. if (ilen1 + ilen2 + 8 > DAL_DATA_MAX)
  473. return -EINVAL;
  474. tmp[param_idx] = ilen1;
  475. param_idx++;
  476. memcpy(&tmp[param_idx], ibuf1, ilen1);
  477. param_idx += DIV_ROUND_UP(ilen1, 4);
  478. tmp[param_idx++] = ilen2;
  479. memcpy(&tmp[param_idx], ibuf2, ilen2);
  480. param_idx += DIV_ROUND_UP(ilen2, 4);
  481. tmp[param_idx++] = olen;
  482. res = dal_call(client, ddi, 13, tmp, param_idx * 4, tmp, sizeof(tmp));
  483. if (res >= 4)
  484. res = (int)tmp[0];
  485. if (!res) {
  486. if (tmp[1] > olen)
  487. return -EIO;
  488. memcpy(obuf, &tmp[2], tmp[1]);
  489. }
  490. return res;
  491. }