hif_rx.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac
  4. * (WSM) API.
  5. *
  6. * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  7. * Copyright (c) 2010, ST-Ericsson
  8. */
  9. #include <linux/skbuff.h>
  10. #include <linux/etherdevice.h>
  11. #include "hif_rx.h"
  12. #include "wfx.h"
  13. #include "scan.h"
  14. #include "bh.h"
  15. #include "sta.h"
  16. #include "data_rx.h"
  17. #include "hif_api_cmd.h"
  18. static int hif_generic_confirm(struct wfx_dev *wdev,
  19. const struct hif_msg *hif, const void *buf)
  20. {
  21. // All confirm messages start with status
  22. int status = le32_to_cpup((__le32 *)buf);
  23. int cmd = hif->id;
  24. int len = le16_to_cpu(hif->len) - 4; // drop header
  25. WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error");
  26. if (!wdev->hif_cmd.buf_send) {
  27. dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd);
  28. return -EINVAL;
  29. }
  30. if (cmd != wdev->hif_cmd.buf_send->id) {
  31. dev_warn(wdev->dev,
  32. "chip response mismatch request: 0x%.2x vs 0x%.2x\n",
  33. cmd, wdev->hif_cmd.buf_send->id);
  34. return -EINVAL;
  35. }
  36. if (wdev->hif_cmd.buf_recv) {
  37. if (wdev->hif_cmd.len_recv >= len && len > 0)
  38. memcpy(wdev->hif_cmd.buf_recv, buf, len);
  39. else
  40. status = -EIO;
  41. }
  42. wdev->hif_cmd.ret = status;
  43. complete(&wdev->hif_cmd.done);
  44. return status;
  45. }
  46. static int hif_tx_confirm(struct wfx_dev *wdev,
  47. const struct hif_msg *hif, const void *buf)
  48. {
  49. const struct hif_cnf_tx *body = buf;
  50. wfx_tx_confirm_cb(wdev, body);
  51. return 0;
  52. }
  53. static int hif_multi_tx_confirm(struct wfx_dev *wdev,
  54. const struct hif_msg *hif, const void *buf)
  55. {
  56. const struct hif_cnf_multi_transmit *body = buf;
  57. int i;
  58. WARN(body->num_tx_confs <= 0, "corrupted message");
  59. for (i = 0; i < body->num_tx_confs; i++)
  60. wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]);
  61. return 0;
  62. }
  63. static int hif_startup_indication(struct wfx_dev *wdev,
  64. const struct hif_msg *hif, const void *buf)
  65. {
  66. const struct hif_ind_startup *body = buf;
  67. if (body->status || body->firmware_type > 4) {
  68. dev_err(wdev->dev, "received invalid startup indication");
  69. return -EINVAL;
  70. }
  71. memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup));
  72. le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id);
  73. le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs);
  74. le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf);
  75. le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask);
  76. complete(&wdev->firmware_ready);
  77. return 0;
  78. }
  79. static int hif_wakeup_indication(struct wfx_dev *wdev,
  80. const struct hif_msg *hif, const void *buf)
  81. {
  82. if (!wdev->pdata.gpio_wakeup ||
  83. gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) {
  84. dev_warn(wdev->dev, "unexpected wake-up indication\n");
  85. return -EIO;
  86. }
  87. return 0;
  88. }
  89. static int hif_receive_indication(struct wfx_dev *wdev,
  90. const struct hif_msg *hif,
  91. const void *buf, struct sk_buff *skb)
  92. {
  93. struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
  94. const struct hif_ind_rx *body = buf;
  95. if (!wvif) {
  96. dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n",
  97. __func__, hif->interface);
  98. return -EIO;
  99. }
  100. skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx));
  101. wfx_rx_cb(wvif, body, skb);
  102. return 0;
  103. }
  104. static int hif_event_indication(struct wfx_dev *wdev,
  105. const struct hif_msg *hif, const void *buf)
  106. {
  107. struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
  108. const struct hif_ind_event *body = buf;
  109. int type = le32_to_cpu(body->event_id);
  110. if (!wvif) {
  111. dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
  112. return -EIO;
  113. }
  114. switch (type) {
  115. case HIF_EVENT_IND_RCPI_RSSI:
  116. wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi);
  117. break;
  118. case HIF_EVENT_IND_BSSLOST:
  119. schedule_delayed_work(&wvif->beacon_loss_work, 0);
  120. break;
  121. case HIF_EVENT_IND_BSSREGAINED:
  122. cancel_delayed_work(&wvif->beacon_loss_work);
  123. dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n");
  124. break;
  125. case HIF_EVENT_IND_PS_MODE_ERROR:
  126. dev_warn(wdev->dev, "error while processing power save request: %d\n",
  127. le32_to_cpu(body->event_data.ps_mode_error));
  128. break;
  129. default:
  130. dev_warn(wdev->dev, "unhandled event indication: %.2x\n",
  131. type);
  132. break;
  133. }
  134. return 0;
  135. }
  136. static int hif_pm_mode_complete_indication(struct wfx_dev *wdev,
  137. const struct hif_msg *hif,
  138. const void *buf)
  139. {
  140. struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
  141. if (!wvif) {
  142. dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
  143. return -EIO;
  144. }
  145. complete(&wvif->set_pm_mode_complete);
  146. return 0;
  147. }
  148. static int hif_scan_complete_indication(struct wfx_dev *wdev,
  149. const struct hif_msg *hif,
  150. const void *buf)
  151. {
  152. struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
  153. if (!wvif) {
  154. dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
  155. return -EIO;
  156. }
  157. wfx_scan_complete(wvif);
  158. return 0;
  159. }
  160. static int hif_join_complete_indication(struct wfx_dev *wdev,
  161. const struct hif_msg *hif,
  162. const void *buf)
  163. {
  164. struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface);
  165. if (!wvif) {
  166. dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
  167. return -EIO;
  168. }
  169. dev_warn(wdev->dev, "unattended JoinCompleteInd\n");
  170. return 0;
  171. }
  172. static int hif_suspend_resume_indication(struct wfx_dev *wdev,
  173. const struct hif_msg *hif,
  174. const void *buf)
  175. {
  176. const struct hif_ind_suspend_resume_tx *body = buf;
  177. struct wfx_vif *wvif;
  178. if (body->bc_mc_only) {
  179. wvif = wdev_to_wvif(wdev, hif->interface);
  180. if (!wvif) {
  181. dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
  182. return -EIO;
  183. }
  184. if (body->resume)
  185. wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE);
  186. else
  187. wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP);
  188. } else {
  189. WARN(body->peer_sta_set, "misunderstood indication");
  190. WARN(hif->interface != 2, "misunderstood indication");
  191. if (body->resume)
  192. wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE);
  193. else
  194. wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP);
  195. }
  196. return 0;
  197. }
  198. static int hif_generic_indication(struct wfx_dev *wdev,
  199. const struct hif_msg *hif, const void *buf)
  200. {
  201. const struct hif_ind_generic *body = buf;
  202. int type = le32_to_cpu(body->type);
  203. switch (type) {
  204. case HIF_GENERIC_INDICATION_TYPE_RAW:
  205. return 0;
  206. case HIF_GENERIC_INDICATION_TYPE_STRING:
  207. dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data);
  208. return 0;
  209. case HIF_GENERIC_INDICATION_TYPE_RX_STATS:
  210. mutex_lock(&wdev->rx_stats_lock);
  211. // Older firmware send a generic indication beside RxStats
  212. if (!wfx_api_older_than(wdev, 1, 4))
  213. dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n",
  214. body->data.rx_stats.current_temp);
  215. memcpy(&wdev->rx_stats, &body->data.rx_stats,
  216. sizeof(wdev->rx_stats));
  217. mutex_unlock(&wdev->rx_stats_lock);
  218. return 0;
  219. case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO:
  220. mutex_lock(&wdev->tx_power_loop_info_lock);
  221. memcpy(&wdev->tx_power_loop_info,
  222. &body->data.tx_power_loop_info,
  223. sizeof(wdev->tx_power_loop_info));
  224. mutex_unlock(&wdev->tx_power_loop_info_lock);
  225. return 0;
  226. default:
  227. dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n",
  228. type);
  229. return -EIO;
  230. }
  231. }
  232. static const struct {
  233. int val;
  234. const char *str;
  235. bool has_param;
  236. } hif_errors[] = {
  237. { HIF_ERROR_FIRMWARE_ROLLBACK,
  238. "rollback status" },
  239. { HIF_ERROR_FIRMWARE_DEBUG_ENABLED,
  240. "debug feature enabled" },
  241. { HIF_ERROR_PDS_PAYLOAD,
  242. "PDS version is not supported" },
  243. { HIF_ERROR_PDS_TESTFEATURE,
  244. "PDS ask for an unknown test mode" },
  245. { HIF_ERROR_OOR_VOLTAGE,
  246. "out-of-range power supply voltage", true },
  247. { HIF_ERROR_OOR_TEMPERATURE,
  248. "out-of-range temperature", true },
  249. { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE,
  250. "secure link does not expect request during key exchange" },
  251. { HIF_ERROR_SLK_SESSION_KEY,
  252. "secure link session key is invalid" },
  253. { HIF_ERROR_SLK_OVERFLOW,
  254. "secure link overflow" },
  255. { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE,
  256. "secure link messages list does not match message encryption" },
  257. { HIF_ERROR_SLK_UNCONFIGURED,
  258. "secure link not yet configured" },
  259. { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW,
  260. "bus clock is too slow (<1kHz)" },
  261. { HIF_ERROR_HIF_RX_DATA_TOO_LARGE,
  262. "HIF message too large" },
  263. // Following errors only exists in old firmware versions:
  264. { HIF_ERROR_HIF_TX_QUEUE_FULL,
  265. "HIF messages queue is full" },
  266. { HIF_ERROR_HIF_BUS,
  267. "HIF bus" },
  268. { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED,
  269. "secure link does not support multi-tx confirmations" },
  270. { HIF_ERROR_SLK_OUTDATED_SESSION_KEY,
  271. "secure link session key is outdated" },
  272. { HIF_ERROR_SLK_DECRYPTION,
  273. "secure link params (nonce or tag) mismatch" },
  274. };
  275. static int hif_error_indication(struct wfx_dev *wdev,
  276. const struct hif_msg *hif, const void *buf)
  277. {
  278. const struct hif_ind_error *body = buf;
  279. int type = le32_to_cpu(body->type);
  280. int param = (s8)body->data[0];
  281. int i;
  282. for (i = 0; i < ARRAY_SIZE(hif_errors); i++)
  283. if (type == hif_errors[i].val)
  284. break;
  285. if (i < ARRAY_SIZE(hif_errors))
  286. if (hif_errors[i].has_param)
  287. dev_err(wdev->dev, "asynchronous error: %s: %d\n",
  288. hif_errors[i].str, param);
  289. else
  290. dev_err(wdev->dev, "asynchronous error: %s\n",
  291. hif_errors[i].str);
  292. else
  293. dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type);
  294. print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
  295. 16, 1, hif, le16_to_cpu(hif->len), false);
  296. wdev->chip_frozen = true;
  297. return 0;
  298. };
  299. static int hif_exception_indication(struct wfx_dev *wdev,
  300. const struct hif_msg *hif, const void *buf)
  301. {
  302. const struct hif_ind_exception *body = buf;
  303. int type = le32_to_cpu(body->type);
  304. if (type == 4)
  305. dev_err(wdev->dev, "firmware assert %d\n",
  306. le32_to_cpup((__le32 *)body->data));
  307. else
  308. dev_err(wdev->dev, "firmware exception\n");
  309. print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET,
  310. 16, 1, hif, le16_to_cpu(hif->len), false);
  311. wdev->chip_frozen = true;
  312. return -1;
  313. }
  314. static const struct {
  315. int msg_id;
  316. int (*handler)(struct wfx_dev *wdev,
  317. const struct hif_msg *hif, const void *buf);
  318. } hif_handlers[] = {
  319. /* Confirmations */
  320. { HIF_CNF_ID_TX, hif_tx_confirm },
  321. { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm },
  322. /* Indications */
  323. { HIF_IND_ID_STARTUP, hif_startup_indication },
  324. { HIF_IND_ID_WAKEUP, hif_wakeup_indication },
  325. { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication },
  326. { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication },
  327. { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication },
  328. { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication },
  329. { HIF_IND_ID_EVENT, hif_event_indication },
  330. { HIF_IND_ID_GENERIC, hif_generic_indication },
  331. { HIF_IND_ID_ERROR, hif_error_indication },
  332. { HIF_IND_ID_EXCEPTION, hif_exception_indication },
  333. // FIXME: allocate skb_p from hif_receive_indication and make it generic
  334. //{ HIF_IND_ID_RX, hif_receive_indication },
  335. };
  336. void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb)
  337. {
  338. int i;
  339. const struct hif_msg *hif = (const struct hif_msg *)skb->data;
  340. int hif_id = hif->id;
  341. if (hif_id == HIF_IND_ID_RX) {
  342. // hif_receive_indication take care of skb lifetime
  343. hif_receive_indication(wdev, hif, hif->body, skb);
  344. return;
  345. }
  346. // Note: mutex_is_lock cause an implicit memory barrier that protect
  347. // buf_send
  348. if (mutex_is_locked(&wdev->hif_cmd.lock)
  349. && wdev->hif_cmd.buf_send
  350. && wdev->hif_cmd.buf_send->id == hif_id) {
  351. hif_generic_confirm(wdev, hif, hif->body);
  352. goto free;
  353. }
  354. for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) {
  355. if (hif_handlers[i].msg_id == hif_id) {
  356. if (hif_handlers[i].handler)
  357. hif_handlers[i].handler(wdev, hif, hif->body);
  358. goto free;
  359. }
  360. }
  361. if (hif_id & 0x80)
  362. dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n",
  363. hif_id);
  364. else
  365. dev_err(wdev->dev, "unexpected HIF confirmation: ID %02x\n",
  366. hif_id);
  367. free:
  368. dev_kfree_skb(skb);
  369. }