hif_tx.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx
  4. * Split Mac (WSM) API.
  5. *
  6. * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
  7. * Copyright (c) 2010, ST-Ericsson
  8. */
  9. #include <linux/etherdevice.h>
  10. #include "hif_tx.h"
  11. #include "wfx.h"
  12. #include "bh.h"
  13. #include "hwio.h"
  14. #include "debug.h"
  15. #include "sta.h"
  16. void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd)
  17. {
  18. init_completion(&hif_cmd->ready);
  19. init_completion(&hif_cmd->done);
  20. mutex_init(&hif_cmd->lock);
  21. }
  22. static void wfx_fill_header(struct hif_msg *hif, int if_id,
  23. unsigned int cmd, size_t size)
  24. {
  25. if (if_id == -1)
  26. if_id = 2;
  27. WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd);
  28. WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size);
  29. WARN(if_id > 0x3, "invalid interface ID %d", if_id);
  30. hif->len = cpu_to_le16(size + 4);
  31. hif->id = cmd;
  32. hif->interface = if_id;
  33. }
  34. static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif)
  35. {
  36. *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL);
  37. if (*hif)
  38. return (*hif)->body;
  39. else
  40. return NULL;
  41. }
  42. int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request,
  43. void *reply, size_t reply_len, bool no_reply)
  44. {
  45. const char *mib_name = "";
  46. const char *mib_sep = "";
  47. int cmd = request->id;
  48. int vif = request->interface;
  49. int ret;
  50. // Do not wait for any reply if chip is frozen
  51. if (wdev->chip_frozen)
  52. return -ETIMEDOUT;
  53. mutex_lock(&wdev->hif_cmd.lock);
  54. WARN(wdev->hif_cmd.buf_send, "data locking error");
  55. // Note: call to complete() below has an implicit memory barrier that
  56. // hopefully protect buf_send
  57. wdev->hif_cmd.buf_send = request;
  58. wdev->hif_cmd.buf_recv = reply;
  59. wdev->hif_cmd.len_recv = reply_len;
  60. complete(&wdev->hif_cmd.ready);
  61. wfx_bh_request_tx(wdev);
  62. if (no_reply) {
  63. // Chip won't reply. Give enough time to the wq to send the
  64. // buffer.
  65. msleep(100);
  66. wdev->hif_cmd.buf_send = NULL;
  67. mutex_unlock(&wdev->hif_cmd.lock);
  68. return 0;
  69. }
  70. if (wdev->poll_irq)
  71. wfx_bh_poll_irq(wdev);
  72. ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ);
  73. if (!ret) {
  74. dev_err(wdev->dev, "chip is abnormally long to answer\n");
  75. reinit_completion(&wdev->hif_cmd.ready);
  76. ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ);
  77. }
  78. if (!ret) {
  79. dev_err(wdev->dev, "chip did not answer\n");
  80. wfx_pending_dump_old_frames(wdev, 3000);
  81. wdev->chip_frozen = true;
  82. reinit_completion(&wdev->hif_cmd.done);
  83. ret = -ETIMEDOUT;
  84. } else {
  85. ret = wdev->hif_cmd.ret;
  86. }
  87. wdev->hif_cmd.buf_send = NULL;
  88. mutex_unlock(&wdev->hif_cmd.lock);
  89. if (ret &&
  90. (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) {
  91. mib_name = get_mib_name(((u16 *)request)[2]);
  92. mib_sep = "/";
  93. }
  94. if (ret < 0)
  95. dev_err(wdev->dev,
  96. "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n",
  97. get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
  98. if (ret > 0)
  99. dev_warn(wdev->dev,
  100. "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n",
  101. get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret);
  102. return ret;
  103. }
  104. // This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any
  105. // request anymore. Obviously, only call this function during device unregister.
  106. int hif_shutdown(struct wfx_dev *wdev)
  107. {
  108. int ret;
  109. struct hif_msg *hif;
  110. wfx_alloc_hif(0, &hif);
  111. if (!hif)
  112. return -ENOMEM;
  113. wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0);
  114. ret = wfx_cmd_send(wdev, hif, NULL, 0, true);
  115. if (wdev->pdata.gpio_wakeup)
  116. gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
  117. else
  118. control_reg_write(wdev, 0);
  119. kfree(hif);
  120. return ret;
  121. }
  122. int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len)
  123. {
  124. int ret;
  125. size_t buf_len = sizeof(struct hif_req_configuration) + len;
  126. struct hif_msg *hif;
  127. struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif);
  128. if (!hif)
  129. return -ENOMEM;
  130. body->length = cpu_to_le16(len);
  131. memcpy(body->pds_data, conf, len);
  132. wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len);
  133. ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
  134. kfree(hif);
  135. return ret;
  136. }
  137. int hif_reset(struct wfx_vif *wvif, bool reset_stat)
  138. {
  139. int ret;
  140. struct hif_msg *hif;
  141. struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif);
  142. if (!hif)
  143. return -ENOMEM;
  144. body->reset_stat = reset_stat;
  145. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body));
  146. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  147. kfree(hif);
  148. return ret;
  149. }
  150. int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
  151. void *val, size_t val_len)
  152. {
  153. int ret;
  154. struct hif_msg *hif;
  155. int buf_len = sizeof(struct hif_cnf_read_mib) + val_len;
  156. struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif);
  157. struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL);
  158. if (!body || !reply) {
  159. ret = -ENOMEM;
  160. goto out;
  161. }
  162. body->mib_id = cpu_to_le16(mib_id);
  163. wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body));
  164. ret = wfx_cmd_send(wdev, hif, reply, buf_len, false);
  165. if (!ret && mib_id != le16_to_cpu(reply->mib_id)) {
  166. dev_warn(wdev->dev, "%s: confirmation mismatch request\n",
  167. __func__);
  168. ret = -EIO;
  169. }
  170. if (ret == -ENOMEM)
  171. dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n",
  172. get_mib_name(mib_id), val_len,
  173. le16_to_cpu(reply->length));
  174. if (!ret)
  175. memcpy(val, &reply->mib_data, le16_to_cpu(reply->length));
  176. else
  177. memset(val, 0xFF, val_len);
  178. out:
  179. kfree(hif);
  180. kfree(reply);
  181. return ret;
  182. }
  183. int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id,
  184. void *val, size_t val_len)
  185. {
  186. int ret;
  187. struct hif_msg *hif;
  188. int buf_len = sizeof(struct hif_req_write_mib) + val_len;
  189. struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif);
  190. if (!hif)
  191. return -ENOMEM;
  192. body->mib_id = cpu_to_le16(mib_id);
  193. body->length = cpu_to_le16(val_len);
  194. memcpy(&body->mib_data, val, val_len);
  195. wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len);
  196. ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
  197. kfree(hif);
  198. return ret;
  199. }
  200. int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req,
  201. int chan_start_idx, int chan_num, int *timeout)
  202. {
  203. int ret, i;
  204. struct hif_msg *hif;
  205. size_t buf_len =
  206. sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8);
  207. struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif);
  208. int tmo_chan_fg, tmo_chan_bg, tmo;
  209. WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params");
  210. WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params");
  211. if (!hif)
  212. return -ENOMEM;
  213. for (i = 0; i < req->n_ssids; i++) {
  214. memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid,
  215. IEEE80211_MAX_SSID_LEN);
  216. body->ssid_def[i].ssid_length =
  217. cpu_to_le32(req->ssids[i].ssid_len);
  218. }
  219. body->num_of_ssids = HIF_API_MAX_NB_SSIDS;
  220. body->maintain_current_bss = 1;
  221. body->disallow_ps = 1;
  222. body->tx_power_level =
  223. cpu_to_le32(req->channels[chan_start_idx]->max_power);
  224. body->num_of_channels = chan_num;
  225. for (i = 0; i < chan_num; i++)
  226. body->channel_list[i] =
  227. req->channels[i + chan_start_idx]->hw_value;
  228. if (req->no_cck)
  229. body->max_transmit_rate = API_RATE_INDEX_G_6MBPS;
  230. else
  231. body->max_transmit_rate = API_RATE_INDEX_B_1MBPS;
  232. if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) {
  233. body->min_channel_time = cpu_to_le32(50);
  234. body->max_channel_time = cpu_to_le32(150);
  235. } else {
  236. body->min_channel_time = cpu_to_le32(10);
  237. body->max_channel_time = cpu_to_le32(50);
  238. body->num_of_probe_requests = 2;
  239. body->probe_delay = 100;
  240. }
  241. tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU;
  242. tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay;
  243. tmo_chan_fg *= body->num_of_probe_requests;
  244. tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU;
  245. if (timeout)
  246. *timeout = usecs_to_jiffies(tmo);
  247. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len);
  248. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  249. kfree(hif);
  250. return ret;
  251. }
  252. int hif_stop_scan(struct wfx_vif *wvif)
  253. {
  254. int ret;
  255. struct hif_msg *hif;
  256. // body associated to HIF_REQ_ID_STOP_SCAN is empty
  257. wfx_alloc_hif(0, &hif);
  258. if (!hif)
  259. return -ENOMEM;
  260. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0);
  261. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  262. kfree(hif);
  263. return ret;
  264. }
  265. int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
  266. struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
  267. {
  268. int ret;
  269. struct hif_msg *hif;
  270. struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif);
  271. WARN_ON(!conf->beacon_int);
  272. WARN_ON(!conf->basic_rates);
  273. WARN_ON(sizeof(body->ssid) < ssidlen);
  274. WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS");
  275. if (WARN_ON(!channel))
  276. return -EINVAL;
  277. if (!hif)
  278. return -ENOMEM;
  279. body->infrastructure_bss_mode = !conf->ibss_joined;
  280. body->short_preamble = conf->use_short_preamble;
  281. if (channel->flags & IEEE80211_CHAN_NO_IR)
  282. body->probe_for_join = 0;
  283. else
  284. body->probe_for_join = 1;
  285. body->channel_number = channel->hw_value;
  286. body->beacon_interval = cpu_to_le32(conf->beacon_int);
  287. body->basic_rate_set =
  288. cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
  289. memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
  290. if (ssid) {
  291. body->ssid_length = cpu_to_le32(ssidlen);
  292. memcpy(body->ssid, ssid, ssidlen);
  293. }
  294. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
  295. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  296. kfree(hif);
  297. return ret;
  298. }
  299. int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count)
  300. {
  301. int ret;
  302. struct hif_msg *hif;
  303. struct hif_req_set_bss_params *body =
  304. wfx_alloc_hif(sizeof(*body), &hif);
  305. if (!hif)
  306. return -ENOMEM;
  307. body->aid = cpu_to_le16(aid);
  308. body->beacon_lost_count = beacon_lost_count;
  309. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS,
  310. sizeof(*body));
  311. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  312. kfree(hif);
  313. return ret;
  314. }
  315. int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg)
  316. {
  317. int ret;
  318. struct hif_msg *hif;
  319. // FIXME: only send necessary bits
  320. struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif);
  321. if (!hif)
  322. return -ENOMEM;
  323. // FIXME: swap bytes as necessary in body
  324. memcpy(body, arg, sizeof(*body));
  325. if (wfx_api_older_than(wdev, 1, 5))
  326. // Legacy firmwares expect that add_key to be sent on right
  327. // interface.
  328. wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY,
  329. sizeof(*body));
  330. else
  331. wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body));
  332. ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
  333. kfree(hif);
  334. return ret;
  335. }
  336. int hif_remove_key(struct wfx_dev *wdev, int idx)
  337. {
  338. int ret;
  339. struct hif_msg *hif;
  340. struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif);
  341. if (!hif)
  342. return -ENOMEM;
  343. body->entry_index = idx;
  344. wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body));
  345. ret = wfx_cmd_send(wdev, hif, NULL, 0, false);
  346. kfree(hif);
  347. return ret;
  348. }
  349. int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue,
  350. const struct ieee80211_tx_queue_params *arg)
  351. {
  352. int ret;
  353. struct hif_msg *hif;
  354. struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body),
  355. &hif);
  356. if (!body)
  357. return -ENOMEM;
  358. WARN_ON(arg->aifs > 255);
  359. if (!hif)
  360. return -ENOMEM;
  361. body->aifsn = arg->aifs;
  362. body->cw_min = cpu_to_le16(arg->cw_min);
  363. body->cw_max = cpu_to_le16(arg->cw_max);
  364. body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP);
  365. body->queue_id = 3 - queue;
  366. // API 2.0 has changed queue IDs values
  367. if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE)
  368. body->queue_id = HIF_QUEUE_ID_BACKGROUND;
  369. if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK)
  370. body->queue_id = HIF_QUEUE_ID_BESTEFFORT;
  371. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS,
  372. sizeof(*body));
  373. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  374. kfree(hif);
  375. return ret;
  376. }
  377. int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout)
  378. {
  379. int ret;
  380. struct hif_msg *hif;
  381. struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif);
  382. if (!body)
  383. return -ENOMEM;
  384. if (!hif)
  385. return -ENOMEM;
  386. if (ps) {
  387. body->enter_psm = 1;
  388. // Firmware does not support more than 128ms
  389. body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255);
  390. if (body->fast_psm_idle_period)
  391. body->fast_psm = 1;
  392. }
  393. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body));
  394. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  395. kfree(hif);
  396. return ret;
  397. }
  398. int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
  399. const struct ieee80211_channel *channel)
  400. {
  401. int ret;
  402. struct hif_msg *hif;
  403. struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
  404. WARN_ON(!conf->beacon_int);
  405. if (!hif)
  406. return -ENOMEM;
  407. body->dtim_period = conf->dtim_period;
  408. body->short_preamble = conf->use_short_preamble;
  409. body->channel_number = channel->hw_value;
  410. body->beacon_interval = cpu_to_le32(conf->beacon_int);
  411. body->basic_rate_set =
  412. cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
  413. body->ssid_length = conf->ssid_len;
  414. memcpy(body->ssid, conf->ssid, conf->ssid_len);
  415. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body));
  416. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  417. kfree(hif);
  418. return ret;
  419. }
  420. int hif_beacon_transmit(struct wfx_vif *wvif, bool enable)
  421. {
  422. int ret;
  423. struct hif_msg *hif;
  424. struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body),
  425. &hif);
  426. if (!hif)
  427. return -ENOMEM;
  428. body->enable_beaconing = enable ? 1 : 0;
  429. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT,
  430. sizeof(*body));
  431. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  432. kfree(hif);
  433. return ret;
  434. }
  435. int hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp)
  436. {
  437. int ret;
  438. struct hif_msg *hif;
  439. struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif);
  440. if (!hif)
  441. return -ENOMEM;
  442. if (mac_addr)
  443. ether_addr_copy(body->mac_addr, mac_addr);
  444. body->mfpc = mfp ? 1 : 0;
  445. body->unmap = unmap ? 1 : 0;
  446. body->peer_sta_id = sta_id;
  447. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body));
  448. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  449. kfree(hif);
  450. return ret;
  451. }
  452. int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len)
  453. {
  454. int ret;
  455. struct hif_msg *hif;
  456. int buf_len = sizeof(struct hif_req_update_ie) + ies_len;
  457. struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif);
  458. if (!hif)
  459. return -ENOMEM;
  460. body->beacon = 1;
  461. body->num_ies = cpu_to_le16(1);
  462. memcpy(body->ie, ies, ies_len);
  463. wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len);
  464. ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
  465. kfree(hif);
  466. return ret;
  467. }