PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/net/wireless/ath/ath9k/htc_hst.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 478 lines | 365 code | 83 blank | 30 comment | 48 complexity | 74bc7d320129eef76fda59ee564f35a4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1. /*
  2. * Copyright (c) 2010-2011 Atheros Communications Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "htc.h"
  17. static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
  18. u16 len, u8 flags, u8 epid)
  19. {
  20. struct htc_frame_hdr *hdr;
  21. struct htc_endpoint *endpoint = &target->endpoint[epid];
  22. int status;
  23. hdr = (struct htc_frame_hdr *)
  24. skb_push(skb, sizeof(struct htc_frame_hdr));
  25. hdr->endpoint_id = epid;
  26. hdr->flags = flags;
  27. hdr->payload_len = cpu_to_be16(len);
  28. status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
  29. return status;
  30. }
  31. static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
  32. {
  33. enum htc_endpoint_id avail_epid;
  34. for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
  35. if (endpoint[avail_epid].service_id == 0)
  36. return &endpoint[avail_epid];
  37. return NULL;
  38. }
  39. static u8 service_to_ulpipe(u16 service_id)
  40. {
  41. switch (service_id) {
  42. case WMI_CONTROL_SVC:
  43. return 4;
  44. case WMI_BEACON_SVC:
  45. case WMI_CAB_SVC:
  46. case WMI_UAPSD_SVC:
  47. case WMI_MGMT_SVC:
  48. case WMI_DATA_VO_SVC:
  49. case WMI_DATA_VI_SVC:
  50. case WMI_DATA_BE_SVC:
  51. case WMI_DATA_BK_SVC:
  52. return 1;
  53. default:
  54. return 0;
  55. }
  56. }
  57. static u8 service_to_dlpipe(u16 service_id)
  58. {
  59. switch (service_id) {
  60. case WMI_CONTROL_SVC:
  61. return 3;
  62. case WMI_BEACON_SVC:
  63. case WMI_CAB_SVC:
  64. case WMI_UAPSD_SVC:
  65. case WMI_MGMT_SVC:
  66. case WMI_DATA_VO_SVC:
  67. case WMI_DATA_VI_SVC:
  68. case WMI_DATA_BE_SVC:
  69. case WMI_DATA_BK_SVC:
  70. return 2;
  71. default:
  72. return 0;
  73. }
  74. }
  75. static void htc_process_target_rdy(struct htc_target *target,
  76. void *buf)
  77. {
  78. struct htc_endpoint *endpoint;
  79. struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
  80. target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
  81. endpoint = &target->endpoint[ENDPOINT0];
  82. endpoint->service_id = HTC_CTRL_RSVD_SVC;
  83. endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
  84. atomic_inc(&target->tgt_ready);
  85. complete(&target->target_wait);
  86. }
  87. static void htc_process_conn_rsp(struct htc_target *target,
  88. struct htc_frame_hdr *htc_hdr)
  89. {
  90. struct htc_conn_svc_rspmsg *svc_rspmsg;
  91. struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
  92. u16 service_id;
  93. u16 max_msglen;
  94. enum htc_endpoint_id epid, tepid;
  95. svc_rspmsg = (struct htc_conn_svc_rspmsg *)
  96. ((void *) htc_hdr + sizeof(struct htc_frame_hdr));
  97. if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
  98. epid = svc_rspmsg->endpoint_id;
  99. service_id = be16_to_cpu(svc_rspmsg->service_id);
  100. max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
  101. endpoint = &target->endpoint[epid];
  102. for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
  103. tmp_endpoint = &target->endpoint[tepid];
  104. if (tmp_endpoint->service_id == service_id) {
  105. tmp_endpoint->service_id = 0;
  106. break;
  107. }
  108. }
  109. if (tepid == ENDPOINT0)
  110. return;
  111. endpoint->service_id = service_id;
  112. endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
  113. endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
  114. endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
  115. endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
  116. endpoint->max_msglen = max_msglen;
  117. target->conn_rsp_epid = epid;
  118. complete(&target->cmd_wait);
  119. } else {
  120. target->conn_rsp_epid = ENDPOINT_UNUSED;
  121. }
  122. }
  123. static int htc_config_pipe_credits(struct htc_target *target)
  124. {
  125. struct sk_buff *skb;
  126. struct htc_config_pipe_msg *cp_msg;
  127. int ret, time_left;
  128. skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
  129. if (!skb) {
  130. dev_err(target->dev, "failed to allocate send buffer\n");
  131. return -ENOMEM;
  132. }
  133. skb_reserve(skb, sizeof(struct htc_frame_hdr));
  134. cp_msg = (struct htc_config_pipe_msg *)
  135. skb_put(skb, sizeof(struct htc_config_pipe_msg));
  136. cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
  137. cp_msg->pipe_id = USB_WLAN_TX_PIPE;
  138. cp_msg->credits = target->credits;
  139. target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
  140. ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
  141. if (ret)
  142. goto err;
  143. time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
  144. if (!time_left) {
  145. dev_err(target->dev, "HTC credit config timeout\n");
  146. return -ETIMEDOUT;
  147. }
  148. return 0;
  149. err:
  150. kfree_skb(skb);
  151. return -EINVAL;
  152. }
  153. static int htc_setup_complete(struct htc_target *target)
  154. {
  155. struct sk_buff *skb;
  156. struct htc_comp_msg *comp_msg;
  157. int ret = 0, time_left;
  158. skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
  159. if (!skb) {
  160. dev_err(target->dev, "failed to allocate send buffer\n");
  161. return -ENOMEM;
  162. }
  163. skb_reserve(skb, sizeof(struct htc_frame_hdr));
  164. comp_msg = (struct htc_comp_msg *)
  165. skb_put(skb, sizeof(struct htc_comp_msg));
  166. comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
  167. target->htc_flags |= HTC_OP_START_WAIT;
  168. ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
  169. if (ret)
  170. goto err;
  171. time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
  172. if (!time_left) {
  173. dev_err(target->dev, "HTC start timeout\n");
  174. return -ETIMEDOUT;
  175. }
  176. return 0;
  177. err:
  178. kfree_skb(skb);
  179. return -EINVAL;
  180. }
  181. /* HTC APIs */
  182. int htc_init(struct htc_target *target)
  183. {
  184. int ret;
  185. ret = htc_config_pipe_credits(target);
  186. if (ret)
  187. return ret;
  188. return htc_setup_complete(target);
  189. }
  190. int htc_connect_service(struct htc_target *target,
  191. struct htc_service_connreq *service_connreq,
  192. enum htc_endpoint_id *conn_rsp_epid)
  193. {
  194. struct sk_buff *skb;
  195. struct htc_endpoint *endpoint;
  196. struct htc_conn_svc_msg *conn_msg;
  197. int ret, time_left;
  198. /* Find an available endpoint */
  199. endpoint = get_next_avail_ep(target->endpoint);
  200. if (!endpoint) {
  201. dev_err(target->dev, "Endpoint is not available for"
  202. "service %d\n", service_connreq->service_id);
  203. return -EINVAL;
  204. }
  205. endpoint->service_id = service_connreq->service_id;
  206. endpoint->max_txqdepth = service_connreq->max_send_qdepth;
  207. endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
  208. endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
  209. endpoint->ep_callbacks = service_connreq->ep_callbacks;
  210. skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
  211. sizeof(struct htc_frame_hdr), GFP_ATOMIC);
  212. if (!skb) {
  213. dev_err(target->dev, "Failed to allocate buf to send"
  214. "service connect req\n");
  215. return -ENOMEM;
  216. }
  217. skb_reserve(skb, sizeof(struct htc_frame_hdr));
  218. conn_msg = (struct htc_conn_svc_msg *)
  219. skb_put(skb, sizeof(struct htc_conn_svc_msg));
  220. conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
  221. conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
  222. conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
  223. conn_msg->dl_pipeid = endpoint->dl_pipeid;
  224. conn_msg->ul_pipeid = endpoint->ul_pipeid;
  225. ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
  226. if (ret)
  227. goto err;
  228. time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
  229. if (!time_left) {
  230. dev_err(target->dev, "Service connection timeout for: %d\n",
  231. service_connreq->service_id);
  232. return -ETIMEDOUT;
  233. }
  234. *conn_rsp_epid = target->conn_rsp_epid;
  235. return 0;
  236. err:
  237. kfree_skb(skb);
  238. return ret;
  239. }
  240. int htc_send(struct htc_target *target, struct sk_buff *skb)
  241. {
  242. struct ath9k_htc_tx_ctl *tx_ctl;
  243. tx_ctl = HTC_SKB_CB(skb);
  244. return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
  245. }
  246. int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
  247. enum htc_endpoint_id epid)
  248. {
  249. return htc_issue_send(target, skb, skb->len, 0, epid);
  250. }
  251. void htc_stop(struct htc_target *target)
  252. {
  253. target->hif->stop(target->hif_dev);
  254. }
  255. void htc_start(struct htc_target *target)
  256. {
  257. target->hif->start(target->hif_dev);
  258. }
  259. void htc_sta_drain(struct htc_target *target, u8 idx)
  260. {
  261. target->hif->sta_drain(target->hif_dev, idx);
  262. }
  263. void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
  264. struct sk_buff *skb, bool txok)
  265. {
  266. struct htc_endpoint *endpoint;
  267. struct htc_frame_hdr *htc_hdr = NULL;
  268. if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
  269. complete(&htc_handle->cmd_wait);
  270. htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
  271. goto ret;
  272. }
  273. if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
  274. complete(&htc_handle->cmd_wait);
  275. htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
  276. goto ret;
  277. }
  278. if (skb) {
  279. htc_hdr = (struct htc_frame_hdr *) skb->data;
  280. endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
  281. skb_pull(skb, sizeof(struct htc_frame_hdr));
  282. if (endpoint->ep_callbacks.tx) {
  283. endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
  284. skb, htc_hdr->endpoint_id,
  285. txok);
  286. }
  287. }
  288. return;
  289. ret:
  290. /* HTC-generated packets are freed here. */
  291. if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
  292. dev_kfree_skb_any(skb);
  293. else
  294. kfree_skb(skb);
  295. }
  296. /*
  297. * HTC Messages are handled directly here and the obtained SKB
  298. * is freed.
  299. *
  300. * Service messages (Data, WMI) passed to the corresponding
  301. * endpoint RX handlers, which have to free the SKB.
  302. */
  303. void ath9k_htc_rx_msg(struct htc_target *htc_handle,
  304. struct sk_buff *skb, u32 len, u8 pipe_id)
  305. {
  306. struct htc_frame_hdr *htc_hdr;
  307. enum htc_endpoint_id epid;
  308. struct htc_endpoint *endpoint;
  309. __be16 *msg_id;
  310. if (!htc_handle || !skb)
  311. return;
  312. htc_hdr = (struct htc_frame_hdr *) skb->data;
  313. epid = htc_hdr->endpoint_id;
  314. if (epid >= ENDPOINT_MAX) {
  315. if (pipe_id != USB_REG_IN_PIPE)
  316. dev_kfree_skb_any(skb);
  317. else
  318. kfree_skb(skb);
  319. return;
  320. }
  321. if (epid == ENDPOINT0) {
  322. /* Handle trailer */
  323. if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
  324. if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
  325. /* Move past the Watchdog pattern */
  326. htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
  327. }
  328. /* Get the message ID */
  329. msg_id = (__be16 *) ((void *) htc_hdr +
  330. sizeof(struct htc_frame_hdr));
  331. /* Now process HTC messages */
  332. switch (be16_to_cpu(*msg_id)) {
  333. case HTC_MSG_READY_ID:
  334. htc_process_target_rdy(htc_handle, htc_hdr);
  335. break;
  336. case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
  337. htc_process_conn_rsp(htc_handle, htc_hdr);
  338. break;
  339. default:
  340. break;
  341. }
  342. kfree_skb(skb);
  343. } else {
  344. if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
  345. skb_trim(skb, len - htc_hdr->control[0]);
  346. skb_pull(skb, sizeof(struct htc_frame_hdr));
  347. endpoint = &htc_handle->endpoint[epid];
  348. if (endpoint->ep_callbacks.rx)
  349. endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
  350. skb, epid);
  351. }
  352. }
  353. struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
  354. struct ath9k_htc_hif *hif,
  355. struct device *dev)
  356. {
  357. struct htc_endpoint *endpoint;
  358. struct htc_target *target;
  359. target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
  360. if (!target) {
  361. printk(KERN_ERR "Unable to allocate memory for"
  362. "target device\n");
  363. return NULL;
  364. }
  365. init_completion(&target->target_wait);
  366. init_completion(&target->cmd_wait);
  367. target->hif = hif;
  368. target->hif_dev = hif_handle;
  369. target->dev = dev;
  370. /* Assign control endpoint pipe IDs */
  371. endpoint = &target->endpoint[ENDPOINT0];
  372. endpoint->ul_pipeid = hif->control_ul_pipe;
  373. endpoint->dl_pipeid = hif->control_dl_pipe;
  374. atomic_set(&target->tgt_ready, 0);
  375. return target;
  376. }
  377. void ath9k_htc_hw_free(struct htc_target *htc)
  378. {
  379. kfree(htc);
  380. }
  381. int ath9k_htc_hw_init(struct htc_target *target,
  382. struct device *dev, u16 devid,
  383. char *product, u32 drv_info)
  384. {
  385. if (ath9k_htc_probe_device(target, dev, devid, product, drv_info)) {
  386. printk(KERN_ERR "Failed to initialize the device\n");
  387. return -ENODEV;
  388. }
  389. return 0;
  390. }
  391. void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
  392. {
  393. if (target)
  394. ath9k_htc_disconnect_device(target, hot_unplug);
  395. }