acx.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * This file is part of wl18xx
  4. *
  5. * Copyright (C) 2011 Texas Instruments Inc.
  6. */
  7. #include "../wlcore/cmd.h"
  8. #include "../wlcore/debug.h"
  9. #include "../wlcore/acx.h"
  10. #include "acx.h"
  11. #include "wl18xx.h"
  12. int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
  13. u32 sdio_blk_size, u32 extra_mem_blks,
  14. u32 len_field_size)
  15. {
  16. struct wl18xx_acx_host_config_bitmap *bitmap_conf;
  17. int ret;
  18. wl1271_debug(DEBUG_ACX, "acx cfg bitmap %d blk %d spare %d field %d",
  19. host_cfg_bitmap, sdio_blk_size, extra_mem_blks,
  20. len_field_size);
  21. bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
  22. if (!bitmap_conf) {
  23. ret = -ENOMEM;
  24. goto out;
  25. }
  26. bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
  27. bitmap_conf->host_sdio_block_size = cpu_to_le32(sdio_blk_size);
  28. bitmap_conf->extra_mem_blocks = cpu_to_le32(extra_mem_blks);
  29. bitmap_conf->length_field_size = cpu_to_le32(len_field_size);
  30. ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
  31. bitmap_conf, sizeof(*bitmap_conf));
  32. if (ret < 0) {
  33. wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
  34. goto out;
  35. }
  36. out:
  37. kfree(bitmap_conf);
  38. return ret;
  39. }
  40. int wl18xx_acx_set_checksum_state(struct wl1271 *wl)
  41. {
  42. struct wl18xx_acx_checksum_state *acx;
  43. int ret;
  44. wl1271_debug(DEBUG_ACX, "acx checksum state");
  45. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  46. if (!acx) {
  47. ret = -ENOMEM;
  48. goto out;
  49. }
  50. acx->checksum_state = CHECKSUM_OFFLOAD_ENABLED;
  51. ret = wl1271_cmd_configure(wl, ACX_CSUM_CONFIG, acx, sizeof(*acx));
  52. if (ret < 0) {
  53. wl1271_warning("failed to set Tx checksum state: %d", ret);
  54. goto out;
  55. }
  56. out:
  57. kfree(acx);
  58. return ret;
  59. }
  60. int wl18xx_acx_clear_statistics(struct wl1271 *wl)
  61. {
  62. struct wl18xx_acx_clear_statistics *acx;
  63. int ret = 0;
  64. wl1271_debug(DEBUG_ACX, "acx clear statistics");
  65. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  66. if (!acx) {
  67. ret = -ENOMEM;
  68. goto out;
  69. }
  70. ret = wl1271_cmd_configure(wl, ACX_CLEAR_STATISTICS, acx, sizeof(*acx));
  71. if (ret < 0) {
  72. wl1271_warning("failed to clear firmware statistics: %d", ret);
  73. goto out;
  74. }
  75. out:
  76. kfree(acx);
  77. return ret;
  78. }
  79. int wl18xx_acx_peer_ht_operation_mode(struct wl1271 *wl, u8 hlid, bool wide)
  80. {
  81. struct wlcore_peer_ht_operation_mode *acx;
  82. int ret;
  83. wl1271_debug(DEBUG_ACX, "acx peer ht operation mode hlid %d bw %d",
  84. hlid, wide);
  85. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  86. if (!acx) {
  87. ret = -ENOMEM;
  88. goto out;
  89. }
  90. acx->hlid = hlid;
  91. acx->bandwidth = wide ? WLCORE_BANDWIDTH_40MHZ : WLCORE_BANDWIDTH_20MHZ;
  92. ret = wl1271_cmd_configure(wl, ACX_PEER_HT_OPERATION_MODE_CFG, acx,
  93. sizeof(*acx));
  94. if (ret < 0) {
  95. wl1271_warning("acx peer ht operation mode failed: %d", ret);
  96. goto out;
  97. }
  98. out:
  99. kfree(acx);
  100. return ret;
  101. }
  102. /*
  103. * this command is basically the same as wl1271_acx_ht_capabilities,
  104. * with the addition of supported rates. they should be unified in
  105. * the next fw api change
  106. */
  107. int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
  108. struct ieee80211_sta_ht_cap *ht_cap,
  109. bool allow_ht_operation,
  110. u32 rate_set, u8 hlid)
  111. {
  112. struct wlcore_acx_peer_cap *acx;
  113. int ret = 0;
  114. u32 ht_capabilites = 0;
  115. wl1271_debug(DEBUG_ACX,
  116. "acx set cap ht_supp: %d ht_cap: %d rates: 0x%x",
  117. ht_cap->ht_supported, ht_cap->cap, rate_set);
  118. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  119. if (!acx) {
  120. ret = -ENOMEM;
  121. goto out;
  122. }
  123. if (allow_ht_operation && ht_cap->ht_supported) {
  124. /* no need to translate capabilities - use the spec values */
  125. ht_capabilites = ht_cap->cap;
  126. /*
  127. * this bit is not employed by the spec but only by FW to
  128. * indicate peer HT support
  129. */
  130. ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION;
  131. /* get data from A-MPDU parameters field */
  132. acx->ampdu_max_length = ht_cap->ampdu_factor;
  133. acx->ampdu_min_spacing = ht_cap->ampdu_density;
  134. }
  135. acx->hlid = hlid;
  136. acx->ht_capabilites = cpu_to_le32(ht_capabilites);
  137. acx->supported_rates = cpu_to_le32(rate_set);
  138. ret = wl1271_cmd_configure(wl, ACX_PEER_CAP, acx, sizeof(*acx));
  139. if (ret < 0) {
  140. wl1271_warning("acx ht capabilities setting failed: %d", ret);
  141. goto out;
  142. }
  143. out:
  144. kfree(acx);
  145. return ret;
  146. }
  147. /*
  148. * When the host is suspended, we don't want to get any fast-link/PSM
  149. * notifications
  150. */
  151. int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
  152. bool action)
  153. {
  154. struct wl18xx_acx_interrupt_notify *acx;
  155. int ret = 0;
  156. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  157. if (!acx) {
  158. ret = -ENOMEM;
  159. goto out;
  160. }
  161. acx->enable = action;
  162. ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
  163. if (ret < 0) {
  164. wl1271_warning("acx interrupt notify setting failed: %d", ret);
  165. goto out;
  166. }
  167. out:
  168. kfree(acx);
  169. return ret;
  170. }
  171. /*
  172. * When the host is suspended, we can configure the FW to disable RX BA
  173. * notifications.
  174. */
  175. int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
  176. {
  177. struct wl18xx_acx_rx_ba_filter *acx;
  178. int ret = 0;
  179. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  180. if (!acx) {
  181. ret = -ENOMEM;
  182. goto out;
  183. }
  184. acx->enable = (u32)action;
  185. ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
  186. if (ret < 0) {
  187. wl1271_warning("acx rx ba activity filter setting failed: %d",
  188. ret);
  189. goto out;
  190. }
  191. out:
  192. kfree(acx);
  193. return ret;
  194. }
  195. int wl18xx_acx_ap_sleep(struct wl1271 *wl)
  196. {
  197. struct wl18xx_priv *priv = wl->priv;
  198. struct acx_ap_sleep_cfg *acx;
  199. struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
  200. int ret;
  201. wl1271_debug(DEBUG_ACX, "acx config ap sleep");
  202. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  203. if (!acx) {
  204. ret = -ENOMEM;
  205. goto out;
  206. }
  207. acx->idle_duty_cycle = conf->idle_duty_cycle;
  208. acx->connected_duty_cycle = conf->connected_duty_cycle;
  209. acx->max_stations_thresh = conf->max_stations_thresh;
  210. acx->idle_conn_thresh = conf->idle_conn_thresh;
  211. ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
  212. if (ret < 0) {
  213. wl1271_warning("acx config ap-sleep failed: %d", ret);
  214. goto out;
  215. }
  216. out:
  217. kfree(acx);
  218. return ret;
  219. }
  220. int wl18xx_acx_dynamic_fw_traces(struct wl1271 *wl)
  221. {
  222. struct acx_dynamic_fw_traces_cfg *acx;
  223. int ret;
  224. wl1271_debug(DEBUG_ACX, "acx dynamic fw traces config %d",
  225. wl->dynamic_fw_traces);
  226. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  227. if (!acx) {
  228. ret = -ENOMEM;
  229. goto out;
  230. }
  231. acx->dynamic_fw_traces = cpu_to_le32(wl->dynamic_fw_traces);
  232. ret = wl1271_cmd_configure(wl, ACX_DYNAMIC_TRACES_CFG,
  233. acx, sizeof(*acx));
  234. if (ret < 0) {
  235. wl1271_warning("acx config dynamic fw traces failed: %d", ret);
  236. goto out;
  237. }
  238. out:
  239. kfree(acx);
  240. return ret;
  241. }
  242. int wl18xx_acx_time_sync_cfg(struct wl1271 *wl)
  243. {
  244. struct acx_time_sync_cfg *acx;
  245. int ret;
  246. wl1271_debug(DEBUG_ACX, "acx time sync cfg: mode %d, addr: %pM",
  247. wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC],
  248. wl->zone_master_mac_addr);
  249. acx = kzalloc(sizeof(*acx), GFP_KERNEL);
  250. if (!acx) {
  251. ret = -ENOMEM;
  252. goto out;
  253. }
  254. acx->sync_mode = wl->conf.sg.params[WL18XX_CONF_SG_TIME_SYNC];
  255. memcpy(acx->zone_mac_addr, wl->zone_master_mac_addr, ETH_ALEN);
  256. ret = wl1271_cmd_configure(wl, ACX_TIME_SYNC_CFG,
  257. acx, sizeof(*acx));
  258. if (ret < 0) {
  259. wl1271_warning("acx time sync cfg failed: %d", ret);
  260. goto out;
  261. }
  262. out:
  263. kfree(acx);
  264. return ret;
  265. }