ipc_router_hsic_xprt.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. /*
  13. * IPC ROUTER HSIC XPRT module.
  14. */
  15. #define DEBUG
  16. #include <linux/module.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/types.h>
  19. #include <mach/ipc_bridge.h>
  20. #include <mach/subsystem_restart.h>
  21. #include "ipc_router.h"
  22. static int msm_ipc_router_hsic_xprt_debug_mask;
  23. module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
  24. int, S_IRUGO | S_IWUSR | S_IWGRP);
  25. #if defined(DEBUG)
  26. #define D(x...) do { \
  27. if (msm_ipc_router_hsic_xprt_debug_mask) \
  28. pr_info(x); \
  29. } while (0)
  30. #else
  31. #define D(x...) do { } while (0)
  32. #endif
  33. #define NUM_HSIC_XPRTS 1
  34. #define XPRT_NAME_LEN 32
  35. /**
  36. * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT strucutre
  37. * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
  38. * @pdev: Platform device registered by IPC Bridge function driver.
  39. * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
  40. * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
  41. * @in_pkt: Pointer to any partially read packet.
  42. * @ss_reset_lock: Lock to protect access to the ss_reset flag.
  43. * @sft_close_complete: Variable to indicate completion of SSR handling
  44. * by IPC Router.
  45. * @xprt_version: IPC Router header version supported by this XPRT.
  46. * @xprt_option: XPRT specific options to be handled by IPC Router.
  47. */
  48. struct msm_ipc_router_hsic_xprt {
  49. struct msm_ipc_router_xprt xprt;
  50. struct platform_device *pdev;
  51. struct workqueue_struct *hsic_xprt_wq;
  52. struct delayed_work read_work;
  53. struct rr_packet *in_pkt;
  54. struct mutex ss_reset_lock;
  55. int ss_reset;
  56. struct completion sft_close_complete;
  57. unsigned xprt_version;
  58. unsigned xprt_option;
  59. };
  60. struct msm_ipc_router_hsic_xprt_work {
  61. struct msm_ipc_router_xprt *xprt;
  62. struct work_struct work;
  63. };
  64. static void hsic_xprt_read_data(struct work_struct *work);
  65. /**
  66. * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
  67. * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
  68. * @xprt_name: Name of the XPRT to be registered with IPC Router.
  69. * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
  70. * @link_id: Network Cluster ID to which this XPRT belongs to.
  71. * @xprt_version: IPC Router header version supported by this XPRT.
  72. */
  73. struct msm_ipc_router_hsic_xprt_config {
  74. char ch_name[XPRT_NAME_LEN];
  75. char xprt_name[XPRT_NAME_LEN];
  76. int hsic_pdev_id;
  77. uint32_t link_id;
  78. unsigned xprt_version;
  79. };
  80. struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
  81. {"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
  82. };
  83. static struct msm_ipc_router_hsic_xprt hsic_remote_xprt[NUM_HSIC_XPRTS];
  84. /**
  85. * find_hsic_xprt_cfg() - Find the config info specific to an HSIC endpoint
  86. * @pdev: Platform device registered by HSIC's ipc_bridge driver
  87. *
  88. * @return: Index to the entry in the hsic_remote_xprt table if matching
  89. * endpoint is found, < 0 on error.
  90. *
  91. * This function is used to find the configuration information specific to
  92. * an HSIC endpoint from the hsic_remote_xprt table.
  93. */
  94. static int find_hsic_xprt_cfg(struct platform_device *pdev)
  95. {
  96. int i;
  97. for (i = 0; i < NUM_HSIC_XPRTS; i++) {
  98. /* TODO: Update the condition for multiple hsic links */
  99. if (!strncmp(pdev->name, hsic_xprt_cfg[i].ch_name, 32))
  100. return i;
  101. }
  102. return -ENODEV;
  103. }
  104. /**
  105. * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
  106. * supported by the XPRT
  107. * @xprt: XPRT for which the version information is required.
  108. *
  109. * @return: IPC Router header version supported by the XPRT.
  110. */
  111. static int msm_ipc_router_hsic_get_xprt_version(
  112. struct msm_ipc_router_xprt *xprt)
  113. {
  114. struct msm_ipc_router_hsic_xprt *hsic_xprtp;
  115. if (!xprt)
  116. return -EINVAL;
  117. hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  118. return (int)hsic_xprtp->xprt_version;
  119. }
  120. /**
  121. * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
  122. * @xprt: XPRT for which the option information is required.
  123. *
  124. * @return: Options supported by the XPRT.
  125. */
  126. static int msm_ipc_router_hsic_get_xprt_option(
  127. struct msm_ipc_router_xprt *xprt)
  128. {
  129. struct msm_ipc_router_hsic_xprt *hsic_xprtp;
  130. if (!xprt)
  131. return -EINVAL;
  132. hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  133. return (int)hsic_xprtp->xprt_option;
  134. }
  135. /**
  136. * msm_ipc_router_hsic_remote_write_avail() - Get available write space
  137. * @xprt: XPRT for which the available write space info. is required.
  138. *
  139. * @return: Write space in bytes on success, 0 on SSR.
  140. */
  141. static int msm_ipc_router_hsic_remote_write_avail(
  142. struct msm_ipc_router_xprt *xprt)
  143. {
  144. struct ipc_bridge_platform_data *pdata;
  145. int write_avail;
  146. struct msm_ipc_router_hsic_xprt *hsic_xprtp =
  147. container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  148. mutex_lock(&hsic_xprtp->ss_reset_lock);
  149. if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
  150. write_avail = 0;
  151. } else {
  152. pdata = hsic_xprtp->pdev->dev.platform_data;
  153. write_avail = pdata->max_write_size;
  154. }
  155. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  156. return write_avail;
  157. }
  158. /**
  159. * msm_ipc_router_hsic_remote_write() - Write to XPRT
  160. * @data: Data to be written to the XPRT.
  161. * @len: Length of the data to be written.
  162. * @xprt: XPRT to which the data has to be written.
  163. *
  164. * @return: Data Length on success, standard Linux error codes on failure.
  165. */
  166. static int msm_ipc_router_hsic_remote_write(void *data,
  167. uint32_t len, struct msm_ipc_router_xprt *xprt)
  168. {
  169. struct rr_packet *pkt = (struct rr_packet *)data;
  170. struct sk_buff *skb;
  171. struct ipc_bridge_platform_data *pdata;
  172. struct msm_ipc_router_hsic_xprt *hsic_xprtp;
  173. int ret;
  174. if (!pkt || pkt->length != len || !xprt) {
  175. pr_err("%s: Invalid input parameters\n", __func__);
  176. return -EINVAL;
  177. }
  178. hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  179. mutex_lock(&hsic_xprtp->ss_reset_lock);
  180. if (hsic_xprtp->ss_reset) {
  181. pr_err("%s: Trying to write on a reset link\n", __func__);
  182. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  183. return -ENETRESET;
  184. }
  185. if (!hsic_xprtp->pdev) {
  186. pr_err("%s: Trying to write on a closed link\n", __func__);
  187. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  188. return -ENODEV;
  189. }
  190. pdata = hsic_xprtp->pdev->dev.platform_data;
  191. if (!pdata || !pdata->write) {
  192. pr_err("%s on a uninitialized link\n", __func__);
  193. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  194. return -EFAULT;
  195. }
  196. skb = skb_peek(pkt->pkt_fragment_q);
  197. if (!skb) {
  198. pr_err("%s SKB is NULL\n", __func__);
  199. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  200. return -EINVAL;
  201. }
  202. D("%s: About to write %d bytes\n", __func__, len);
  203. ret = pdata->write(hsic_xprtp->pdev, skb->data, skb->len);
  204. if (ret == skb->len)
  205. ret = len;
  206. D("%s: Finished writing %d bytes\n", __func__, len);
  207. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  208. return ret;
  209. }
  210. /**
  211. * msm_ipc_router_hsic_remote_close() - Close the XPRT
  212. * @xprt: XPRT which needs to be closed.
  213. *
  214. * @return: 0 on success, standard Linux error codes on failure.
  215. */
  216. static int msm_ipc_router_hsic_remote_close(
  217. struct msm_ipc_router_xprt *xprt)
  218. {
  219. struct msm_ipc_router_hsic_xprt *hsic_xprtp;
  220. struct ipc_bridge_platform_data *pdata;
  221. if (!xprt)
  222. return -EINVAL;
  223. hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  224. mutex_lock(&hsic_xprtp->ss_reset_lock);
  225. hsic_xprtp->ss_reset = 1;
  226. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  227. flush_workqueue(hsic_xprtp->hsic_xprt_wq);
  228. destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
  229. pdata = hsic_xprtp->pdev->dev.platform_data;
  230. if (pdata && pdata->close)
  231. pdata->close(hsic_xprtp->pdev);
  232. hsic_xprtp->pdev = NULL;
  233. return 0;
  234. }
  235. /**
  236. * hsic_xprt_read_data() - Read work to read from the XPRT
  237. * @work: Read work to be executed.
  238. *
  239. * This function is a read work item queued on a XPRT specific workqueue.
  240. * The work parameter contains information regarding the XPRT on which this
  241. * read work has to be performed. The work item keeps reading from the HSIC
  242. * endpoint, until the endpoint returns an error.
  243. */
  244. static void hsic_xprt_read_data(struct work_struct *work)
  245. {
  246. int pkt_size;
  247. struct sk_buff *skb = NULL;
  248. void *data;
  249. struct ipc_bridge_platform_data *pdata;
  250. struct delayed_work *rwork = to_delayed_work(work);
  251. struct msm_ipc_router_hsic_xprt *hsic_xprtp =
  252. container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
  253. while (1) {
  254. mutex_lock(&hsic_xprtp->ss_reset_lock);
  255. if (hsic_xprtp->ss_reset) {
  256. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  257. break;
  258. }
  259. pdata = hsic_xprtp->pdev->dev.platform_data;
  260. mutex_unlock(&hsic_xprtp->ss_reset_lock);
  261. while (!hsic_xprtp->in_pkt) {
  262. hsic_xprtp->in_pkt = kzalloc(sizeof(struct rr_packet),
  263. GFP_KERNEL);
  264. if (hsic_xprtp->in_pkt)
  265. break;
  266. pr_err("%s: packet allocation failure\n", __func__);
  267. msleep(100);
  268. }
  269. while (!hsic_xprtp->in_pkt->pkt_fragment_q) {
  270. hsic_xprtp->in_pkt->pkt_fragment_q =
  271. kmalloc(sizeof(struct sk_buff_head),
  272. GFP_KERNEL);
  273. if (hsic_xprtp->in_pkt->pkt_fragment_q)
  274. break;
  275. pr_err("%s: Couldn't alloc pkt_fragment_q\n",
  276. __func__);
  277. msleep(100);
  278. }
  279. skb_queue_head_init(hsic_xprtp->in_pkt->pkt_fragment_q);
  280. D("%s: Allocated rr_packet\n", __func__);
  281. while (!skb) {
  282. skb = alloc_skb(pdata->max_read_size, GFP_KERNEL);
  283. if (skb)
  284. break;
  285. pr_err("%s: Couldn't alloc SKB\n", __func__);
  286. msleep(100);
  287. }
  288. data = skb_put(skb, pdata->max_read_size);
  289. pkt_size = pdata->read(hsic_xprtp->pdev, data,
  290. pdata->max_read_size);
  291. if (pkt_size < 0) {
  292. pr_err("%s: Error %d @ read operation\n",
  293. __func__, pkt_size);
  294. kfree_skb(skb);
  295. kfree(hsic_xprtp->in_pkt->pkt_fragment_q);
  296. kfree(hsic_xprtp->in_pkt);
  297. break;
  298. }
  299. skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
  300. hsic_xprtp->in_pkt->length = pkt_size;
  301. D("%s: Packet size read %d\n", __func__, pkt_size);
  302. msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
  303. IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
  304. release_pkt(hsic_xprtp->in_pkt);
  305. hsic_xprtp->in_pkt = NULL;
  306. skb = NULL;
  307. }
  308. }
  309. /**
  310. * hsic_xprt_sft_close_done() - Completion of XPRT reset
  311. * @xprt: XPRT on which the reset operation is complete.
  312. *
  313. * This function is used by IPC Router to signal this HSIC XPRT Abstraction
  314. * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
  315. */
  316. static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
  317. {
  318. struct msm_ipc_router_hsic_xprt *hsic_xprtp =
  319. container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
  320. complete_all(&hsic_xprtp->sft_close_complete);
  321. }
  322. /**
  323. * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
  324. * @pdev: Platform device corresponding to HSIC endpoint.
  325. *
  326. * @return: 0 on success, standard Linux error codes on error.
  327. *
  328. * This function is called when the underlying ipc_bridge driver unregisters
  329. * a platform device, mapped to an HSIC endpoint, during SSR.
  330. */
  331. static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
  332. {
  333. int id;
  334. struct ipc_bridge_platform_data *pdata;
  335. id = find_hsic_xprt_cfg(pdev);
  336. if (id < 0) {
  337. pr_err("%s: called for unknown ch %s\n",
  338. __func__, pdev->name);
  339. return id;
  340. }
  341. mutex_lock(&hsic_remote_xprt[id].ss_reset_lock);
  342. hsic_remote_xprt[id].ss_reset = 1;
  343. mutex_unlock(&hsic_remote_xprt[id].ss_reset_lock);
  344. flush_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
  345. destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
  346. init_completion(&hsic_remote_xprt[id].sft_close_complete);
  347. msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
  348. IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
  349. D("%s: Notified IPC Router of %s CLOSE\n",
  350. __func__, hsic_remote_xprt[id].xprt.name);
  351. wait_for_completion(&hsic_remote_xprt[id].sft_close_complete);
  352. hsic_remote_xprt[id].pdev = NULL;
  353. pdata = pdev->dev.platform_data;
  354. if (pdata && pdata->close)
  355. pdata->close(pdev);
  356. return 0;
  357. }
  358. /**
  359. * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
  360. * @pdev: Platform device corresponding to HSIC endpoint.
  361. *
  362. * @return: 0 on success, standard Linux error codes on error.
  363. *
  364. * This function is called when the underlying ipc_bridge driver registers
  365. * a platform device, mapped to an HSIC endpoint.
  366. */
  367. static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
  368. {
  369. int rc;
  370. int id; /*Index into the hsic_xprt_cfg table*/
  371. struct ipc_bridge_platform_data *pdata;
  372. pdata = pdev->dev.platform_data;
  373. if (!pdata || !pdata->open || !pdata->read ||
  374. !pdata->write || !pdata->close) {
  375. pr_err("%s: pdata or pdata->operations is NULL\n", __func__);
  376. return -EINVAL;
  377. }
  378. id = find_hsic_xprt_cfg(pdev);
  379. if (id < 0) {
  380. pr_err("%s: called for unknown ch %s\n",
  381. __func__, pdev->name);
  382. return id;
  383. }
  384. hsic_remote_xprt[id].hsic_xprt_wq =
  385. create_singlethread_workqueue(pdev->name);
  386. if (!hsic_remote_xprt[id].hsic_xprt_wq) {
  387. pr_err("%s: WQ creation failed for %s\n",
  388. __func__, pdev->name);
  389. return -EFAULT;
  390. }
  391. hsic_remote_xprt[id].xprt.name = hsic_xprt_cfg[id].xprt_name;
  392. hsic_remote_xprt[id].xprt.link_id = hsic_xprt_cfg[id].link_id;
  393. hsic_remote_xprt[id].xprt.get_version =
  394. msm_ipc_router_hsic_get_xprt_version;
  395. hsic_remote_xprt[id].xprt.get_option =
  396. msm_ipc_router_hsic_get_xprt_option;
  397. hsic_remote_xprt[id].xprt.read_avail = NULL;
  398. hsic_remote_xprt[id].xprt.read = NULL;
  399. hsic_remote_xprt[id].xprt.write_avail =
  400. msm_ipc_router_hsic_remote_write_avail;
  401. hsic_remote_xprt[id].xprt.write = msm_ipc_router_hsic_remote_write;
  402. hsic_remote_xprt[id].xprt.close = msm_ipc_router_hsic_remote_close;
  403. hsic_remote_xprt[id].xprt.sft_close_done = hsic_xprt_sft_close_done;
  404. hsic_remote_xprt[id].xprt.priv = NULL;
  405. hsic_remote_xprt[id].in_pkt = NULL;
  406. INIT_DELAYED_WORK(&hsic_remote_xprt[id].read_work, hsic_xprt_read_data);
  407. mutex_init(&hsic_remote_xprt[id].ss_reset_lock);
  408. hsic_remote_xprt[id].ss_reset = 0;
  409. hsic_remote_xprt[id].xprt_version = hsic_xprt_cfg[id].xprt_version;
  410. hsic_remote_xprt[id].xprt_option = 0;
  411. rc = pdata->open(pdev);
  412. if (rc < 0) {
  413. pr_err("%s: Channel open failed for %s.%d\n",
  414. __func__, pdev->name, pdev->id);
  415. destroy_workqueue(hsic_remote_xprt[id].hsic_xprt_wq);
  416. return rc;
  417. }
  418. hsic_remote_xprt[id].pdev = pdev;
  419. msm_ipc_router_xprt_notify(&hsic_remote_xprt[id].xprt,
  420. IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
  421. D("%s: Notified IPC Router of %s OPEN\n",
  422. __func__, hsic_remote_xprt[id].xprt.name);
  423. queue_delayed_work(hsic_remote_xprt[id].hsic_xprt_wq,
  424. &hsic_remote_xprt[id].read_work, 0);
  425. return 0;
  426. }
  427. static struct platform_driver msm_ipc_router_hsic_remote_driver[] = {
  428. {
  429. .probe = msm_ipc_router_hsic_remote_probe,
  430. .remove = msm_ipc_router_hsic_remote_remove,
  431. .driver = {
  432. .name = "ipc_bridge",
  433. .owner = THIS_MODULE,
  434. },
  435. },
  436. };
  437. static int __init msm_ipc_router_hsic_init(void)
  438. {
  439. int i, ret, rc = 0;
  440. BUG_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS);
  441. for (i = 0; i < ARRAY_SIZE(msm_ipc_router_hsic_remote_driver); i++) {
  442. ret = platform_driver_register(
  443. &msm_ipc_router_hsic_remote_driver[i]);
  444. if (ret) {
  445. pr_err("%s: Failed to register platform driver for xprt%d. Continuing...\n",
  446. __func__, i);
  447. rc = ret;
  448. }
  449. }
  450. return rc;
  451. }
  452. module_init(msm_ipc_router_hsic_init);
  453. MODULE_DESCRIPTION("IPC Router HSIC XPRT");
  454. MODULE_LICENSE("GPL v2");