wmi_unified_ocb_tlv.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. /*
  2. * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for
  5. * any purpose with or without fee is hereby granted, provided that the
  6. * above copyright notice and this permission notice appear in all
  7. * copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  10. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  11. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  12. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  14. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  16. * PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include <osdep.h>
  19. #include <wmi.h>
  20. #include <wmi_unified_priv.h>
  21. #include <wlan_ocb_public_structs.h>
  22. #include <wmi_unified_ocb_api.h>
  23. /**
  24. * send_ocb_set_utc_time_cmd() - send the UTC time to the firmware
  25. * @wmi_handle: pointer to the wmi handle
  26. * @utc: pointer to the UTC time struct
  27. *
  28. * Return: 0 on succes
  29. */
  30. static QDF_STATUS send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle,
  31. struct ocb_utc_param *utc)
  32. {
  33. QDF_STATUS ret;
  34. wmi_ocb_set_utc_time_cmd_fixed_param *cmd;
  35. uint8_t *buf_ptr;
  36. uint32_t len, i;
  37. wmi_buf_t buf;
  38. len = sizeof(*cmd);
  39. buf = wmi_buf_alloc(wmi_handle, len);
  40. if (!buf) {
  41. return QDF_STATUS_E_NOMEM;
  42. }
  43. buf_ptr = (uint8_t *)wmi_buf_data(buf);
  44. cmd = (wmi_ocb_set_utc_time_cmd_fixed_param *)buf_ptr;
  45. WMITLV_SET_HDR(&cmd->tlv_header,
  46. WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param,
  47. WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_utc_time_cmd_fixed_param));
  48. cmd->vdev_id = utc->vdev_id;
  49. for (i = 0; i < SIZE_UTC_TIME; i++)
  50. WMI_UTC_TIME_SET(cmd, i, utc->utc_time[i]);
  51. for (i = 0; i < SIZE_UTC_TIME_ERROR; i++)
  52. WMI_TIME_ERROR_SET(cmd, i, utc->time_error[i]);
  53. wmi_mtrace(WMI_OCB_SET_UTC_TIME_CMDID, cmd->vdev_id, 0);
  54. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  55. WMI_OCB_SET_UTC_TIME_CMDID);
  56. if (QDF_IS_STATUS_ERROR(ret)) {
  57. WMI_LOGE(FL("Failed to set OCB UTC time"));
  58. wmi_buf_free(buf);
  59. }
  60. return ret;
  61. }
  62. /**
  63. * send_ocb_start_timing_advert_cmd_tlv() - start sending the timing advertisement
  64. * frames on a channel
  65. * @wmi_handle: pointer to the wmi handle
  66. * @timing_advert: pointer to the timing advertisement struct
  67. *
  68. * Return: 0 on succes
  69. */
  70. static QDF_STATUS send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
  71. struct ocb_timing_advert_param *timing_advert)
  72. {
  73. QDF_STATUS ret;
  74. wmi_ocb_start_timing_advert_cmd_fixed_param *cmd;
  75. uint8_t *buf_ptr;
  76. uint32_t len, len_template;
  77. wmi_buf_t buf;
  78. len = sizeof(*cmd) +
  79. WMI_TLV_HDR_SIZE;
  80. len_template = timing_advert->template_length;
  81. /* Add padding to the template if needed */
  82. if (len_template % 4 != 0)
  83. len_template += 4 - (len_template % 4);
  84. len += len_template;
  85. buf = wmi_buf_alloc(wmi_handle, len);
  86. if (!buf) {
  87. return QDF_STATUS_E_NOMEM;
  88. }
  89. buf_ptr = (uint8_t *)wmi_buf_data(buf);
  90. cmd = (wmi_ocb_start_timing_advert_cmd_fixed_param *)buf_ptr;
  91. WMITLV_SET_HDR(&cmd->tlv_header,
  92. WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param,
  93. WMITLV_GET_STRUCT_TLVLEN(
  94. wmi_ocb_start_timing_advert_cmd_fixed_param));
  95. cmd->vdev_id = timing_advert->vdev_id;
  96. cmd->repeat_rate = timing_advert->repeat_rate;
  97. cmd->channel_freq = timing_advert->chan_freq;
  98. cmd->timestamp_offset = timing_advert->timestamp_offset;
  99. cmd->time_value_offset = timing_advert->time_value_offset;
  100. cmd->timing_advert_template_length = timing_advert->template_length;
  101. buf_ptr += sizeof(*cmd);
  102. /* Add the timing advert template */
  103. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE,
  104. len_template);
  105. qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE,
  106. (uint8_t *)timing_advert->template_value,
  107. timing_advert->template_length);
  108. wmi_mtrace(WMI_OCB_START_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
  109. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  110. WMI_OCB_START_TIMING_ADVERT_CMDID);
  111. if (QDF_IS_STATUS_ERROR(ret)) {
  112. WMI_LOGE(FL("Failed to start OCB timing advert"));
  113. wmi_buf_free(buf);
  114. }
  115. return ret;
  116. }
  117. /**
  118. * send_ocb_stop_timing_advert_cmd_tlv() - stop sending the timing advertisement frames
  119. * on a channel
  120. * @wmi_handle: pointer to the wmi handle
  121. * @timing_advert: pointer to the timing advertisement struct
  122. *
  123. * Return: 0 on succes
  124. */
  125. static QDF_STATUS send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle,
  126. struct ocb_timing_advert_param *timing_advert)
  127. {
  128. QDF_STATUS ret;
  129. wmi_ocb_stop_timing_advert_cmd_fixed_param *cmd;
  130. uint8_t *buf_ptr;
  131. uint32_t len;
  132. wmi_buf_t buf;
  133. len = sizeof(*cmd);
  134. buf = wmi_buf_alloc(wmi_handle, len);
  135. if (!buf) {
  136. return QDF_STATUS_E_NOMEM;
  137. }
  138. buf_ptr = (uint8_t *)wmi_buf_data(buf);
  139. cmd = (wmi_ocb_stop_timing_advert_cmd_fixed_param *)buf_ptr;
  140. WMITLV_SET_HDR(&cmd->tlv_header,
  141. WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param,
  142. WMITLV_GET_STRUCT_TLVLEN(
  143. wmi_ocb_stop_timing_advert_cmd_fixed_param));
  144. cmd->vdev_id = timing_advert->vdev_id;
  145. cmd->channel_freq = timing_advert->chan_freq;
  146. wmi_mtrace(WMI_OCB_STOP_TIMING_ADVERT_CMDID, cmd->vdev_id, 0);
  147. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  148. WMI_OCB_STOP_TIMING_ADVERT_CMDID);
  149. if (QDF_IS_STATUS_ERROR(ret)) {
  150. WMI_LOGE(FL("Failed to stop OCB timing advert"));
  151. wmi_buf_free(buf);
  152. }
  153. return ret;
  154. }
  155. /**
  156. * send_ocb_get_tsf_timer_cmd_tlv() - get ocb tsf timer val
  157. * @wmi_handle: pointer to the wmi handle
  158. * @request: pointer to the request
  159. *
  160. * Return: 0 on succes
  161. */
  162. static QDF_STATUS send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle,
  163. uint8_t vdev_id)
  164. {
  165. QDF_STATUS ret;
  166. wmi_ocb_get_tsf_timer_cmd_fixed_param *cmd;
  167. uint8_t *buf_ptr;
  168. wmi_buf_t buf;
  169. int32_t len;
  170. len = sizeof(*cmd);
  171. buf = wmi_buf_alloc(wmi_handle, len);
  172. if (!buf) {
  173. return QDF_STATUS_E_NOMEM;
  174. }
  175. buf_ptr = (uint8_t *)wmi_buf_data(buf);
  176. cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr;
  177. qdf_mem_zero(cmd, len);
  178. WMITLV_SET_HDR(&cmd->tlv_header,
  179. WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param,
  180. WMITLV_GET_STRUCT_TLVLEN(
  181. wmi_ocb_get_tsf_timer_cmd_fixed_param));
  182. cmd->vdev_id = vdev_id;
  183. /* Send the WMI command */
  184. wmi_mtrace(WMI_OCB_GET_TSF_TIMER_CMDID, cmd->vdev_id, 0);
  185. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  186. WMI_OCB_GET_TSF_TIMER_CMDID);
  187. /* If there is an error, set the completion event */
  188. if (QDF_IS_STATUS_ERROR(ret)) {
  189. WMI_LOGE(FL("Failed to send WMI message: %d"), ret);
  190. wmi_buf_free(buf);
  191. }
  192. return ret;
  193. }
  194. /**
  195. * send_dcc_get_stats_cmd_tlv() - get the DCC channel stats
  196. * @wmi_handle: pointer to the wmi handle
  197. * @get_stats_param: pointer to the dcc stats
  198. *
  199. * Return: 0 on succes
  200. */
  201. static QDF_STATUS send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle,
  202. struct ocb_dcc_get_stats_param *get_stats_param)
  203. {
  204. QDF_STATUS ret;
  205. wmi_dcc_get_stats_cmd_fixed_param *cmd;
  206. wmi_dcc_channel_stats_request *channel_stats_array;
  207. wmi_buf_t buf;
  208. uint8_t *buf_ptr;
  209. uint32_t len;
  210. uint32_t i;
  211. /* Validate the input */
  212. if (get_stats_param->request_array_len !=
  213. get_stats_param->channel_count * sizeof(*channel_stats_array)) {
  214. WMI_LOGE(FL("Invalid parameter"));
  215. return QDF_STATUS_E_INVAL;
  216. }
  217. /* Allocate memory for the WMI command */
  218. len = sizeof(*cmd) + WMI_TLV_HDR_SIZE +
  219. get_stats_param->request_array_len;
  220. buf = wmi_buf_alloc(wmi_handle, len);
  221. if (!buf) {
  222. return QDF_STATUS_E_NOMEM;
  223. }
  224. buf_ptr = wmi_buf_data(buf);
  225. qdf_mem_zero(buf_ptr, len);
  226. /* Populate the WMI command */
  227. cmd = (wmi_dcc_get_stats_cmd_fixed_param *)buf_ptr;
  228. buf_ptr += sizeof(*cmd);
  229. WMITLV_SET_HDR(&cmd->tlv_header,
  230. WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param,
  231. WMITLV_GET_STRUCT_TLVLEN(
  232. wmi_dcc_get_stats_cmd_fixed_param));
  233. cmd->vdev_id = get_stats_param->vdev_id;
  234. cmd->num_channels = get_stats_param->channel_count;
  235. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  236. get_stats_param->request_array_len);
  237. buf_ptr += WMI_TLV_HDR_SIZE;
  238. channel_stats_array = (wmi_dcc_channel_stats_request *)buf_ptr;
  239. qdf_mem_copy(channel_stats_array, get_stats_param->request_array,
  240. get_stats_param->request_array_len);
  241. for (i = 0; i < cmd->num_channels; i++)
  242. WMITLV_SET_HDR(&channel_stats_array[i].tlv_header,
  243. WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request,
  244. WMITLV_GET_STRUCT_TLVLEN(
  245. wmi_dcc_channel_stats_request));
  246. /* Send the WMI command */
  247. wmi_mtrace(WMI_DCC_GET_STATS_CMDID, cmd->vdev_id, 0);
  248. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  249. WMI_DCC_GET_STATS_CMDID);
  250. if (QDF_IS_STATUS_ERROR(ret)) {
  251. WMI_LOGE(FL("Failed to send WMI message: %d"), ret);
  252. wmi_buf_free(buf);
  253. }
  254. return ret;
  255. }
  256. /**
  257. * send_dcc_clear_stats_cmd_tlv() - command to clear the DCC stats
  258. * @wmi_handle: pointer to the wmi handle
  259. * @vdev_id: vdev id
  260. * @dcc_stats_bitmap: dcc status bitmap
  261. *
  262. * Return: 0 on succes
  263. */
  264. static QDF_STATUS send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle,
  265. uint32_t vdev_id, uint32_t dcc_stats_bitmap)
  266. {
  267. QDF_STATUS ret;
  268. wmi_dcc_clear_stats_cmd_fixed_param *cmd;
  269. wmi_buf_t buf;
  270. uint8_t *buf_ptr;
  271. uint32_t len;
  272. /* Allocate memory for the WMI command */
  273. len = sizeof(*cmd);
  274. buf = wmi_buf_alloc(wmi_handle, len);
  275. if (!buf) {
  276. return QDF_STATUS_E_NOMEM;
  277. }
  278. buf_ptr = wmi_buf_data(buf);
  279. qdf_mem_zero(buf_ptr, len);
  280. /* Populate the WMI command */
  281. cmd = (wmi_dcc_clear_stats_cmd_fixed_param *)buf_ptr;
  282. WMITLV_SET_HDR(&cmd->tlv_header,
  283. WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param,
  284. WMITLV_GET_STRUCT_TLVLEN(
  285. wmi_dcc_clear_stats_cmd_fixed_param));
  286. cmd->vdev_id = vdev_id;
  287. cmd->dcc_stats_bitmap = dcc_stats_bitmap;
  288. /* Send the WMI command */
  289. wmi_mtrace(WMI_DCC_CLEAR_STATS_CMDID, cmd->vdev_id, 0);
  290. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  291. WMI_DCC_CLEAR_STATS_CMDID);
  292. if (QDF_IS_STATUS_ERROR(ret)) {
  293. WMI_LOGE(FL("Failed to send the WMI command"));
  294. wmi_buf_free(buf);
  295. }
  296. return ret;
  297. }
  298. /**
  299. * send_dcc_update_ndl_cmd_tlv() - command to update the NDL data
  300. * @wmi_handle: pointer to the wmi handle
  301. * @update_ndl_param: pointer to the request parameters
  302. *
  303. * Return: 0 on success
  304. */
  305. static QDF_STATUS send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle,
  306. struct ocb_dcc_update_ndl_param *update_ndl_param)
  307. {
  308. QDF_STATUS qdf_status;
  309. wmi_dcc_update_ndl_cmd_fixed_param *cmd;
  310. wmi_dcc_ndl_chan *ndl_chan_array;
  311. wmi_dcc_ndl_active_state_config *ndl_active_state_array;
  312. uint32_t active_state_count;
  313. wmi_buf_t buf;
  314. uint8_t *buf_ptr;
  315. uint32_t len;
  316. uint32_t i;
  317. /* validate the input */
  318. if (update_ndl_param->dcc_ndl_chan_list_len !=
  319. update_ndl_param->channel_count * sizeof(*ndl_chan_array)) {
  320. WMI_LOGE(FL("Invalid parameter"));
  321. return QDF_STATUS_E_INVAL;
  322. }
  323. active_state_count = 0;
  324. ndl_chan_array = update_ndl_param->dcc_ndl_chan_list;
  325. for (i = 0; i < update_ndl_param->channel_count; i++)
  326. active_state_count +=
  327. WMI_NDL_NUM_ACTIVE_STATE_GET(&ndl_chan_array[i]);
  328. if (update_ndl_param->dcc_ndl_active_state_list_len !=
  329. active_state_count * sizeof(*ndl_active_state_array)) {
  330. WMI_LOGE(FL("Invalid parameter"));
  331. return QDF_STATUS_E_INVAL;
  332. }
  333. /* Allocate memory for the WMI command */
  334. len = sizeof(*cmd) +
  335. WMI_TLV_HDR_SIZE + update_ndl_param->dcc_ndl_chan_list_len +
  336. WMI_TLV_HDR_SIZE +
  337. update_ndl_param->dcc_ndl_active_state_list_len;
  338. buf = wmi_buf_alloc(wmi_handle, len);
  339. if (!buf) {
  340. return QDF_STATUS_E_NOMEM;
  341. }
  342. buf_ptr = wmi_buf_data(buf);
  343. qdf_mem_zero(buf_ptr, len);
  344. /* Populate the WMI command */
  345. cmd = (wmi_dcc_update_ndl_cmd_fixed_param *)buf_ptr;
  346. buf_ptr += sizeof(*cmd);
  347. WMITLV_SET_HDR(&cmd->tlv_header,
  348. WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param,
  349. WMITLV_GET_STRUCT_TLVLEN(
  350. wmi_dcc_update_ndl_cmd_fixed_param));
  351. cmd->vdev_id = update_ndl_param->vdev_id;
  352. cmd->num_channel = update_ndl_param->channel_count;
  353. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  354. update_ndl_param->dcc_ndl_chan_list_len);
  355. buf_ptr += WMI_TLV_HDR_SIZE;
  356. ndl_chan_array = (wmi_dcc_ndl_chan *)buf_ptr;
  357. qdf_mem_copy(ndl_chan_array, update_ndl_param->dcc_ndl_chan_list,
  358. update_ndl_param->dcc_ndl_chan_list_len);
  359. for (i = 0; i < cmd->num_channel; i++)
  360. WMITLV_SET_HDR(&ndl_chan_array[i].tlv_header,
  361. WMITLV_TAG_STRUC_wmi_dcc_ndl_chan,
  362. WMITLV_GET_STRUCT_TLVLEN(
  363. wmi_dcc_ndl_chan));
  364. buf_ptr += update_ndl_param->dcc_ndl_chan_list_len;
  365. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  366. update_ndl_param->dcc_ndl_active_state_list_len);
  367. buf_ptr += WMI_TLV_HDR_SIZE;
  368. ndl_active_state_array = (wmi_dcc_ndl_active_state_config *)buf_ptr;
  369. qdf_mem_copy(ndl_active_state_array,
  370. update_ndl_param->dcc_ndl_active_state_list,
  371. update_ndl_param->dcc_ndl_active_state_list_len);
  372. for (i = 0; i < active_state_count; i++) {
  373. WMITLV_SET_HDR(&ndl_active_state_array[i].tlv_header,
  374. WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config,
  375. WMITLV_GET_STRUCT_TLVLEN(
  376. wmi_dcc_ndl_active_state_config));
  377. }
  378. buf_ptr += update_ndl_param->dcc_ndl_active_state_list_len;
  379. /* Send the WMI command */
  380. wmi_mtrace(WMI_DCC_UPDATE_NDL_CMDID, cmd->vdev_id, 0);
  381. qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len,
  382. WMI_DCC_UPDATE_NDL_CMDID);
  383. /* If there is an error, set the completion event */
  384. if (QDF_IS_STATUS_ERROR(qdf_status)) {
  385. WMI_LOGE(FL("Failed to send WMI message: %d"), qdf_status);
  386. wmi_buf_free(buf);
  387. }
  388. return qdf_status;
  389. }
  390. /**
  391. * send_ocb_set_config_cmd_tlv() - send the OCB config to the FW
  392. * @wmi_handle: pointer to the wmi handle
  393. * @config: the OCB configuration
  394. *
  395. * Return: 0 on success
  396. */
  397. static QDF_STATUS send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle,
  398. struct ocb_config *config)
  399. {
  400. QDF_STATUS ret;
  401. wmi_ocb_set_config_cmd_fixed_param *cmd;
  402. wmi_channel *chan;
  403. wmi_ocb_channel *ocb_chan;
  404. wmi_qos_parameter *qos_param;
  405. wmi_dcc_ndl_chan *ndl_chan;
  406. wmi_dcc_ndl_active_state_config *ndl_active_config;
  407. wmi_ocb_schedule_element *sched_elem;
  408. uint8_t *buf_ptr;
  409. wmi_buf_t buf;
  410. int32_t len;
  411. int32_t i, j, active_state_count;
  412. /*
  413. * Validate the dcc_ndl_chan_list_len and count the number of active
  414. * states. Validate dcc_ndl_active_state_list_len.
  415. */
  416. active_state_count = 0;
  417. if (config->dcc_ndl_chan_list_len) {
  418. if (!config->dcc_ndl_chan_list ||
  419. config->dcc_ndl_chan_list_len !=
  420. config->channel_count * sizeof(wmi_dcc_ndl_chan)) {
  421. WMI_LOGE(FL("NDL channel is invalid. List len: %d"),
  422. config->dcc_ndl_chan_list_len);
  423. return QDF_STATUS_E_INVAL;
  424. }
  425. for (i = 0, ndl_chan = config->dcc_ndl_chan_list;
  426. i < config->channel_count; ++i, ++ndl_chan)
  427. active_state_count +=
  428. WMI_NDL_NUM_ACTIVE_STATE_GET(ndl_chan);
  429. if (active_state_count) {
  430. if (!config->dcc_ndl_active_state_list ||
  431. config->dcc_ndl_active_state_list_len !=
  432. active_state_count *
  433. sizeof(wmi_dcc_ndl_active_state_config)) {
  434. WMI_LOGE(FL("NDL active state is invalid."));
  435. return QDF_STATUS_E_INVAL;
  436. }
  437. }
  438. }
  439. len = sizeof(*cmd) +
  440. WMI_TLV_HDR_SIZE + config->channel_count *
  441. sizeof(wmi_channel) +
  442. WMI_TLV_HDR_SIZE + config->channel_count *
  443. sizeof(wmi_ocb_channel) +
  444. WMI_TLV_HDR_SIZE + config->channel_count *
  445. sizeof(wmi_qos_parameter) * WMI_MAX_NUM_AC +
  446. WMI_TLV_HDR_SIZE + config->dcc_ndl_chan_list_len +
  447. WMI_TLV_HDR_SIZE + active_state_count *
  448. sizeof(wmi_dcc_ndl_active_state_config) +
  449. WMI_TLV_HDR_SIZE + config->schedule_size *
  450. sizeof(wmi_ocb_schedule_element);
  451. buf = wmi_buf_alloc(wmi_handle, len);
  452. if (!buf) {
  453. return QDF_STATUS_E_NOMEM;
  454. }
  455. buf_ptr = (uint8_t *)wmi_buf_data(buf);
  456. cmd = (wmi_ocb_set_config_cmd_fixed_param *)buf_ptr;
  457. WMITLV_SET_HDR(&cmd->tlv_header,
  458. WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param,
  459. WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_config_cmd_fixed_param));
  460. cmd->vdev_id = config->vdev_id;
  461. cmd->channel_count = config->channel_count;
  462. cmd->schedule_size = config->schedule_size;
  463. cmd->flags = config->flags;
  464. buf_ptr += sizeof(*cmd);
  465. /* Add the wmi_channel info */
  466. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  467. config->channel_count * sizeof(wmi_channel));
  468. buf_ptr += WMI_TLV_HDR_SIZE;
  469. for (i = 0; i < config->channel_count; i++) {
  470. chan = (wmi_channel *)buf_ptr;
  471. WMITLV_SET_HDR(&chan->tlv_header,
  472. WMITLV_TAG_STRUC_wmi_channel,
  473. WMITLV_GET_STRUCT_TLVLEN(wmi_channel));
  474. chan->mhz = config->channels[i].chan_freq;
  475. chan->band_center_freq1 = config->channels[i].chan_freq;
  476. chan->band_center_freq2 = 0;
  477. chan->info = 0;
  478. WMI_SET_CHANNEL_MODE(chan, config->channels[i].ch_mode);
  479. WMI_SET_CHANNEL_MAX_POWER(chan, config->channels[i].max_pwr);
  480. WMI_SET_CHANNEL_MIN_POWER(chan, config->channels[i].min_pwr);
  481. WMI_SET_CHANNEL_MAX_TX_POWER(chan, config->channels[i].max_pwr);
  482. WMI_SET_CHANNEL_REG_POWER(chan, config->channels[i].reg_pwr);
  483. WMI_SET_CHANNEL_ANTENNA_MAX(chan,
  484. config->channels[i].antenna_max);
  485. if (config->channels[i].bandwidth < 10)
  486. WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE);
  487. else if (config->channels[i].bandwidth < 20)
  488. WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE);
  489. buf_ptr += sizeof(*chan);
  490. }
  491. /* Add the wmi_ocb_channel info */
  492. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  493. config->channel_count * sizeof(wmi_ocb_channel));
  494. buf_ptr += WMI_TLV_HDR_SIZE;
  495. for (i = 0; i < config->channel_count; i++) {
  496. ocb_chan = (wmi_ocb_channel *)buf_ptr;
  497. WMITLV_SET_HDR(&ocb_chan->tlv_header,
  498. WMITLV_TAG_STRUC_wmi_ocb_channel,
  499. WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_channel));
  500. ocb_chan->bandwidth = config->channels[i].bandwidth;
  501. WMI_CHAR_ARRAY_TO_MAC_ADDR(
  502. config->channels[i].mac_address.bytes,
  503. &ocb_chan->mac_address);
  504. buf_ptr += sizeof(*ocb_chan);
  505. }
  506. /* Add the wmi_qos_parameter info */
  507. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  508. config->channel_count * sizeof(wmi_qos_parameter)*WMI_MAX_NUM_AC);
  509. buf_ptr += WMI_TLV_HDR_SIZE;
  510. /* WMI_MAX_NUM_AC parameters for each channel */
  511. for (i = 0; i < config->channel_count; i++) {
  512. for (j = 0; j < WMI_MAX_NUM_AC; j++) {
  513. qos_param = (wmi_qos_parameter *)buf_ptr;
  514. WMITLV_SET_HDR(&qos_param->tlv_header,
  515. WMITLV_TAG_STRUC_wmi_qos_parameter,
  516. WMITLV_GET_STRUCT_TLVLEN(wmi_qos_parameter));
  517. qos_param->aifsn =
  518. config->channels[i].qos_params[j].aifsn;
  519. qos_param->cwmin =
  520. config->channels[i].qos_params[j].cwmin;
  521. qos_param->cwmax =
  522. config->channels[i].qos_params[j].cwmax;
  523. buf_ptr += sizeof(*qos_param);
  524. }
  525. }
  526. /* Add the wmi_dcc_ndl_chan (per channel) */
  527. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  528. config->dcc_ndl_chan_list_len);
  529. buf_ptr += WMI_TLV_HDR_SIZE;
  530. if (config->dcc_ndl_chan_list_len) {
  531. ndl_chan = (wmi_dcc_ndl_chan *)buf_ptr;
  532. qdf_mem_copy(ndl_chan, config->dcc_ndl_chan_list,
  533. config->dcc_ndl_chan_list_len);
  534. for (i = 0; i < config->channel_count; i++)
  535. WMITLV_SET_HDR(&(ndl_chan[i].tlv_header),
  536. WMITLV_TAG_STRUC_wmi_dcc_ndl_chan,
  537. WMITLV_GET_STRUCT_TLVLEN(wmi_dcc_ndl_chan));
  538. buf_ptr += config->dcc_ndl_chan_list_len;
  539. }
  540. /* Add the wmi_dcc_ndl_active_state_config */
  541. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, active_state_count *
  542. sizeof(wmi_dcc_ndl_active_state_config));
  543. buf_ptr += WMI_TLV_HDR_SIZE;
  544. if (active_state_count) {
  545. ndl_active_config = (wmi_dcc_ndl_active_state_config *)buf_ptr;
  546. qdf_mem_copy(ndl_active_config,
  547. config->dcc_ndl_active_state_list,
  548. active_state_count * sizeof(*ndl_active_config));
  549. for (i = 0; i < active_state_count; ++i)
  550. WMITLV_SET_HDR(&(ndl_active_config[i].tlv_header),
  551. WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config,
  552. WMITLV_GET_STRUCT_TLVLEN(
  553. wmi_dcc_ndl_active_state_config));
  554. buf_ptr += active_state_count *
  555. sizeof(*ndl_active_config);
  556. }
  557. /* Add the wmi_ocb_schedule_element info */
  558. WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC,
  559. config->schedule_size * sizeof(wmi_ocb_schedule_element));
  560. buf_ptr += WMI_TLV_HDR_SIZE;
  561. for (i = 0; i < config->schedule_size; i++) {
  562. sched_elem = (wmi_ocb_schedule_element *)buf_ptr;
  563. WMITLV_SET_HDR(&sched_elem->tlv_header,
  564. WMITLV_TAG_STRUC_wmi_ocb_schedule_element,
  565. WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_schedule_element));
  566. sched_elem->channel_freq = config->schedule[i].chan_freq;
  567. sched_elem->total_duration = config->schedule[i].total_duration;
  568. sched_elem->guard_interval = config->schedule[i].guard_interval;
  569. buf_ptr += sizeof(*sched_elem);
  570. }
  571. wmi_mtrace(WMI_OCB_SET_CONFIG_CMDID, cmd->vdev_id, 0);
  572. ret = wmi_unified_cmd_send(wmi_handle, buf, len,
  573. WMI_OCB_SET_CONFIG_CMDID);
  574. if (QDF_IS_STATUS_ERROR(ret)) {
  575. WMI_LOGE("Failed to set OCB config");
  576. wmi_buf_free(buf);
  577. }
  578. return ret;
  579. }
  580. /**
  581. * extract_ocb_channel_config_resp_tlv() - extract ocb channel config resp
  582. * @wmi_handle: wmi handle
  583. * @evt_buf: wmi event buffer
  584. * @status: status buffer
  585. *
  586. * Return: QDF_STATUS_SUCCESS on success
  587. */
  588. static QDF_STATUS extract_ocb_channel_config_resp_tlv(wmi_unified_t wmi_handle,
  589. void *evt_buf,
  590. uint32_t *status)
  591. {
  592. WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs;
  593. wmi_ocb_set_config_resp_event_fixed_param *fix_param;
  594. param_tlvs = evt_buf;
  595. fix_param = param_tlvs->fixed_param;
  596. *status = fix_param->status;
  597. return QDF_STATUS_SUCCESS;
  598. }
  599. /**
  600. * extract_ocb_tsf_timer_tlv() - extract TSF timer from event buffer
  601. * @wmi_handle: wmi handle
  602. * @evt_buf: wmi event buffer
  603. * @resp: response buffer
  604. *
  605. * Return: QDF_STATUS_SUCCESS on success
  606. */
  607. static QDF_STATUS extract_ocb_tsf_timer_tlv(wmi_unified_t wmi_handle,
  608. void *evt_buf, struct ocb_get_tsf_timer_response *resp)
  609. {
  610. WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs;
  611. wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param;
  612. param_tlvs = evt_buf;
  613. fix_param = param_tlvs->fixed_param;
  614. resp->vdev_id = fix_param->vdev_id;
  615. resp->timer_high = fix_param->tsf_timer_high;
  616. resp->timer_low = fix_param->tsf_timer_low;
  617. return QDF_STATUS_SUCCESS;
  618. }
  619. /**
  620. * extract_ocb_ndl_resp_tlv() - extract TSF timer from event buffer
  621. * @wmi_handle: wmi handle
  622. * @evt_buf: wmi event buffer
  623. * @resp: response buffer
  624. *
  625. * Return: QDF_STATUS_SUCCESS on success
  626. */
  627. static QDF_STATUS extract_ocb_ndl_resp_tlv(wmi_unified_t wmi_handle,
  628. void *evt_buf, struct ocb_dcc_update_ndl_response *resp)
  629. {
  630. WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs;
  631. wmi_dcc_update_ndl_resp_event_fixed_param *fix_param;
  632. param_tlvs = evt_buf;
  633. fix_param = param_tlvs->fixed_param;
  634. resp->vdev_id = fix_param->vdev_id;
  635. resp->status = fix_param->status;
  636. return QDF_STATUS_SUCCESS;
  637. }
  638. /**
  639. * extract_ocb_dcc_stats_tlv() - extract DCC stats from event buffer
  640. * @wmi_handle: wmi handle
  641. * @evt_buf: wmi event buffer
  642. * @resp: response buffer
  643. *
  644. * Since length of stats is variable, buffer for DCC stats will be allocated
  645. * in this function. The caller must free the buffer.
  646. *
  647. * Return: QDF_STATUS_SUCCESS on success
  648. */
  649. static QDF_STATUS extract_ocb_dcc_stats_tlv(wmi_unified_t wmi_handle,
  650. void *evt_buf, struct ocb_dcc_get_stats_response **resp)
  651. {
  652. struct ocb_dcc_get_stats_response *response;
  653. WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs;
  654. wmi_dcc_get_stats_resp_event_fixed_param *fix_param;
  655. param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)evt_buf;
  656. fix_param = param_tlvs->fixed_param;
  657. /* Allocate and populate the response */
  658. if (fix_param->num_channels > ((WMI_SVC_MSG_MAX_SIZE -
  659. sizeof(*fix_param)) / sizeof(wmi_dcc_ndl_stats_per_channel)) ||
  660. fix_param->num_channels > param_tlvs->num_stats_per_channel_list) {
  661. wmi_warn("Too many channels:%d actual:%d",
  662. fix_param->num_channels,
  663. param_tlvs->num_stats_per_channel_list);
  664. *resp = NULL;
  665. return QDF_STATUS_E_INVAL;
  666. }
  667. response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels *
  668. sizeof(wmi_dcc_ndl_stats_per_channel));
  669. *resp = response;
  670. if (!response)
  671. return QDF_STATUS_E_NOMEM;
  672. response->vdev_id = fix_param->vdev_id;
  673. response->num_channels = fix_param->num_channels;
  674. response->channel_stats_array_len =
  675. fix_param->num_channels *
  676. sizeof(wmi_dcc_ndl_stats_per_channel);
  677. response->channel_stats_array = ((uint8_t *)response) +
  678. sizeof(*response);
  679. qdf_mem_copy(response->channel_stats_array,
  680. param_tlvs->stats_per_channel_list,
  681. response->channel_stats_array_len);
  682. return QDF_STATUS_SUCCESS;
  683. }
  684. void wmi_ocb_attach_tlv(wmi_unified_t wmi_handle)
  685. {
  686. struct wmi_ops *ops = wmi_handle->ops;
  687. ops->send_ocb_set_utc_time_cmd = send_ocb_set_utc_time_cmd_tlv;
  688. ops->send_ocb_get_tsf_timer_cmd = send_ocb_get_tsf_timer_cmd_tlv;
  689. ops->send_dcc_clear_stats_cmd = send_dcc_clear_stats_cmd_tlv;
  690. ops->send_dcc_get_stats_cmd = send_dcc_get_stats_cmd_tlv;
  691. ops->send_dcc_update_ndl_cmd = send_dcc_update_ndl_cmd_tlv;
  692. ops->send_ocb_set_config_cmd = send_ocb_set_config_cmd_tlv;
  693. ops->send_ocb_stop_timing_advert_cmd =
  694. send_ocb_stop_timing_advert_cmd_tlv;
  695. ops->send_ocb_start_timing_advert_cmd =
  696. send_ocb_start_timing_advert_cmd_tlv;
  697. ops->extract_ocb_chan_config_resp =
  698. extract_ocb_channel_config_resp_tlv;
  699. ops->extract_ocb_tsf_timer = extract_ocb_tsf_timer_tlv;
  700. ops->extract_dcc_update_ndl_resp = extract_ocb_ndl_resp_tlv;
  701. ops->extract_dcc_stats = extract_ocb_dcc_stats_tlv;
  702. }