wmi_tlv_helper.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
  1. /*
  2. * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
  3. *
  4. * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  5. *
  6. *
  7. * Permission to use, copy, modify, and/or distribute this software for
  8. * any purpose with or without fee is hereby granted, provided that the
  9. * above copyright notice and this permission notice appear in all
  10. * copies.
  11. *
  12. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  13. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  15. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  16. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  17. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  18. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  19. * PERFORMANCE OF THIS SOFTWARE.
  20. */
  21. /*
  22. * This file was originally distributed by Qualcomm Atheros, Inc.
  23. * under proprietary terms before Copyright ownership was assigned
  24. * to the Linux Foundation.
  25. */
  26. #include "wmi_tlv_platform.c"
  27. #include "wmi_tlv_defs.h"
  28. #include "wmi_version.h"
  29. #define WMITLV_GET_ATTRIB_NUM_TLVS 0xFFFFFFFF
  30. #define WMITLV_GET_CMDID(val) (val & 0x00FFFFFF)
  31. #define WMITLV_GET_NUM_TLVS(val) ((val >> 24) & 0xFF)
  32. #define WMITLV_GET_TAGID(val) (val & 0x00000FFF)
  33. #define WMITLV_GET_TAG_STRUCT_SIZE(val) ((val >> 12) & 0x000001FF)
  34. #define WMITLV_GET_TAG_ARRAY_SIZE(val) ((val >> 21) & 0x000001FF)
  35. #define WMITLV_GET_TAG_VARIED(val) ((val >> 30) & 0x00000001)
  36. #define WMITLV_SET_ATTRB0(id) ((WMITLV_GET_TAG_NUM_TLV_ATTRIB(id) << 24) | \
  37. (id & 0x00FFFFFF))
  38. #define WMITLV_SET_ATTRB1(tagID, tagStructSize, tagArraySize, tagVaried) \
  39. (((tagVaried&0x1)<<30) | ((tagArraySize&0x1FF)<<21) | \
  40. ((tagStructSize&0x1FF)<<12) | (tagID&0xFFF))
  41. #define WMITLV_OP_SET_TLV_ATTRIB_macro(param_ptr, param_len, wmi_cmd_event_id, \
  42. elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \
  43. WMITLV_SET_ATTRB1(elem_tlv_tag, sizeof(elem_struc_type), arr_size, var_len),
  44. #define WMITLV_GET_CMD_EVT_ATTRB_LIST(id) \
  45. WMITLV_SET_ATTRB0(id), \
  46. WMITLV_TABLE(id,SET_TLV_ATTRIB, NULL, 0)
  47. A_UINT32 cmd_attr_list[] = {
  48. WMITLV_ALL_CMD_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST)
  49. };
  50. A_UINT32 evt_attr_list[] = {
  51. WMITLV_ALL_EVT_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST)
  52. };
  53. #ifdef NO_DYNAMIC_MEM_ALLOC
  54. static wmitlv_cmd_param_info *g_wmi_static_cmd_param_info_buf;
  55. A_UINT32 g_wmi_static_max_cmd_param_tlvs;
  56. #endif
  57. /**
  58. * wmitlv_set_static_param_tlv_buf() - tlv helper function
  59. * @param_tlv_buf: tlv buffer parameter
  60. * @max_tlvs_accomodated: max no of tlv entries
  61. *
  62. *
  63. * WMI TLV Helper function to set the static cmd_param_tlv structure
  64. * and number of TLVs that can be accomodated in the structure.
  65. * This function should be used when dynamic memory allocation is not
  66. * supported. When dynamic memory allocation is not supported by any
  67. * component then NO_DYNAMIC_MEMALLOC macro has to be defined in respective
  68. * tlv_platform.c file. And respective component has to allocate
  69. * cmd_param_tlv structure buffer to accomodate whatever number of TLV's.
  70. * Both the buffer address and number of TLV's that can be accomodated in
  71. * the buffer should be sent as arguments to this function.
  72. *
  73. * Return None
  74. */
  75. void
  76. wmitlv_set_static_param_tlv_buf(void *param_tlv_buf,
  77. A_UINT32 max_tlvs_accomodated)
  78. {
  79. #ifdef NO_DYNAMIC_MEM_ALLOC
  80. g_wmi_static_cmd_param_info_buf = param_tlv_buf;
  81. g_wmi_static_max_cmd_param_tlvs = max_tlvs_accomodated;
  82. #endif
  83. }
  84. /**
  85. * wmitlv_get_attributes() - tlv helper function
  86. * @is_cmd_id: boolean for command attribute
  87. * @cmd_event_id: command event id
  88. * @curr_tlv_order: tlv order
  89. * @tlv_attr_ptr: pointer to tlv attribute
  90. *
  91. *
  92. * WMI TLV Helper functions to find the attributes of the
  93. * Command/Event TLVs.
  94. *
  95. * Return: 0 if success. Return >=1 if failure.
  96. */
  97. static
  98. A_UINT32 wmitlv_get_attributes(A_UINT32 is_cmd_id, A_UINT32 cmd_event_id,
  99. A_UINT32 curr_tlv_order,
  100. wmitlv_attributes_struc *tlv_attr_ptr)
  101. {
  102. A_UINT32 i, base_index, num_tlvs, num_entries;
  103. A_UINT32 *pAttrArrayList;
  104. if (is_cmd_id) {
  105. pAttrArrayList = &cmd_attr_list[0];
  106. num_entries = QDF_ARRAY_SIZE(cmd_attr_list);
  107. } else {
  108. pAttrArrayList = &evt_attr_list[0];
  109. num_entries = QDF_ARRAY_SIZE(evt_attr_list);
  110. }
  111. for (i = 0; i < num_entries; i++) {
  112. num_tlvs = WMITLV_GET_NUM_TLVS(pAttrArrayList[i]);
  113. if (WMITLV_GET_CMDID(cmd_event_id) ==
  114. WMITLV_GET_CMDID(pAttrArrayList[i])) {
  115. tlv_attr_ptr->cmd_num_tlv = num_tlvs;
  116. /* Return success from here when only number of TLVS for
  117. * this command/event is required */
  118. if (curr_tlv_order == WMITLV_GET_ATTRIB_NUM_TLVS) {
  119. wmi_tlv_print_verbose
  120. ("%s: WMI TLV attribute definitions for %s:0x%x found; num_of_tlvs:%d\n",
  121. __func__, (is_cmd_id ? "Cmd" : "Evt"),
  122. cmd_event_id, num_tlvs);
  123. return 0;
  124. }
  125. /* Return failure if tlv_order is more than the expected
  126. * number of TLVs */
  127. if (curr_tlv_order >= num_tlvs) {
  128. wmi_tlv_print_error
  129. ("%s: ERROR: TLV order %d greater than num_of_tlvs:%d for %s:0x%x\n",
  130. __func__, curr_tlv_order, num_tlvs,
  131. (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id);
  132. return 1;
  133. }
  134. base_index = i + 1; /* index to first TLV attributes */
  135. wmi_tlv_print_verbose
  136. ("%s: WMI TLV attributes for %s:0x%x tlv[%d]:0x%x\n",
  137. __func__, (is_cmd_id ? "Cmd" : "Evt"),
  138. cmd_event_id, curr_tlv_order,
  139. pAttrArrayList[(base_index + curr_tlv_order)]);
  140. tlv_attr_ptr->tag_order = curr_tlv_order;
  141. tlv_attr_ptr->tag_id =
  142. WMITLV_GET_TAGID(pAttrArrayList
  143. [(base_index + curr_tlv_order)]);
  144. tlv_attr_ptr->tag_struct_size =
  145. WMITLV_GET_TAG_STRUCT_SIZE(pAttrArrayList
  146. [(base_index +
  147. curr_tlv_order)]);
  148. tlv_attr_ptr->tag_varied_size =
  149. WMITLV_GET_TAG_VARIED(pAttrArrayList
  150. [(base_index +
  151. curr_tlv_order)]);
  152. tlv_attr_ptr->tag_array_size =
  153. WMITLV_GET_TAG_ARRAY_SIZE(pAttrArrayList
  154. [(base_index +
  155. curr_tlv_order)]);
  156. return 0;
  157. }
  158. i += num_tlvs;
  159. }
  160. wmi_tlv_print_error
  161. ("%s: ERROR: Didn't found WMI TLV attribute definitions for %s:0x%x\n",
  162. __func__, (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id);
  163. return 1;
  164. }
  165. /**
  166. * wmitlv_check_tlv_params() - tlv helper function
  167. * @os_handle: os context handle
  168. * @param_struc_ptr: pointer to tlv structure
  169. * @is_cmd_id: boolean for command attribute
  170. * @wmi_cmd_event_id: command event id
  171. *
  172. *
  173. * Helper Function to vaidate the prepared TLV's for
  174. * an WMI event/command to be sent.
  175. *
  176. * Return: 0 if success. Return < 0 if failure.
  177. */
  178. static int
  179. wmitlv_check_tlv_params(void *os_handle, void *param_struc_ptr,
  180. A_UINT32 param_buf_len, A_UINT32 is_cmd_id,
  181. A_UINT32 wmi_cmd_event_id)
  182. {
  183. wmitlv_attributes_struc attr_struct_ptr;
  184. A_UINT32 buf_idx = 0;
  185. A_UINT32 tlv_index = 0;
  186. A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr;
  187. A_UINT32 expected_num_tlvs, expected_tlv_len;
  188. A_INT32 error = -1;
  189. /* Get the number of TLVs for this command/event */
  190. if (wmitlv_get_attributes
  191. (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS,
  192. &attr_struct_ptr) != 0) {
  193. wmi_tlv_print_error
  194. ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n",
  195. __func__, wmi_cmd_event_id);
  196. goto Error_wmitlv_check_tlv_params;
  197. }
  198. /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */
  199. expected_num_tlvs = attr_struct_ptr.cmd_num_tlv;
  200. while ((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) {
  201. A_UINT32 curr_tlv_tag =
  202. WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
  203. A_UINT32 curr_tlv_len =
  204. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
  205. if ((buf_idx + WMI_TLV_HDR_SIZE + curr_tlv_len) > param_buf_len) {
  206. wmi_tlv_print_error
  207. ("%s: ERROR: Invalid TLV length for Cmd=%d Tag_order=%d buf_idx=%d Tag:%d Len:%d TotalLen:%d\n",
  208. __func__, wmi_cmd_event_id, tlv_index, buf_idx,
  209. curr_tlv_tag, curr_tlv_len, param_buf_len);
  210. goto Error_wmitlv_check_tlv_params;
  211. }
  212. /* Get the attributes of the TLV with the given order in "tlv_index" */
  213. wmi_tlv_OS_MEMZERO(&attr_struct_ptr,
  214. sizeof(wmitlv_attributes_struc));
  215. if (wmitlv_get_attributes
  216. (is_cmd_id, wmi_cmd_event_id, tlv_index,
  217. &attr_struct_ptr) != 0) {
  218. wmi_tlv_print_error
  219. ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n",
  220. __func__, wmi_cmd_event_id, tlv_index);
  221. goto Error_wmitlv_check_tlv_params;
  222. }
  223. /* Found the TLV that we wanted */
  224. wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n",
  225. __func__, tlv_index, curr_tlv_tag,
  226. curr_tlv_len);
  227. /* Validating Tag ID order */
  228. if (curr_tlv_tag != attr_struct_ptr.tag_id) {
  229. wmi_tlv_print_error
  230. ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n",
  231. __func__, wmi_cmd_event_id, curr_tlv_tag,
  232. attr_struct_ptr.tag_id);
  233. goto Error_wmitlv_check_tlv_params;
  234. }
  235. /* Validate Tag length */
  236. /* Array TLVs length checking needs special handling */
  237. if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)
  238. && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) {
  239. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  240. /* Array size can't be invalid for fixed size Array TLV */
  241. if (WMITLV_ARR_SIZE_INVALID ==
  242. attr_struct_ptr.tag_array_size) {
  243. wmi_tlv_print_error
  244. ("%s: ERROR: array_size can't be invalid for Array TLV Cmd=0x%x Tag=%d\n",
  245. __func__, wmi_cmd_event_id,
  246. curr_tlv_tag);
  247. goto Error_wmitlv_check_tlv_params;
  248. }
  249. expected_tlv_len =
  250. attr_struct_ptr.tag_array_size *
  251. attr_struct_ptr.tag_struct_size;
  252. /* Paddding is only required for Byte array Tlvs all other
  253. * array tlv's should be aligned to 4 bytes during their
  254. * definition */
  255. if (WMITLV_TAG_ARRAY_BYTE ==
  256. attr_struct_ptr.tag_id) {
  257. expected_tlv_len =
  258. roundup(expected_tlv_len,
  259. sizeof(A_UINT32));
  260. }
  261. if (curr_tlv_len != expected_tlv_len) {
  262. wmi_tlv_print_error
  263. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%d Expected_Len=%d.\n",
  264. __func__, wmi_cmd_event_id,
  265. tlv_index, curr_tlv_tag,
  266. curr_tlv_len, expected_tlv_len);
  267. goto Error_wmitlv_check_tlv_params;
  268. }
  269. } else {
  270. /* Array size should be invalid for variable size Array TLV */
  271. if (WMITLV_ARR_SIZE_INVALID !=
  272. attr_struct_ptr.tag_array_size) {
  273. wmi_tlv_print_error
  274. ("%s: ERROR: array_size should be invalid for Array TLV Cmd=0x%x Tag=%d\n",
  275. __func__, wmi_cmd_event_id,
  276. curr_tlv_tag);
  277. goto Error_wmitlv_check_tlv_params;
  278. }
  279. /* Incase of variable length TLV's, there is no expectation
  280. * on the length field so do whatever checking you can
  281. * depending on the TLV tag if TLV length is non-zero */
  282. if (curr_tlv_len != 0) {
  283. /* Verify TLV length is aligned to the size of structure */
  284. if ((curr_tlv_len %
  285. attr_struct_ptr.tag_struct_size) !=
  286. 0) {
  287. wmi_tlv_print_error
  288. ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to size of structure(%d bytes)\n",
  289. __func__, curr_tlv_len,
  290. wmi_cmd_event_id,
  291. attr_struct_ptr.
  292. tag_struct_size);
  293. goto Error_wmitlv_check_tlv_params;
  294. }
  295. if (curr_tlv_tag ==
  296. WMITLV_TAG_ARRAY_STRUC) {
  297. A_UINT8 *tlv_buf_ptr = NULL;
  298. A_UINT32 in_tlv_len;
  299. A_UINT32 idx;
  300. A_UINT32 num_of_elems;
  301. /* Verify length of inner TLVs */
  302. num_of_elems =
  303. curr_tlv_len /
  304. attr_struct_ptr.
  305. tag_struct_size;
  306. /* Set tlv_buf_ptr to the first inner TLV address */
  307. tlv_buf_ptr =
  308. buf_ptr + WMI_TLV_HDR_SIZE;
  309. for (idx = 0;
  310. idx < num_of_elems;
  311. idx++) {
  312. in_tlv_len =
  313. WMITLV_GET_TLVLEN
  314. (WMITLV_GET_HDR
  315. (tlv_buf_ptr));
  316. if ((in_tlv_len +
  317. WMI_TLV_HDR_SIZE)
  318. !=
  319. attr_struct_ptr.
  320. tag_struct_size) {
  321. wmi_tlv_print_error
  322. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%zu Expected_Len=%d.\n",
  323. __func__,
  324. wmi_cmd_event_id,
  325. tlv_index,
  326. curr_tlv_tag,
  327. (in_tlv_len
  328. +
  329. WMI_TLV_HDR_SIZE),
  330. attr_struct_ptr.
  331. tag_struct_size);
  332. goto Error_wmitlv_check_tlv_params;
  333. }
  334. tlv_buf_ptr +=
  335. in_tlv_len +
  336. WMI_TLV_HDR_SIZE;
  337. }
  338. } else
  339. if ((curr_tlv_tag ==
  340. WMITLV_TAG_ARRAY_UINT32)
  341. || (curr_tlv_tag ==
  342. WMITLV_TAG_ARRAY_BYTE)
  343. || (curr_tlv_tag ==
  344. WMITLV_TAG_ARRAY_FIXED_STRUC)) {
  345. /* Nothing to verify here */
  346. } else {
  347. wmi_tlv_print_error
  348. ("%s ERROR Need to handle the Array tlv %d for variable length for Cmd=0x%x\n",
  349. __func__,
  350. attr_struct_ptr.tag_id,
  351. wmi_cmd_event_id);
  352. goto Error_wmitlv_check_tlv_params;
  353. }
  354. }
  355. }
  356. } else {
  357. /* Non-array TLV. */
  358. if ((curr_tlv_len + WMI_TLV_HDR_SIZE) !=
  359. attr_struct_ptr.tag_struct_size) {
  360. wmi_tlv_print_error
  361. ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Given=%zu, Expected=%d.\n",
  362. __func__, wmi_cmd_event_id,
  363. (curr_tlv_len + WMI_TLV_HDR_SIZE),
  364. attr_struct_ptr.tag_struct_size);
  365. goto Error_wmitlv_check_tlv_params;
  366. }
  367. }
  368. /* Check TLV length is aligned to 4 bytes or not */
  369. if ((curr_tlv_len % sizeof(A_UINT32)) != 0) {
  370. wmi_tlv_print_error
  371. ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to %zu bytes\n",
  372. __func__, curr_tlv_len, wmi_cmd_event_id,
  373. sizeof(A_UINT32));
  374. goto Error_wmitlv_check_tlv_params;
  375. }
  376. tlv_index++;
  377. buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE;
  378. buf_idx += curr_tlv_len + WMI_TLV_HDR_SIZE;
  379. }
  380. if (tlv_index != expected_num_tlvs) {
  381. wmi_tlv_print_verbose
  382. ("%s: INFO: Less number of TLVs filled for Cmd=0x%x Filled %d Expected=%d\n",
  383. __func__, wmi_cmd_event_id, tlv_index, expected_num_tlvs);
  384. }
  385. return 0;
  386. Error_wmitlv_check_tlv_params:
  387. return error;
  388. }
  389. /**
  390. * wmitlv_check_event_tlv_params() - tlv helper function
  391. * @os_handle: os context handle
  392. * @param_struc_ptr: pointer to tlv structure
  393. * @is_cmd_id: boolean for command attribute
  394. * @wmi_cmd_event_id: command event id
  395. *
  396. *
  397. * Helper Function to vaidate the prepared TLV's for
  398. * an WMI event/command to be sent.
  399. *
  400. * Return: 0 if success. Return < 0 if failure.
  401. */
  402. int
  403. wmitlv_check_event_tlv_params(void *os_handle, void *param_struc_ptr,
  404. A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id)
  405. {
  406. A_UINT32 is_cmd_id = 0;
  407. return wmitlv_check_tlv_params
  408. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  409. wmi_cmd_event_id);
  410. }
  411. /**
  412. * wmitlv_check_command_tlv_params() - tlv helper function
  413. * @os_handle: os context handle
  414. * @param_struc_ptr: pointer to tlv structure
  415. * @is_cmd_id: boolean for command attribute
  416. * @wmi_cmd_event_id: command event id
  417. *
  418. *
  419. * Helper Function to vaidate the prepared TLV's for
  420. * an WMI event/command to be sent.
  421. *
  422. * Return: 0 if success. Return < 0 if failure.
  423. */
  424. int
  425. wmitlv_check_command_tlv_params(void *os_handle, void *param_struc_ptr,
  426. A_UINT32 param_buf_len,
  427. A_UINT32 wmi_cmd_event_id)
  428. {
  429. A_UINT32 is_cmd_id = 1;
  430. return wmitlv_check_tlv_params
  431. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  432. wmi_cmd_event_id);
  433. }
  434. /**
  435. * wmitlv_check_and_pad_tlvs() - tlv helper function
  436. * @os_handle: os context handle
  437. * @param_buf_len: length of tlv parameter
  438. * @param_struc_ptr: pointer to tlv structure
  439. * @is_cmd_id: boolean for command attribute
  440. * @wmi_cmd_event_id: command event id
  441. * @wmi_cmd_struct_ptr: wmi command structure
  442. *
  443. *
  444. * vaidate the TLV's coming for an event/command and
  445. * also pads data to TLV's if necessary
  446. *
  447. * Return: 0 if success. Return < 0 if failure.
  448. */
  449. static int
  450. wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr,
  451. A_UINT32 param_buf_len, A_UINT32 is_cmd_id,
  452. A_UINT32 wmi_cmd_event_id, void **wmi_cmd_struct_ptr)
  453. {
  454. wmitlv_attributes_struc attr_struct_ptr;
  455. A_UINT32 buf_idx = 0;
  456. A_UINT32 tlv_index = 0;
  457. A_UINT32 num_of_elems = 0;
  458. int tlv_size_diff = 0;
  459. A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr;
  460. wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL;
  461. A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF;
  462. A_UINT32 len_wmi_cmd_struct_buf;
  463. A_INT32 error = -1;
  464. /* Get the number of TLVs for this command/event */
  465. if (wmitlv_get_attributes
  466. (is_cmd_id, wmi_cmd_event_id, WMITLV_GET_ATTRIB_NUM_TLVS,
  467. &attr_struct_ptr) != 0) {
  468. wmi_tlv_print_error
  469. ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n",
  470. __func__, wmi_cmd_event_id);
  471. return error;
  472. }
  473. /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */
  474. if (param_buf_len < WMI_TLV_HDR_SIZE) {
  475. wmi_tlv_print_error
  476. ("%s: ERROR: Incorrect param buf length passed\n",
  477. __func__);
  478. return error;
  479. }
  480. /* Create base structure of format wmi_cmd_event_id##_param_tlvs */
  481. len_wmi_cmd_struct_buf =
  482. attr_struct_ptr.cmd_num_tlv * sizeof(wmitlv_cmd_param_info);
  483. #ifndef NO_DYNAMIC_MEM_ALLOC
  484. /* Dynamic memory allocation supported */
  485. wmi_tlv_os_mem_alloc(os_handle, *wmi_cmd_struct_ptr,
  486. len_wmi_cmd_struct_buf);
  487. #else
  488. /* Dynamic memory allocation is not supported. Use the buffer
  489. * g_wmi_static_cmd_param_info_buf, which should be set using
  490. * wmi_tlv_set_static_param_tlv_buf(),
  491. * for base structure of format wmi_cmd_event_id##_param_tlvs */
  492. *wmi_cmd_struct_ptr = g_wmi_static_cmd_param_info_buf;
  493. if (attr_struct_ptr.cmd_num_tlv > g_wmi_static_max_cmd_param_tlvs) {
  494. /* Error: Expecting more TLVs that accomodated for static structure */
  495. wmi_tlv_print_error
  496. ("%s: Error: Expecting more TLVs that accomodated for static structure. Expected:%d Accomodated:%d\n",
  497. __func__, attr_struct_ptr.cmd_num_tlv,
  498. g_wmi_static_max_cmd_param_tlvs);
  499. return error;
  500. }
  501. #endif
  502. if (*wmi_cmd_struct_ptr == NULL) {
  503. /* Error: unable to alloc memory */
  504. wmi_tlv_print_error
  505. ("%s: Error: unable to alloc memory (size=%d) for TLV\n",
  506. __func__, len_wmi_cmd_struct_buf);
  507. return error;
  508. }
  509. cmd_param_tlvs_ptr = (wmitlv_cmd_param_info *) *wmi_cmd_struct_ptr;
  510. wmi_tlv_OS_MEMZERO(cmd_param_tlvs_ptr, len_wmi_cmd_struct_buf);
  511. remaining_expected_tlvs = attr_struct_ptr.cmd_num_tlv;
  512. while (((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len)
  513. && (remaining_expected_tlvs)) {
  514. A_UINT32 curr_tlv_tag =
  515. WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr));
  516. A_UINT32 curr_tlv_len =
  517. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr));
  518. int num_padding_bytes = 0;
  519. /* Get the attributes of the TLV with the given order in "tlv_index" */
  520. wmi_tlv_OS_MEMZERO(&attr_struct_ptr,
  521. sizeof(wmitlv_attributes_struc));
  522. if (wmitlv_get_attributes
  523. (is_cmd_id, wmi_cmd_event_id, tlv_index,
  524. &attr_struct_ptr) != 0) {
  525. wmi_tlv_print_error
  526. ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n",
  527. __func__, wmi_cmd_event_id, tlv_index);
  528. goto Error_wmitlv_check_and_pad_tlvs;
  529. }
  530. /* Found the TLV that we wanted */
  531. wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n",
  532. __func__, tlv_index, curr_tlv_tag,
  533. curr_tlv_len);
  534. /* Validating Tag order */
  535. if (curr_tlv_tag != attr_struct_ptr.tag_id) {
  536. wmi_tlv_print_error
  537. ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n",
  538. __func__, wmi_cmd_event_id, curr_tlv_tag,
  539. attr_struct_ptr.tag_id);
  540. goto Error_wmitlv_check_and_pad_tlvs;
  541. }
  542. if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM)
  543. && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) {
  544. /* Current Tag is an array of some kind. */
  545. /* Skip the TLV header of this array */
  546. buf_ptr += WMI_TLV_HDR_SIZE;
  547. buf_idx += WMI_TLV_HDR_SIZE;
  548. } else {
  549. /* Non-array TLV. */
  550. curr_tlv_len += WMI_TLV_HDR_SIZE;
  551. }
  552. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  553. /* This TLV is fixed length */
  554. if (WMITLV_ARR_SIZE_INVALID ==
  555. attr_struct_ptr.tag_array_size) {
  556. tlv_size_diff =
  557. curr_tlv_len -
  558. attr_struct_ptr.tag_struct_size;
  559. num_of_elems =
  560. (curr_tlv_len > WMI_TLV_HDR_SIZE) ? 1 : 0;
  561. } else {
  562. tlv_size_diff =
  563. curr_tlv_len -
  564. (attr_struct_ptr.tag_struct_size *
  565. attr_struct_ptr.tag_array_size);
  566. num_of_elems = attr_struct_ptr.tag_array_size;
  567. }
  568. } else {
  569. /* This TLV has a variable number of elements */
  570. if (WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) {
  571. A_UINT32 in_tlv_len = 0;
  572. if (curr_tlv_len != 0) {
  573. in_tlv_len =
  574. WMITLV_GET_TLVLEN(WMITLV_GET_HDR
  575. (buf_ptr));
  576. in_tlv_len += WMI_TLV_HDR_SIZE;
  577. tlv_size_diff =
  578. in_tlv_len -
  579. attr_struct_ptr.tag_struct_size;
  580. num_of_elems =
  581. curr_tlv_len / in_tlv_len;
  582. wmi_tlv_print_verbose
  583. ("%s: WARN: TLV array of structures in_tlv_len=%d struct_size:%d diff:%d num_of_elems=%d \n",
  584. __func__, in_tlv_len,
  585. attr_struct_ptr.tag_struct_size,
  586. tlv_size_diff, num_of_elems);
  587. } else {
  588. tlv_size_diff = 0;
  589. num_of_elems = 0;
  590. }
  591. } else
  592. if ((WMITLV_TAG_ARRAY_UINT32 ==
  593. attr_struct_ptr.tag_id)
  594. || (WMITLV_TAG_ARRAY_BYTE ==
  595. attr_struct_ptr.tag_id)
  596. || (WMITLV_TAG_ARRAY_FIXED_STRUC ==
  597. attr_struct_ptr.tag_id)) {
  598. tlv_size_diff = 0;
  599. num_of_elems =
  600. curr_tlv_len /
  601. attr_struct_ptr.tag_struct_size;
  602. } else {
  603. wmi_tlv_print_error
  604. ("%s ERROR Need to handle this tag ID for variable length %d\n",
  605. __func__, attr_struct_ptr.tag_id);
  606. goto Error_wmitlv_check_and_pad_tlvs;
  607. }
  608. }
  609. if ((WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) &&
  610. (tlv_size_diff != 0)) {
  611. void *new_tlv_buf = NULL;
  612. A_UINT8 *tlv_buf_ptr = NULL;
  613. A_UINT32 in_tlv_len;
  614. A_UINT32 i;
  615. if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) {
  616. /* This is not allowed. The tag WMITLV_TAG_ARRAY_STRUC can
  617. * only be used with variable-length structure array
  618. * should not have a fixed number of elements (contradicting).
  619. * Use WMITLV_TAG_ARRAY_FIXED_STRUC tag for fixed size
  620. * structure array(where structure never change without
  621. * breaking compatibility) */
  622. wmi_tlv_print_error
  623. ("%s: ERROR: TLV (tag=%d) should be variable-length and not fixed length\n",
  624. __func__, curr_tlv_tag);
  625. goto Error_wmitlv_check_and_pad_tlvs;
  626. }
  627. /* Warning: Needs to allocate a larger structure and pad with zeros */
  628. wmi_tlv_print_verbose
  629. ("%s: WARN: TLV array of structures needs padding. tlv_size_diff=%d\n",
  630. __func__, tlv_size_diff);
  631. /* incoming structure length */
  632. in_tlv_len =
  633. WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)) +
  634. WMI_TLV_HDR_SIZE;
  635. #ifndef NO_DYNAMIC_MEM_ALLOC
  636. wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf,
  637. (num_of_elems *
  638. attr_struct_ptr.tag_struct_size));
  639. if (new_tlv_buf == NULL) {
  640. /* Error: unable to alloc memory */
  641. wmi_tlv_print_error
  642. ("%s: Error: unable to alloc memory (size=%d) for padding the TLV array %d\n",
  643. __func__,
  644. (num_of_elems *
  645. attr_struct_ptr.tag_struct_size),
  646. curr_tlv_tag);
  647. goto Error_wmitlv_check_and_pad_tlvs;
  648. }
  649. wmi_tlv_OS_MEMZERO(new_tlv_buf,
  650. (num_of_elems *
  651. attr_struct_ptr.tag_struct_size));
  652. tlv_buf_ptr = (A_UINT8 *) new_tlv_buf;
  653. for (i = 0; i < num_of_elems; i++) {
  654. if (tlv_size_diff > 0) {
  655. /* Incoming structure size is greater than expected
  656. * structure size. so copy the number of bytes equal
  657. * to expected structure size */
  658. wmi_tlv_OS_MEMCPY(tlv_buf_ptr,
  659. (void *)(buf_ptr +
  660. i *
  661. in_tlv_len),
  662. attr_struct_ptr.
  663. tag_struct_size);
  664. } else {
  665. /* Incoming structure size is smaller than expected
  666. * structure size. so copy the number of bytes equal
  667. * to incoming structure size */
  668. wmi_tlv_OS_MEMCPY(tlv_buf_ptr,
  669. (void *)(buf_ptr +
  670. i *
  671. in_tlv_len),
  672. in_tlv_len);
  673. }
  674. tlv_buf_ptr += attr_struct_ptr.tag_struct_size;
  675. }
  676. #else
  677. {
  678. A_UINT8 *src_addr;
  679. A_UINT8 *dst_addr;
  680. A_UINT32 buf_mov_len;
  681. if (tlv_size_diff < 0) {
  682. /* Incoming structure size is smaller than expected size
  683. * then this needs padding for each element in the array */
  684. /* Find amount of bytes to be padded for one element */
  685. num_padding_bytes = tlv_size_diff * -1;
  686. /* Move subsequent TLVs by number of bytes to be padded
  687. * for all elements */
  688. if (param_buf_len >
  689. (buf_idx + curr_tlv_len)) {
  690. src_addr =
  691. buf_ptr + curr_tlv_len;
  692. dst_addr =
  693. buf_ptr + curr_tlv_len +
  694. (num_padding_bytes *
  695. num_of_elems);
  696. buf_mov_len =
  697. param_buf_len - (buf_idx +
  698. curr_tlv_len);
  699. wmi_tlv_OS_MEMMOVE(dst_addr,
  700. src_addr,
  701. buf_mov_len);
  702. }
  703. /* Move subsequent elements of array down by number of
  704. * bytes to be padded for one element and alse set
  705. * padding bytes to zero */
  706. tlv_buf_ptr = buf_ptr;
  707. for (i = 0; i < num_of_elems; i++) {
  708. src_addr =
  709. tlv_buf_ptr + in_tlv_len;
  710. if (i != (num_of_elems - 1)) {
  711. /* Need not move anything for last element
  712. * in the array */
  713. dst_addr =
  714. tlv_buf_ptr +
  715. in_tlv_len +
  716. num_padding_bytes;
  717. buf_mov_len =
  718. curr_tlv_len -
  719. ((i +
  720. 1) * in_tlv_len);
  721. wmi_tlv_OS_MEMMOVE
  722. (dst_addr, src_addr,
  723. buf_mov_len);
  724. }
  725. /* Set the padding bytes to zeroes */
  726. wmi_tlv_OS_MEMZERO(src_addr,
  727. num_padding_bytes);
  728. tlv_buf_ptr +=
  729. attr_struct_ptr.
  730. tag_struct_size;
  731. }
  732. /* Update the number of padding bytes to total number
  733. * of bytes padded for all elements in the array */
  734. num_padding_bytes =
  735. num_padding_bytes * num_of_elems;
  736. new_tlv_buf = buf_ptr;
  737. } else {
  738. /* Incoming structure size is greater than expected size
  739. * then this needs shrinking for each element in the array */
  740. /* Find amount of bytes to be shrinked for one element */
  741. num_padding_bytes = tlv_size_diff * -1;
  742. /* Move subsequent elements of array up by number of bytes
  743. * to be shrinked for one element */
  744. tlv_buf_ptr = buf_ptr;
  745. for (i = 0; i < (num_of_elems - 1); i++) {
  746. src_addr =
  747. tlv_buf_ptr + in_tlv_len;
  748. dst_addr =
  749. tlv_buf_ptr + in_tlv_len +
  750. num_padding_bytes;
  751. buf_mov_len =
  752. curr_tlv_len -
  753. ((i + 1) * in_tlv_len);
  754. wmi_tlv_OS_MEMMOVE(dst_addr,
  755. src_addr,
  756. buf_mov_len);
  757. tlv_buf_ptr +=
  758. attr_struct_ptr.
  759. tag_struct_size;
  760. }
  761. /* Move subsequent TLVs by number of bytes to be shrinked
  762. * for all elements */
  763. if (param_buf_len >
  764. (buf_idx + curr_tlv_len)) {
  765. src_addr =
  766. buf_ptr + curr_tlv_len;
  767. dst_addr =
  768. buf_ptr + curr_tlv_len +
  769. (num_padding_bytes *
  770. num_of_elems);
  771. buf_mov_len =
  772. param_buf_len - (buf_idx +
  773. curr_tlv_len);
  774. wmi_tlv_OS_MEMMOVE(dst_addr,
  775. src_addr,
  776. buf_mov_len);
  777. }
  778. /* Update the number of padding bytes to total number of
  779. * bytes shrinked for all elements in the array */
  780. num_padding_bytes =
  781. num_padding_bytes * num_of_elems;
  782. new_tlv_buf = buf_ptr;
  783. }
  784. }
  785. #endif
  786. cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf;
  787. cmd_param_tlvs_ptr[tlv_index].num_elements =
  788. num_of_elems;
  789. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */
  790. } else if (tlv_size_diff >= 0) {
  791. /* Warning: some parameter truncation */
  792. if (tlv_size_diff > 0) {
  793. wmi_tlv_print_verbose
  794. ("%s: WARN: TLV truncated. tlv_size_diff=%d, curr_tlv_len=%d\n",
  795. __func__, tlv_size_diff, curr_tlv_len);
  796. }
  797. /* TODO: this next line needs more comments and explanation */
  798. cmd_param_tlvs_ptr[tlv_index].tlv_ptr =
  799. (attr_struct_ptr.tag_varied_size
  800. && !curr_tlv_len) ? NULL : (void *)buf_ptr;
  801. cmd_param_tlvs_ptr[tlv_index].num_elements =
  802. num_of_elems;
  803. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 0; /* Indicates that buffer is not allocated */
  804. } else {
  805. void *new_tlv_buf = NULL;
  806. /* Warning: Needs to allocate a larger structure and pad with zeros */
  807. wmi_tlv_print_verbose
  808. ("%s: WARN: TLV needs padding. tlv_size_diff=%d\n",
  809. __func__, tlv_size_diff);
  810. #ifndef NO_DYNAMIC_MEM_ALLOC
  811. /* Dynamic memory allocation is supported */
  812. wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf,
  813. (curr_tlv_len - tlv_size_diff));
  814. if (new_tlv_buf == NULL) {
  815. /* Error: unable to alloc memory */
  816. wmi_tlv_print_error
  817. ("%s: Error: unable to alloc memory (size=%d) for padding the TLV %d\n",
  818. __func__, (curr_tlv_len - tlv_size_diff),
  819. curr_tlv_tag);
  820. goto Error_wmitlv_check_and_pad_tlvs;
  821. }
  822. wmi_tlv_OS_MEMZERO(new_tlv_buf,
  823. (curr_tlv_len - tlv_size_diff));
  824. wmi_tlv_OS_MEMCPY(new_tlv_buf, (void *)buf_ptr,
  825. curr_tlv_len);
  826. #else
  827. /* Dynamic memory allocation is not supported. Padding has
  828. * to be done with in the existing buffer assuming we have
  829. * enough space to grow */
  830. {
  831. /* Note: tlv_size_diff is a value less than zero */
  832. /* Move the Subsequent TLVs by amount of bytes needs to be padded */
  833. A_UINT8 *src_addr;
  834. A_UINT8 *dst_addr;
  835. A_UINT32 src_len;
  836. num_padding_bytes = (tlv_size_diff * -1);
  837. src_addr = buf_ptr + curr_tlv_len;
  838. dst_addr =
  839. buf_ptr + curr_tlv_len + num_padding_bytes;
  840. src_len =
  841. param_buf_len - (buf_idx + curr_tlv_len);
  842. wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, src_len);
  843. /* Set the padding bytes to zeroes */
  844. wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes);
  845. new_tlv_buf = buf_ptr;
  846. }
  847. #endif
  848. cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf;
  849. cmd_param_tlvs_ptr[tlv_index].num_elements =
  850. num_of_elems;
  851. cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */
  852. }
  853. tlv_index++;
  854. remaining_expected_tlvs--;
  855. buf_ptr += curr_tlv_len + num_padding_bytes;
  856. buf_idx += curr_tlv_len + num_padding_bytes;
  857. }
  858. return 0;
  859. Error_wmitlv_check_and_pad_tlvs:
  860. if (is_cmd_id) {
  861. wmitlv_free_allocated_command_tlvs(wmi_cmd_event_id,
  862. wmi_cmd_struct_ptr);
  863. } else {
  864. wmitlv_free_allocated_event_tlvs(wmi_cmd_event_id,
  865. wmi_cmd_struct_ptr);
  866. }
  867. *wmi_cmd_struct_ptr = NULL;
  868. return error;
  869. }
  870. /**
  871. * wmitlv_check_and_pad_event_tlvs() - tlv helper function
  872. * @os_handle: os context handle
  873. * @param_struc_ptr: pointer to tlv structure
  874. * @param_buf_len: length of tlv parameter
  875. * @wmi_cmd_event_id: command event id
  876. * @wmi_cmd_struct_ptr: wmi command structure
  877. *
  878. *
  879. * validate and pad(if necessary) for incoming WMI Event TLVs
  880. *
  881. * Return: 0 if success. Return < 0 if failure.
  882. */
  883. int
  884. wmitlv_check_and_pad_event_tlvs(void *os_handle, void *param_struc_ptr,
  885. A_UINT32 param_buf_len,
  886. A_UINT32 wmi_cmd_event_id,
  887. void **wmi_cmd_struct_ptr)
  888. {
  889. A_UINT32 is_cmd_id = 0;
  890. return wmitlv_check_and_pad_tlvs
  891. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  892. wmi_cmd_event_id, wmi_cmd_struct_ptr);
  893. }
  894. /**
  895. * wmitlv_check_and_pad_command_tlvs() - tlv helper function
  896. * @os_handle: os context handle
  897. * @param_struc_ptr: pointer to tlv structure
  898. * @param_buf_len: length of tlv parameter
  899. * @wmi_cmd_event_id: command event id
  900. * @wmi_cmd_struct_ptr: wmi command structure
  901. *
  902. *
  903. * validate and pad(if necessary) for incoming WMI Command TLVs
  904. *
  905. * Return: 0 if success. Return < 0 if failure.
  906. */
  907. int
  908. wmitlv_check_and_pad_command_tlvs(void *os_handle, void *param_struc_ptr,
  909. A_UINT32 param_buf_len,
  910. A_UINT32 wmi_cmd_event_id,
  911. void **wmi_cmd_struct_ptr)
  912. {
  913. A_UINT32 is_cmd_id = 1;
  914. return wmitlv_check_and_pad_tlvs
  915. (os_handle, param_struc_ptr, param_buf_len, is_cmd_id,
  916. wmi_cmd_event_id, wmi_cmd_struct_ptr);
  917. }
  918. /**
  919. * wmitlv_free_allocated_tlvs() - tlv helper function
  920. * @is_cmd_id: bollean to check if cmd or event tlv
  921. * @cmd_event_id: command or event id
  922. * @wmi_cmd_struct_ptr: wmi command structure
  923. *
  924. *
  925. * free any allocated buffers for WMI Event/Command TLV processing
  926. *
  927. * Return: none
  928. */
  929. static void wmitlv_free_allocated_tlvs(A_UINT32 is_cmd_id,
  930. A_UINT32 cmd_event_id,
  931. void **wmi_cmd_struct_ptr)
  932. {
  933. void *ptr = *wmi_cmd_struct_ptr;
  934. if (!ptr) {
  935. wmi_tlv_print_error("%s: Nothing to free for CMD/Event 0x%x\n",
  936. __func__, cmd_event_id);
  937. return;
  938. }
  939. #ifndef NO_DYNAMIC_MEM_ALLOC
  940. /* macro to free that previously allocated memory for this TLV. When (op==FREE_TLV_ELEM). */
  941. #define WMITLV_OP_FREE_TLV_ELEM_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \
  942. if ((((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name)) && \
  943. (((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name != NULL)) \
  944. { \
  945. wmi_tlv_os_mem_free(((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name); \
  946. }
  947. #define WMITLV_FREE_TLV_ELEMS(id) \
  948. case id: \
  949. { \
  950. WMITLV_TABLE(id, FREE_TLV_ELEM, NULL, 0) \
  951. } \
  952. break;
  953. if (is_cmd_id) {
  954. switch (cmd_event_id) {
  955. WMITLV_ALL_CMD_LIST(WMITLV_FREE_TLV_ELEMS);
  956. default:
  957. wmi_tlv_print_error
  958. ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n",
  959. __func__, cmd_event_id, cmd_event_id);
  960. }
  961. } else {
  962. switch (cmd_event_id) {
  963. WMITLV_ALL_EVT_LIST(WMITLV_FREE_TLV_ELEMS);
  964. default:
  965. wmi_tlv_print_error
  966. ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n",
  967. __func__, cmd_event_id, cmd_event_id);
  968. }
  969. }
  970. wmi_tlv_os_mem_free(*wmi_cmd_struct_ptr);
  971. *wmi_cmd_struct_ptr = NULL;
  972. #endif
  973. return;
  974. }
  975. /**
  976. * wmitlv_free_allocated_command_tlvs() - tlv helper function
  977. * @cmd_event_id: command or event id
  978. * @wmi_cmd_struct_ptr: wmi command structure
  979. *
  980. *
  981. * free any allocated buffers for WMI Event/Command TLV processing
  982. *
  983. * Return: none
  984. */
  985. void wmitlv_free_allocated_command_tlvs(A_UINT32 cmd_event_id,
  986. void **wmi_cmd_struct_ptr)
  987. {
  988. wmitlv_free_allocated_tlvs(1, cmd_event_id, wmi_cmd_struct_ptr);
  989. }
  990. /**
  991. * wmitlv_free_allocated_event_tlvs() - tlv helper function
  992. * @cmd_event_id: command or event id
  993. * @wmi_cmd_struct_ptr: wmi command structure
  994. *
  995. *
  996. * free any allocated buffers for WMI Event/Command TLV processing
  997. *
  998. * Return: none
  999. */
  1000. void wmitlv_free_allocated_event_tlvs(A_UINT32 cmd_event_id,
  1001. void **wmi_cmd_struct_ptr)
  1002. {
  1003. wmitlv_free_allocated_tlvs(0, cmd_event_id, wmi_cmd_struct_ptr);
  1004. }
  1005. /**
  1006. * wmi_versions_are_compatible() - tlv helper function
  1007. * @vers1: host wmi version
  1008. * @vers2: target wmi version
  1009. *
  1010. *
  1011. * check if two given wmi versions are compatible
  1012. *
  1013. * Return: none
  1014. */
  1015. int
  1016. wmi_versions_are_compatible(wmi_abi_version *vers1, wmi_abi_version *vers2)
  1017. {
  1018. if ((vers1->abi_version_ns_0 != vers2->abi_version_ns_0) ||
  1019. (vers1->abi_version_ns_1 != vers2->abi_version_ns_1) ||
  1020. (vers1->abi_version_ns_2 != vers2->abi_version_ns_2) ||
  1021. (vers1->abi_version_ns_3 != vers2->abi_version_ns_3)) {
  1022. /* The namespaces are different. Incompatible. */
  1023. return 0;
  1024. }
  1025. if (vers1->abi_version_0 != vers2->abi_version_0) {
  1026. /* The major or minor versions are different. Incompatible */
  1027. return 0;
  1028. }
  1029. /* We ignore the build version */
  1030. return 1;
  1031. }
  1032. /**
  1033. * wmi_versions_can_downgrade() - tlv helper function
  1034. * @version_whitelist_table: version table
  1035. * @my_vers: host version
  1036. * @opp_vers: target version
  1037. * @out_vers: downgraded version
  1038. *
  1039. *
  1040. * check if target wmi version can be downgraded
  1041. *
  1042. * Return: 0 if success. Return < 0 if failure.
  1043. */
  1044. static int
  1045. wmi_versions_can_downgrade(int num_whitelist,
  1046. wmi_whitelist_version_info *version_whitelist_table,
  1047. wmi_abi_version *my_vers,
  1048. wmi_abi_version *opp_vers,
  1049. wmi_abi_version *out_vers)
  1050. {
  1051. A_UINT8 can_try_to_downgrade;
  1052. A_UINT32 my_major_vers = WMI_VER_GET_MAJOR(my_vers->abi_version_0);
  1053. A_UINT32 my_minor_vers = WMI_VER_GET_MINOR(my_vers->abi_version_0);
  1054. A_UINT32 opp_major_vers = WMI_VER_GET_MAJOR(opp_vers->abi_version_0);
  1055. A_UINT32 opp_minor_vers = WMI_VER_GET_MINOR(opp_vers->abi_version_0);
  1056. A_UINT32 downgraded_minor_vers;
  1057. if ((my_vers->abi_version_ns_0 != opp_vers->abi_version_ns_0) ||
  1058. (my_vers->abi_version_ns_1 != opp_vers->abi_version_ns_1) ||
  1059. (my_vers->abi_version_ns_2 != opp_vers->abi_version_ns_2) ||
  1060. (my_vers->abi_version_ns_3 != opp_vers->abi_version_ns_3)) {
  1061. /* The namespaces are different. Incompatible. */
  1062. can_try_to_downgrade = false;
  1063. } else if (my_major_vers != opp_major_vers) {
  1064. /* Major version is different. Incompatible and cannot downgrade. */
  1065. can_try_to_downgrade = false;
  1066. } else {
  1067. /* Same major version. */
  1068. if (my_minor_vers < opp_minor_vers) {
  1069. /* Opposite party is newer. Incompatible and cannot downgrade. */
  1070. can_try_to_downgrade = false;
  1071. } else if (my_minor_vers > opp_minor_vers) {
  1072. /* Opposite party is older. Check whitelist if we can downgrade */
  1073. can_try_to_downgrade = true;
  1074. } else {
  1075. /* Same version */
  1076. wmi_tlv_OS_MEMCPY(out_vers, my_vers,
  1077. sizeof(wmi_abi_version));
  1078. return 1;
  1079. }
  1080. }
  1081. if (!can_try_to_downgrade) {
  1082. wmi_tlv_print_error("%s: Warning: incompatible WMI version.\n",
  1083. __func__);
  1084. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1085. return 0;
  1086. }
  1087. /* Try to see we can downgrade the supported version */
  1088. downgraded_minor_vers = my_minor_vers;
  1089. while (downgraded_minor_vers > opp_minor_vers) {
  1090. A_UINT8 downgraded = false;
  1091. int i;
  1092. for (i = 0; i < num_whitelist; i++) {
  1093. if (version_whitelist_table[i].major != my_major_vers) {
  1094. continue; /* skip */
  1095. }
  1096. if ((version_whitelist_table[i].namespace_0 !=
  1097. my_vers->abi_version_ns_0)
  1098. || (version_whitelist_table[i].namespace_1 !=
  1099. my_vers->abi_version_ns_1)
  1100. || (version_whitelist_table[i].namespace_2 !=
  1101. my_vers->abi_version_ns_2)
  1102. || (version_whitelist_table[i].namespace_3 !=
  1103. my_vers->abi_version_ns_3)) {
  1104. continue; /* skip */
  1105. }
  1106. if (version_whitelist_table[i].minor ==
  1107. downgraded_minor_vers) {
  1108. /* Found the next version that I can downgrade */
  1109. wmi_tlv_print_error
  1110. ("%s: Note: found a whitelist entry to downgrade. wh. list ver: %d,%d,0x%x 0x%x 0x%x 0x%x\n",
  1111. __func__, version_whitelist_table[i].major,
  1112. version_whitelist_table[i].minor,
  1113. version_whitelist_table[i].namespace_0,
  1114. version_whitelist_table[i].namespace_1,
  1115. version_whitelist_table[i].namespace_2,
  1116. version_whitelist_table[i].namespace_3);
  1117. downgraded_minor_vers--;
  1118. downgraded = true;
  1119. break;
  1120. }
  1121. }
  1122. if (!downgraded) {
  1123. break; /* Done since we did not find any whitelist to downgrade version */
  1124. }
  1125. }
  1126. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1127. out_vers->abi_version_0 =
  1128. WMI_VER_GET_VERSION_0(my_major_vers, downgraded_minor_vers);
  1129. if (downgraded_minor_vers != opp_minor_vers) {
  1130. wmi_tlv_print_error
  1131. ("%s: Warning: incompatible WMI version and cannot downgrade.\n",
  1132. __func__);
  1133. return 0; /* Incompatible */
  1134. } else {
  1135. return 1; /* Compatible */
  1136. }
  1137. }
  1138. /**
  1139. * wmi_cmp_and_set_abi_version() - tlv helper function
  1140. * @version_whitelist_table: version table
  1141. * @my_vers: host version
  1142. * @opp_vers: target version
  1143. * @out_vers: downgraded version
  1144. *
  1145. * This routine will compare and set the WMI ABI version.
  1146. * First, compare my version with the opposite side's version.
  1147. * If incompatible, then check the whitelist to see if our side can downgrade.
  1148. * Finally, fill in the final ABI version into the output, out_vers.
  1149. * Return 0 if the output version is compatible
  1150. * Else return 1 if the output version is incompatible
  1151. *
  1152. * Return: 0 if the output version is compatible else < 0.
  1153. */
  1154. int
  1155. wmi_cmp_and_set_abi_version(int num_whitelist,
  1156. wmi_whitelist_version_info *
  1157. version_whitelist_table,
  1158. struct _wmi_abi_version *my_vers,
  1159. struct _wmi_abi_version *opp_vers,
  1160. struct _wmi_abi_version *out_vers)
  1161. {
  1162. wmi_tlv_print_verbose
  1163. ("%s: Our WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1164. __func__, WMI_VER_GET_MAJOR(my_vers->abi_version_0),
  1165. WMI_VER_GET_MINOR(my_vers->abi_version_0), my_vers->abi_version_1,
  1166. my_vers->abi_version_ns_0, my_vers->abi_version_ns_1,
  1167. my_vers->abi_version_ns_2, my_vers->abi_version_ns_3);
  1168. wmi_tlv_print_verbose
  1169. ("%s: Opposite side WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1170. __func__, WMI_VER_GET_MAJOR(opp_vers->abi_version_0),
  1171. WMI_VER_GET_MINOR(opp_vers->abi_version_0),
  1172. opp_vers->abi_version_1, opp_vers->abi_version_ns_0,
  1173. opp_vers->abi_version_ns_1, opp_vers->abi_version_ns_2,
  1174. opp_vers->abi_version_ns_3);
  1175. /* By default, the output version is our version. */
  1176. wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version));
  1177. if (!wmi_versions_are_compatible(my_vers, opp_vers)) {
  1178. /* Our host version and the given firmware version are incompatible. */
  1179. if (wmi_versions_can_downgrade
  1180. (num_whitelist, version_whitelist_table, my_vers, opp_vers,
  1181. out_vers)) {
  1182. /* We can downgrade our host versions to match firmware. */
  1183. wmi_tlv_print_error
  1184. ("%s: Host downgraded WMI Versions to match fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1185. __func__,
  1186. WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1187. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1188. out_vers->abi_version_1,
  1189. out_vers->abi_version_ns_0,
  1190. out_vers->abi_version_ns_1,
  1191. out_vers->abi_version_ns_2,
  1192. out_vers->abi_version_ns_3);
  1193. return 0; /* Compatible */
  1194. } else {
  1195. /* Warn: We cannot downgrade our host versions to match firmware. */
  1196. wmi_tlv_print_error
  1197. ("%s: WARN: Host WMI Versions mismatch with fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1198. __func__,
  1199. WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1200. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1201. out_vers->abi_version_1,
  1202. out_vers->abi_version_ns_0,
  1203. out_vers->abi_version_ns_1,
  1204. out_vers->abi_version_ns_2,
  1205. out_vers->abi_version_ns_3);
  1206. return 1; /* Incompatible */
  1207. }
  1208. } else {
  1209. /* We are compatible. Our host version is the output version */
  1210. wmi_tlv_print_verbose
  1211. ("%s: Host and FW Compatible WMI Versions. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n",
  1212. __func__, WMI_VER_GET_MAJOR(out_vers->abi_version_0),
  1213. WMI_VER_GET_MINOR(out_vers->abi_version_0),
  1214. out_vers->abi_version_1, out_vers->abi_version_ns_0,
  1215. out_vers->abi_version_ns_1, out_vers->abi_version_ns_2,
  1216. out_vers->abi_version_ns_3);
  1217. return 0; /* Compatible */
  1218. }
  1219. }