target_if_spectral_phyerr.c 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647
  1. /*
  2. * Copyright (c) 2011,2017 The Linux Foundation. All rights reserved.
  3. *
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for
  6. * any purpose with or without fee is hereby granted, provided that the
  7. * above copyright notice and this permission notice appear in all
  8. * copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  11. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  12. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  13. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  14. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  15. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  17. * PERFORMANCE OF THIS SOFTWARE.
  18. */
  19. #include <osdep.h>
  20. #include <qdf_types.h>
  21. #include <wlan_tgt_def_config.h>
  22. #include <hif.h>
  23. #include <hif_hw_version.h>
  24. #include <wmi_unified_api.h>
  25. #include <target_if_spectral.h>
  26. #include <wlan_lmac_if_def.h>
  27. #include <wlan_osif_priv.h>
  28. #ifdef CONFIG_WIN
  29. #include <osif_rawmode_sim.h>
  30. #endif /*CONFIG_WIN*/
  31. #include <reg_services_public_struct.h>
  32. extern int spectral_debug_level;
  33. /* START of spectral GEN II HW specific function declarations */
  34. static int dump_summary_report_gen2(
  35. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  36. int tlvlen,
  37. bool is_160_format);
  38. static int process_search_fft_report_gen2(
  39. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  40. int tlvlen,
  41. SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_fft_info);
  42. static int dump_adc_report_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, int tlvlen);
  43. static int dump_search_fft_report_gen2(
  44. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  45. int tlvlen,
  46. bool is_160_format);
  47. /* END of spectral GEN II HW specific function declarations */
  48. #if WLAN_SPECTRAL_ENABLE
  49. /*
  50. * Function : print_buf
  51. * Description : Prints given buffer for given length
  52. * Input : Pointer to buffer and length
  53. * Output : Void
  54. *
  55. */
  56. static void print_buf(u_int8_t *pbuf, int len)
  57. {
  58. int i = 0;
  59. for (i = 0; i < len; i++) {
  60. qdf_print("%02X ", pbuf[i]);
  61. if (i % 32 == 31)
  62. qdf_print("\n");
  63. }
  64. }
  65. /*
  66. * Function : target_if_spectral_dump_fft
  67. * Description : Dump Spectral FFT
  68. * Input : Pointer to Spectral Phyerr FFT
  69. * Output : Success/Failure
  70. *
  71. */
  72. int target_if_spectral_dump_fft(u_int8_t *pfft, int fftlen)
  73. {
  74. int i = 0;
  75. /* TODO : Do not delete the following print
  76. * The scripts used to validate Spectral depend on this Print
  77. */
  78. qdf_print("SPECTRAL : FFT Length is 0x%x (%d)\n", fftlen, fftlen);
  79. qdf_print("fft_data # ");
  80. for (i = 0; i < fftlen; i++) {
  81. qdf_print("%d ", pfft[i]);
  82. /* if (i % 32 == 31)
  83. * qdf_print("\n");
  84. */
  85. }
  86. qdf_print("\n");
  87. return 0;
  88. }
  89. /*
  90. * Function : target_if_spectral_send_tlv_to_host
  91. * Description : Send the TLV information to Host
  92. * Input : Pointer to the TLV
  93. * Output : Success/Failure
  94. *
  95. */
  96. int target_if_spectral_send_tlv_to_host(
  97. struct target_if_spectral *spectral,
  98. u_int8_t *data,
  99. u_int32_t datalen)
  100. {
  101. int status = true;
  102. target_if_spectral_prep_skb(spectral);
  103. if (spectral->spectral_skb) {
  104. spectral->spectral_nlh =
  105. (struct nlmsghdr *)spectral->spectral_skb->data;
  106. memcpy(NLMSG_DATA(spectral->spectral_nlh), data, datalen);
  107. target_if_spectral_bcast_msg(spectral);
  108. } else {
  109. status = false;
  110. }
  111. return status;
  112. }
  113. /*
  114. * Function : dbg_print_SAMP_param
  115. * Description : Print contents of SAMP struct
  116. * Input : Pointer to SAMP message
  117. * Output : Void
  118. *
  119. */
  120. void target_if_dbg_print_SAMP_param(struct target_if_samp_msg_params *p)
  121. {
  122. qdf_print("\nSAMP Packet : -------------------- START --------------"
  123. "------\n");
  124. qdf_print("Freq = %d\n", p->freq);
  125. qdf_print("RSSI = %d\n", p->rssi);
  126. qdf_print("Bin Count = %d\n", p->pwr_count);
  127. qdf_print("Timestamp = %d\n", p->tstamp);
  128. qdf_print("SAMP Packet : -------------------- END ------------------"
  129. "-----\n");
  130. }
  131. /*
  132. * Function : dbg_print_SAMP_msg
  133. * Description : Print contents of SAMP Message
  134. * Input : Pointer to SAMP message
  135. * Output : Void
  136. *
  137. */
  138. void target_if_dbg_print_SAMP_msg(SPECTRAL_SAMP_MSG *ss_msg)
  139. {
  140. int i = 0;
  141. SPECTRAL_SAMP_DATA *p = &ss_msg->samp_data;
  142. SPECTRAL_CLASSIFIER_PARAMS *pc = &p->classifier_params;
  143. struct INTERF_SRC_RSP *pi = &p->interf_list;
  144. line();
  145. qdf_print("Spectral Message\n");
  146. line();
  147. qdf_print("Signature : 0x%x\n", ss_msg->signature);
  148. qdf_print("Freq : %d\n", ss_msg->freq);
  149. qdf_print("Freq load : %d\n", ss_msg->freq_loading);
  150. qdf_print("Intfnc type : %d\n", ss_msg->int_type);
  151. line();
  152. qdf_print("Spectral Data info\n");
  153. line();
  154. qdf_print("data length : %d\n", p->spectral_data_len);
  155. qdf_print("rssi : %d\n", p->spectral_rssi);
  156. qdf_print("combined rssi : %d\n", p->spectral_combined_rssi);
  157. qdf_print("upper rssi : %d\n", p->spectral_upper_rssi);
  158. qdf_print("lower rssi : %d\n", p->spectral_lower_rssi);
  159. qdf_print("bw info : %d\n", p->spectral_bwinfo);
  160. qdf_print("timestamp : %d\n", p->spectral_tstamp);
  161. qdf_print("max index : %d\n", p->spectral_max_index);
  162. qdf_print("max exp : %d\n", p->spectral_max_exp);
  163. qdf_print("max mag : %d\n", p->spectral_max_mag);
  164. qdf_print("last timstamp : %d\n", p->spectral_last_tstamp);
  165. qdf_print("upper max idx : %d\n", p->spectral_upper_max_index);
  166. qdf_print("lower max idx : %d\n", p->spectral_lower_max_index);
  167. qdf_print("bin power count : %d\n", p->bin_pwr_count);
  168. line();
  169. qdf_print("Classifier info\n");
  170. line();
  171. qdf_print("20/40 Mode : %d\n", pc->spectral_20_40_mode);
  172. qdf_print("dc index : %d\n", pc->spectral_dc_index);
  173. qdf_print("dc in MHz : %d\n", pc->spectral_dc_in_mhz);
  174. qdf_print("upper channel : %d\n", pc->upper_chan_in_mhz);
  175. qdf_print("lower channel : %d\n", pc->lower_chan_in_mhz);
  176. line();
  177. qdf_print("Interference info\n");
  178. line();
  179. qdf_print("inter count : %d\n", pi->count);
  180. for (i = 0; i < pi->count; i++) {
  181. qdf_print("inter type : %d\n", pi->interf[i].interf_type);
  182. qdf_print("min freq : %d\n", pi->interf[i].interf_min_freq);
  183. qdf_print("max freq : %d\n", pi->interf[i].interf_max_freq);
  184. }
  185. }
  186. /*
  187. * Function : get_offset_swar_sec80
  188. * Description : Get offset for SWAR according to the channel width
  189. * Input : Channel width
  190. * Output : Offset for SWAR algorithm
  191. */
  192. uint32_t target_if_get_offset_swar_sec80(uint32_t channel_width)
  193. {
  194. uint32_t offset = 0;
  195. switch (channel_width) {
  196. case CH_WIDTH_20MHZ:
  197. offset = OFFSET_CH_WIDTH_20;
  198. break;
  199. case CH_WIDTH_40MHZ:
  200. offset = OFFSET_CH_WIDTH_40;
  201. break;
  202. case CH_WIDTH_80MHZ:
  203. offset = OFFSET_CH_WIDTH_80;
  204. break;
  205. case CH_WIDTH_160MHZ:
  206. offset = OFFSET_CH_WIDTH_160;
  207. break;
  208. default:
  209. offset = OFFSET_CH_WIDTH_80;
  210. break;
  211. }
  212. return offset;
  213. }
  214. /* START of spectral GEN II HW specific functions */
  215. /*
  216. * Function : dump_summary_report_gen2
  217. * Description : Dump Spectral Summary Report
  218. * Input : Pointer to Spectral Phyerr TLV and Length, flag indicating
  219. * whether information provided by HW is in altered format for
  220. * 802.11ac 160/80+80 MHz support (QCA9984 onwards).
  221. * Output : Success/Failure
  222. *
  223. */
  224. int dump_summary_report_gen2(
  225. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  226. int tlvlen,
  227. bool is_160_format)
  228. {
  229. /* For simplicity, everything is defined as uint32_t (except one).
  230. * Proper code will later use the right sizes.
  231. */
  232. /* For easy comparision between MDK team and OS team, the MDK script
  233. * variable names have been used
  234. */
  235. uint32_t agc_mb_gain;
  236. uint32_t sscan_gidx;
  237. uint32_t agc_total_gain;
  238. uint32_t recent_rfsat;
  239. uint32_t ob_flag;
  240. uint32_t nb_mask;
  241. uint32_t peak_mag;
  242. int16_t peak_inx;
  243. uint32_t ss_summary_A = 0;
  244. uint32_t ss_summary_B = 0;
  245. uint32_t ss_summary_C = 0;
  246. uint32_t ss_summary_D = 0;
  247. uint32_t ss_summary_E = 0;
  248. SPECTRAL_PHYERR_HDR_GEN2 *phdr =
  249. (SPECTRAL_PHYERR_HDR_GEN2 *)((u_int8_t *)ptlv +
  250. sizeof(SPECTRAL_PHYERR_TLV_GEN2));
  251. qdf_print("SPECTRAL : SPECTRAL SUMMARY REPORT\n");
  252. if (is_160_format) {
  253. if (tlvlen != 20) {
  254. qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
  255. "Summary Report! Hexdump follows\n", tlvlen);
  256. print_buf((u_int8_t *)ptlv, tlvlen + 4);
  257. return -EPERM;
  258. }
  259. /* Doing copy as the contents may not be aligned */
  260. qdf_mem_copy(&ss_summary_A, (u_int8_t *)phdr, sizeof(int));
  261. qdf_mem_copy(
  262. &ss_summary_B,
  263. (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
  264. sizeof(int));
  265. qdf_mem_copy(
  266. &ss_summary_C,
  267. (u_int8_t *)((u_int8_t *)phdr + 2 * sizeof(int)),
  268. sizeof(int));
  269. qdf_mem_copy(
  270. &ss_summary_D,
  271. (u_int8_t *)((u_int8_t *)phdr + 3 * sizeof(int)),
  272. sizeof(int));
  273. qdf_mem_copy(
  274. &ss_summary_E,
  275. (u_int8_t *)((u_int8_t *)phdr + 4 * sizeof(int)),
  276. sizeof(int));
  277. /*The following is adapted from MDK scripts for easier comparability */
  278. recent_rfsat = ((ss_summary_A >> 8) & 0x1);
  279. sscan_gidx = (ss_summary_A & 0xff);
  280. qdf_print("sscan_gidx=%d, is_recent_rfsat=%d\n",
  281. sscan_gidx, recent_rfsat);
  282. /* First segment */
  283. agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
  284. agc_total_gain = (ss_summary_B & 0x3ff);
  285. nb_mask = ((ss_summary_C >> 22) & 0xff);
  286. ob_flag = ((ss_summary_B >> 17) & 0x1);
  287. peak_inx = (ss_summary_C & 0xfff);
  288. if (peak_inx > 2047)
  289. peak_inx = peak_inx - 4096;
  290. peak_mag = ((ss_summary_C >> 12) & 0x3ff);
  291. qdf_print("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d\n",
  292. agc_total_gain, agc_mb_gain);
  293. qdf_print("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, "
  294. "peak_index_segid0=%d, peak_mag_segid0=%d\n",
  295. nb_mask, ob_flag, peak_inx, peak_mag);
  296. /* Second segment */
  297. agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
  298. agc_total_gain = (ss_summary_D & 0x3ff);
  299. nb_mask = ((ss_summary_E >> 22) & 0xff);
  300. ob_flag = ((ss_summary_D >> 17) & 0x1);
  301. peak_inx = (ss_summary_E & 0xfff);
  302. if (peak_inx > 2047)
  303. peak_inx = peak_inx - 4096;
  304. peak_mag = ((ss_summary_E >> 12) & 0x3ff);
  305. qdf_print("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d\n",
  306. agc_total_gain, agc_mb_gain);
  307. qdf_print("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, "
  308. "peak_index_segid1=%d, peak_mag_segid1=%d\n",
  309. nb_mask, ob_flag, peak_inx, peak_mag);
  310. } else {
  311. if (tlvlen != 8) {
  312. qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
  313. "Summary Report! Hexdump follows\n", tlvlen);
  314. print_buf((u_int8_t *)ptlv, tlvlen + 4);
  315. return -EPERM;
  316. }
  317. /* Doing copy as the contents may not be aligned */
  318. qdf_mem_copy(&ss_summary_A, (u_int8_t *)phdr, sizeof(int));
  319. qdf_mem_copy(
  320. &ss_summary_B,
  321. (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
  322. sizeof(int));
  323. nb_mask = ((ss_summary_B >> 22) & 0xff);
  324. ob_flag = ((ss_summary_B >> 30) & 0x1);
  325. peak_inx = (ss_summary_B & 0xfff);
  326. if (peak_inx > 2047)
  327. peak_inx = peak_inx - 4096;
  328. peak_mag = ((ss_summary_B >> 12) & 0x3ff);
  329. agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
  330. agc_total_gain = (ss_summary_A & 0x3ff);
  331. sscan_gidx = ((ss_summary_A >> 16) & 0xff);
  332. recent_rfsat = ((ss_summary_B >> 31) & 0x1);
  333. qdf_print("nb_mask = 0x%.2x, ob_flag=%d, peak_index=%d, peak_mag=%d, "
  334. "agc_mb_gain=%d, agc_total_gain=%d, sscan_gidx=%d, "
  335. "recent_rfsat=%d\n",
  336. nb_mask, ob_flag, peak_inx, peak_mag, agc_mb_gain,
  337. agc_total_gain, sscan_gidx, recent_rfsat);
  338. }
  339. return 0;
  340. }
  341. /*
  342. * Function : process_search_fft_report_gen2
  343. * Description : Process Search FFT Report
  344. * Input : Pointer to Spectral Phyerr TLV and Length and pointer to
  345. * search fft info
  346. * Output : Success/Failure
  347. *
  348. */
  349. int process_search_fft_report_gen2(
  350. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  351. int tlvlen,
  352. SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_fft_info)
  353. {
  354. /* For simplicity, everything is defined as uint32_t (except one).
  355. * Proper code will later use the right sizes.
  356. */
  357. /* For easy comparision between MDK team and OS team, the MDK script
  358. * variable names have been used
  359. */
  360. uint32_t relpwr_db;
  361. uint32_t num_str_bins_ib;
  362. uint32_t base_pwr;
  363. uint32_t total_gain_info;
  364. uint32_t fft_chn_idx;
  365. int16_t peak_inx;
  366. uint32_t avgpwr_db;
  367. uint32_t peak_mag;
  368. uint32_t fft_summary_A = 0;
  369. uint32_t fft_summary_B = 0;
  370. u_int8_t *tmp = (u_int8_t *)ptlv;
  371. SPECTRAL_PHYERR_HDR_GEN2 *phdr =
  372. (SPECTRAL_PHYERR_HDR_GEN2 *)(tmp + sizeof(SPECTRAL_PHYERR_TLV_GEN2));
  373. /* Relook this */
  374. if (tlvlen < 8) {
  375. qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
  376. "Summary Report! Hexdump follows\n", tlvlen);
  377. print_buf((u_int8_t *)ptlv, tlvlen + 4);
  378. return -EPERM;
  379. }
  380. /* Doing copy as the contents may not be aligned */
  381. qdf_mem_copy(&fft_summary_A, (u_int8_t *)phdr, sizeof(int));
  382. qdf_mem_copy(
  383. &fft_summary_B,
  384. (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
  385. sizeof(int));
  386. relpwr_db = ((fft_summary_B >> 26) & 0x3f);
  387. num_str_bins_ib = fft_summary_B & 0xff;
  388. base_pwr = ((fft_summary_A >> 14) & 0x1ff);
  389. total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
  390. fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
  391. peak_inx = fft_summary_A & 0xfff;
  392. if (peak_inx > 2047)
  393. peak_inx = peak_inx - 4096;
  394. avgpwr_db = ((fft_summary_B >> 18) & 0xff);
  395. peak_mag = ((fft_summary_B >> 8) & 0x3ff);
  396. /* Populate the Search FFT Info */
  397. if (p_fft_info) {
  398. p_fft_info->relpwr_db = relpwr_db;
  399. p_fft_info->num_str_bins_ib = num_str_bins_ib;
  400. p_fft_info->base_pwr = base_pwr;
  401. p_fft_info->total_gain_info = total_gain_info;
  402. p_fft_info->fft_chn_idx = fft_chn_idx;
  403. p_fft_info->peak_inx = peak_inx;
  404. p_fft_info->avgpwr_db = avgpwr_db;
  405. p_fft_info->peak_mag = peak_mag;
  406. }
  407. return 0;
  408. }
  409. /*
  410. * Function : dump_adc_report_gen2
  411. * Description : Dump ADC Reports
  412. * Input : Pointer to Spectral Phyerr TLV and Length
  413. * Output : Success/Failure
  414. *
  415. */
  416. int dump_adc_report_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, int tlvlen)
  417. {
  418. int i;
  419. uint32_t *pdata;
  420. uint32_t data;
  421. /* For simplicity, everything is defined as uint32_t (except one).
  422. * Proper code will later use the right sizes.
  423. */
  424. uint32_t samp_fmt;
  425. uint32_t chn_idx;
  426. uint32_t recent_rfsat;
  427. uint32_t agc_mb_gain;
  428. uint32_t agc_total_gain;
  429. uint32_t adc_summary = 0;
  430. u_int8_t *ptmp = (u_int8_t *)ptlv;
  431. qdf_print("SPECTRAL : ADC REPORT\n");
  432. /* Relook this */
  433. if (tlvlen < 4) {
  434. qdf_print("Unexpected TLV length %d for ADC Report! Hexdump"
  435. " follows\n", tlvlen);
  436. print_buf((u_int8_t *)ptlv, tlvlen + 4);
  437. return -EPERM;
  438. }
  439. qdf_mem_copy(&adc_summary, (u_int8_t *)(ptlv + 4), sizeof(int));
  440. samp_fmt = ((adc_summary >> 28) & 0x1);
  441. chn_idx = ((adc_summary >> 24) & 0x3);
  442. recent_rfsat = ((adc_summary >> 23) & 0x1);
  443. agc_mb_gain = ((adc_summary >> 16) & 0x7f);
  444. agc_total_gain = adc_summary & 0x3ff;
  445. qdf_print("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u"
  446. " agc_total_gain=%u\n", samp_fmt, chn_idx, recent_rfsat,
  447. agc_mb_gain, agc_total_gain);
  448. for (i = 0; i < (tlvlen / 4); i++) {
  449. pdata = (uint32_t *)(ptmp + 4 + i * 4);
  450. data = *pdata;
  451. /* Interpreting capture format 1 */
  452. if (1) {
  453. uint8_t i1;
  454. uint8_t q1;
  455. uint8_t i2;
  456. uint8_t q2;
  457. int8_t si1;
  458. int8_t sq1;
  459. int8_t si2;
  460. int8_t sq2;
  461. i1 = data & 0xff;
  462. q1 = (data >> 8) & 0xff;
  463. i2 = (data >> 16) & 0xff;
  464. q2 = (data >> 24) & 0xff;
  465. if (i1 > 127)
  466. si1 = i1 - 256;
  467. else
  468. si1 = i1;
  469. if (q1 > 127)
  470. sq1 = q1 - 256;
  471. else
  472. sq1 = q1;
  473. if (i2 > 127)
  474. si2 = i2 - 256;
  475. else
  476. si2 = i2;
  477. if (q2 > 127)
  478. sq2 = q2 - 256;
  479. else
  480. sq2 = q2;
  481. qdf_print("SPECTRAL ADC : Interpreting capture format 1\n");
  482. qdf_print("adc_data_format_1 # %d %d %d\n", 2 * i, si1, sq1);
  483. qdf_print("adc_data_format_1 # %d %d %d\n",
  484. 2 * i + 1, si2, sq2);
  485. }
  486. /* Interpreting capture format 0 */
  487. if (1) {
  488. uint16_t i1;
  489. uint16_t q1;
  490. int16_t si1;
  491. int16_t sq1;
  492. i1 = data & 0xffff;
  493. q1 = (data >> 16) & 0xffff;
  494. if (i1 > 32767)
  495. si1 = i1 - 65536;
  496. else
  497. si1 = i1;
  498. if (q1 > 32767)
  499. sq1 = q1 - 65536;
  500. else
  501. sq1 = q1;
  502. qdf_print("SPECTRAL ADC : Interpreting capture format 0\n");
  503. qdf_print("adc_data_format_2 # %d %d %d\n", i, si1, sq1);
  504. }
  505. }
  506. qdf_print("\n");
  507. return 0;
  508. }
  509. /*
  510. * Function : dump_search_fft_report_gen2
  511. * Description : Process Search FFT Report
  512. * Input : Pointer to Spectral Phyerr TLV and Length, flag indicating
  513. * whether information provided by HW is in altered format for
  514. * 802.11ac 160/80+80 MHz support (QCA9984 onwards).
  515. * Output : Success/Failure
  516. *
  517. */
  518. int dump_search_fft_report_gen2(
  519. SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
  520. int tlvlen,
  521. bool is_160_format)
  522. {
  523. int i;
  524. uint32_t fft_mag;
  525. /* For simplicity, everything is defined as uint32_t (except one).
  526. * Proper code will later use the right sizes.
  527. */
  528. /* For easy comparision between MDK team and OS team, the MDK script
  529. * variable names have been used
  530. */
  531. uint32_t relpwr_db;
  532. uint32_t num_str_bins_ib;
  533. uint32_t base_pwr;
  534. uint32_t total_gain_info;
  535. uint32_t fft_chn_idx;
  536. int16_t peak_inx;
  537. uint32_t avgpwr_db;
  538. uint32_t peak_mag;
  539. u_int8_t segid;
  540. uint32_t fft_summary_A = 0;
  541. uint32_t fft_summary_B = 0;
  542. uint32_t fft_summary_C = 0;
  543. u_int8_t *tmp = (u_int8_t *)ptlv;
  544. SPECTRAL_PHYERR_HDR_GEN2 *phdr =
  545. (SPECTRAL_PHYERR_HDR_GEN2 *)(tmp + sizeof(SPECTRAL_PHYERR_TLV_GEN2));
  546. u_int32_t segid_skiplen = 0;
  547. if (is_160_format)
  548. segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
  549. qdf_print("SPECTRAL : SEARCH FFT REPORT\n");
  550. /* Relook this */
  551. if (tlvlen < (8 + segid_skiplen)) {
  552. qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
  553. "Summary Report! Hexdump follows\n", tlvlen);
  554. print_buf((u_int8_t *)ptlv, tlvlen + 4);
  555. return -EPERM;
  556. }
  557. /* Doing copy as the contents may not be aligned */
  558. qdf_mem_copy(&fft_summary_A, (u_int8_t *)phdr, sizeof(int));
  559. qdf_mem_copy(
  560. &fft_summary_B,
  561. (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
  562. sizeof(int));
  563. if (is_160_format)
  564. qdf_mem_copy(
  565. &fft_summary_C,
  566. (u_int8_t *)((u_int8_t *)phdr + 2 * sizeof(int)),
  567. sizeof(int));
  568. relpwr_db = ((fft_summary_B >> 26) & 0x3f);
  569. num_str_bins_ib = fft_summary_B & 0xff;
  570. base_pwr = ((fft_summary_A >> 14) & 0x1ff);
  571. total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
  572. fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
  573. peak_inx = fft_summary_A & 0xfff;
  574. if (peak_inx > 2047)
  575. peak_inx = peak_inx - 4096;
  576. avgpwr_db = ((fft_summary_B >> 18) & 0xff);
  577. peak_mag = ((fft_summary_B >> 8) & 0x3ff);
  578. qdf_print("Header A = 0x%x Header B = 0x%x\n",
  579. phdr->hdr_a, phdr->hdr_b);
  580. qdf_print("Base Power= 0x%x, Total Gain= %d, relpwr_db=%d, "
  581. "num_str_bins_ib=%d fft_chn_idx=%d peak_inx=%d avgpwr_db=%d "
  582. "peak_mag=%d\n", base_pwr, total_gain_info, relpwr_db,
  583. num_str_bins_ib, fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
  584. if (is_160_format) {
  585. segid = fft_summary_C & 0x1;
  586. qdf_print("Segment ID: %hhu\n", segid);
  587. }
  588. qdf_print("FFT bins:\n");
  589. for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
  590. fft_mag = ((u_int8_t *)ptlv)[12 + segid_skiplen + i];
  591. qdf_print("%d %d, ", i, fft_mag);
  592. }
  593. qdf_print("\n");
  594. return 0;
  595. }
  596. /*
  597. * Function : spectral_process_phyerr_gen2
  598. * Description : Process PHY Error
  599. * Input : Pointer to buffer
  600. * Output : Success/Failure
  601. *
  602. */
  603. int spectral_process_phyerr_gen2(
  604. struct target_if_spectral *spectral,
  605. u_int8_t *data,
  606. u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
  607. struct target_if_spectral_chan_info *p_chaninfo,
  608. u_int64_t tsf64,
  609. struct target_if_spectral_acs_stats *acs_stats)
  610. {
  611. /*
  612. * XXX : The classifier do not use all the members of the SAMP
  613. * message data format.
  614. * The classifier only depends upon the following parameters
  615. *
  616. * 1. Frequency (freq, msg->freq)
  617. * 2. Spectral RSSI (spectral_rssi,
  618. * msg->samp_data.spectral_rssi)
  619. * 3. Bin Power Count (bin_pwr_count,
  620. * msg->samp_data.bin_pwr_count)
  621. * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
  622. * 5. Spectral Timestamp (spectral_tstamp,
  623. * msg->samp_data.spectral_tstamp)
  624. * 6. MAC Address (macaddr, msg->macaddr)
  625. *
  626. * This function prepares the params structure and populates it
  627. * with
  628. * relevant values, this is in turn passed to
  629. * spectral_create_samp_msg()
  630. * to prepare fully formatted Spectral SAMP message
  631. *
  632. * XXX : Need to verify
  633. * 1. Order of FFT bin values
  634. *
  635. */
  636. struct target_if_samp_msg_params params;
  637. SPECTRAL_SEARCH_FFT_INFO_GEN2 search_fft_info;
  638. SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft = &search_fft_info;
  639. SPECTRAL_SEARCH_FFT_INFO_GEN2 search_fft_info_sec80;
  640. SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft_sec80 = &search_fft_info_sec80;
  641. u_int32_t segid_skiplen = 0;
  642. int8_t rssi_up = 0;
  643. int8_t rssi_low = 0;
  644. int8_t chn_idx_highest_enabled = 0;
  645. int8_t chn_idx_lowest_enabled = 0;
  646. u_int8_t control_rssi = 0;
  647. u_int8_t extension_rssi = 0;
  648. u_int8_t combined_rssi = 0;
  649. u_int32_t tstamp = 0;
  650. struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
  651. SPECTRAL_PHYERR_TLV_GEN2 *ptlv = (SPECTRAL_PHYERR_TLV_GEN2 *)data;
  652. SPECTRAL_PHYERR_TLV_GEN2 *ptlv_sec80 = NULL;
  653. SPECTRAL_PHYERR_FFT_GEN2 *pfft = NULL;
  654. SPECTRAL_PHYERR_FFT_GEN2 *pfft_sec80 = NULL;
  655. u_int8_t segid = 0;
  656. u_int8_t segid_sec80 = 0;
  657. if (spectral->is_160_format)
  658. segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
  659. pfft = (SPECTRAL_PHYERR_FFT_GEN2 *)(data +
  660. sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  661. sizeof(SPECTRAL_PHYERR_HDR_GEN2) + segid_skiplen);
  662. /* XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
  663. * and use this facility inside spectral_dump_phyerr_data()
  664. * and supporting functions.
  665. */
  666. if (spectral_debug_level & ATH_DEBUG_SPECTRAL2)
  667. spectral_dump_phyerr_data_gen2(data, datalen, spectral->is_160_format);
  668. if (spectral_debug_level & ATH_DEBUG_SPECTRAL4) {
  669. spectral_dump_phyerr_data_gen2(data, datalen, spectral->is_160_format);
  670. spectral_debug_level = ATH_DEBUG_SPECTRAL;
  671. }
  672. if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
  673. /* EV# 118023: We tentatively disable the below print
  674. * and provide stats instead.
  675. */
  676. /* qdf_print("SPECTRAL : Mismatch\n"); */
  677. spectral->diag_stats.spectral_mismatch++;
  678. return -EPERM;
  679. }
  680. OS_MEMZERO(&params, sizeof(params));
  681. if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
  682. if (spectral->is_160_format) {
  683. segid = *((SPECTRAL_SEGID_INFO *)(
  684. (u_int8_t *)ptlv +
  685. sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  686. sizeof(SPECTRAL_PHYERR_HDR_GEN2)));
  687. if (segid != 0) {
  688. spectral->diag_stats.spectral_vhtseg1id_mismatch++;
  689. return -EPERM;
  690. }
  691. }
  692. process_search_fft_report_gen2(ptlv, ptlv->length, &search_fft_info);
  693. tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
  694. combined_rssi = p_rfqual->rssi_comb;
  695. if (spectral->upper_is_control)
  696. rssi_up = control_rssi;
  697. else
  698. rssi_up = extension_rssi;
  699. if (spectral->lower_is_control)
  700. rssi_low = control_rssi;
  701. else
  702. rssi_low = extension_rssi;
  703. params.rssi = p_rfqual->rssi_comb;
  704. params.lower_rssi = rssi_low;
  705. params.upper_rssi = rssi_up;
  706. if (spectral->sc_spectral_noise_pwr_cal) {
  707. params.chain_ctl_rssi[0] =
  708. p_rfqual->pc_rssi_info[0].rssi_pri20;
  709. params.chain_ctl_rssi[1] =
  710. p_rfqual->pc_rssi_info[1].rssi_pri20;
  711. params.chain_ctl_rssi[2] =
  712. p_rfqual->pc_rssi_info[2].rssi_pri20;
  713. params.chain_ext_rssi[0] =
  714. p_rfqual->pc_rssi_info[0].rssi_sec20;
  715. params.chain_ext_rssi[1] =
  716. p_rfqual->pc_rssi_info[1].rssi_sec20;
  717. params.chain_ext_rssi[2] =
  718. p_rfqual->pc_rssi_info[2].rssi_sec20;
  719. }
  720. /*
  721. * XXX : This actually depends on the programmed chain mask
  722. * There are three chains in Peregrine and 4 chains in Beeliner &
  723. * Cascade
  724. * This value decides the per-chain enable mask to select
  725. * the input ADC for search FTT.
  726. * For modes upto VHT80, if more than one chain is enabled, the
  727. * max valid chain
  728. * is used. LSB corresponds to chain zero.
  729. * For VHT80_80 and VHT160, the lowest enabled chain is used for
  730. * primary
  731. * detection and highest enabled chain is used for secondary
  732. * detection.
  733. *
  734. * XXX: The current algorithm do not use these control and extension
  735. * channel
  736. * Instead, it just relies on the combined RSSI values only.
  737. * For fool-proof detection algorithm, we should take these RSSI
  738. * values
  739. * in to account. This is marked for future enhancements.
  740. */
  741. chn_idx_highest_enabled = ((spectral->params.ss_chn_mask & 0x8) ? 3 :
  742. (spectral->params.ss_chn_mask & 0x4) ? 2 :
  743. (spectral->params.ss_chn_mask & 0x2) ? 1 : 0);
  744. chn_idx_lowest_enabled = ((spectral->params.ss_chn_mask & 0x1) ? 0 :
  745. (spectral->params.ss_chn_mask & 0x2) ? 1 :
  746. (spectral->params.ss_chn_mask & 0x4) ? 2 : 3);
  747. control_rssi = (u_int8_t)
  748. p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
  749. extension_rssi = (u_int8_t)
  750. p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
  751. params.bwinfo = 0;
  752. params.tstamp = 0;
  753. params.max_mag = p_sfft->peak_mag;
  754. params.max_index = p_sfft->peak_inx;
  755. params.max_exp = 0;
  756. params.peak = 0;
  757. params.bin_pwr_data = (u_int8_t *)pfft;
  758. params.freq = p_sops->get_current_channel(spectral);
  759. params.freq_loading = 0;
  760. params.interf_list.count = 0;
  761. params.max_lower_index = 0;
  762. params.max_upper_index = 0;
  763. params.nb_lower = 0;
  764. params.nb_upper = 0;
  765. /*
  766. * For modes upto VHT80, the noise floor is populated with the one
  767. * corresponding
  768. * to the highest enabled antenna chain
  769. */
  770. params.noise_floor =
  771. p_rfqual->noise_floor[chn_idx_highest_enabled];
  772. params.datalen = ptlv->length;
  773. params.pwr_count = ptlv->length -
  774. sizeof(SPECTRAL_PHYERR_HDR_GEN2) - segid_skiplen;
  775. params.tstamp = (tsf64 & SPECTRAL_TSMASK);
  776. acs_stats->ctrl_nf = params.noise_floor;
  777. acs_stats->ext_nf = params.noise_floor;
  778. acs_stats->nfc_ctl_rssi = control_rssi;
  779. acs_stats->nfc_ext_rssi = extension_rssi;
  780. if (spectral->is_160_format &&
  781. spectral->ch_width == CH_WIDTH_160MHZ) {
  782. /* We expect to see one more Search FFT report, and it should
  783. * be equal in size to the current one.
  784. */
  785. if (datalen < (2 * (sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  786. ptlv->length))) {
  787. spectral->diag_stats.spectral_sec80_sfft_insufflen++;
  788. return -EPERM;
  789. }
  790. ptlv_sec80 = (SPECTRAL_PHYERR_TLV_GEN2 *)(
  791. data +
  792. sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  793. ptlv->length);
  794. if (ptlv_sec80->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
  795. spectral->diag_stats.spectral_mismatch++;
  796. return -EPERM;
  797. }
  798. if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
  799. spectral->diag_stats.spectral_no_sec80_sfft++;
  800. return -EPERM;
  801. }
  802. segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
  803. (u_int8_t *)ptlv_sec80 +
  804. sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  805. sizeof(SPECTRAL_PHYERR_HDR_GEN2)));
  806. if (segid_sec80 != 1) {
  807. spectral->diag_stats.spectral_vhtseg2id_mismatch++;
  808. return -EPERM;
  809. }
  810. params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
  811. params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
  812. process_search_fft_report_gen2(
  813. ptlv_sec80,
  814. ptlv_sec80->length, &search_fft_info_sec80);
  815. pfft_sec80 = (SPECTRAL_PHYERR_FFT_GEN2 *)(
  816. ((u_int8_t *)ptlv_sec80) +
  817. sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  818. sizeof(SPECTRAL_PHYERR_HDR_GEN2) +
  819. segid_skiplen);
  820. /* XXX: Confirm. TBD at SoD. */
  821. params.rssi_sec80 = p_rfqual->rssi_comb;
  822. if (spectral->is_sec80_rssi_war_required)
  823. params.rssi_sec80 =
  824. get_combined_rssi_sec80_segment_gen2(
  825. spectral,
  826. &search_fft_info_sec80);
  827. /* XXX: Determine dynamically. TBD at SoD. */
  828. /*
  829. * For VHT80_80/VHT160, the noise floor for primary 80MHz
  830. * segment is populated with the
  831. * lowest enabled antenna chain and the noise floor for
  832. * secondary 80MHz segment is populated
  833. * with the highest enabled antenna chain
  834. */
  835. params.noise_floor_sec80 =
  836. p_rfqual->noise_floor[chn_idx_highest_enabled];
  837. params.noise_floor =
  838. p_rfqual->noise_floor[chn_idx_lowest_enabled];
  839. params.max_mag_sec80 = p_sfft_sec80->peak_mag;
  840. params.max_index_sec80 = p_sfft_sec80->peak_inx;
  841. /* XXX Does this definition of datalen *still hold? */
  842. params.datalen_sec80 = ptlv_sec80->length;
  843. params.pwr_count_sec80 =
  844. ptlv_sec80->length -
  845. sizeof(SPECTRAL_PHYERR_HDR_GEN2) -
  846. segid_skiplen;
  847. params.bin_pwr_data_sec80 = (u_int8_t *)pfft_sec80;
  848. }
  849. qdf_mem_copy(
  850. &params.classifier_params,
  851. &spectral->classifier_params,
  852. sizeof(struct spectral_classifier_params));
  853. #ifdef SPECTRAL_DEBUG_SAMP_MSG
  854. target_if_dbg_print_SAMP_param(&params);
  855. #endif
  856. target_if_spectral_create_samp_msg(spectral, &params);
  857. }
  858. return 0;
  859. }
  860. /*
  861. * Function : spectral_dump_header_gen2
  862. * Description : Dump Spectral header
  863. * Input : Pointer to Spectral Phyerr Header
  864. * Output : Success/Failure
  865. *
  866. */
  867. int spectral_dump_header_gen2(SPECTRAL_PHYERR_HDR_GEN2 *phdr)
  868. {
  869. u_int32_t a = 0;
  870. u_int32_t b = 0;
  871. qdf_mem_copy(&a, (u_int8_t *)phdr, sizeof(int));
  872. qdf_mem_copy(
  873. &b,
  874. (u_int8_t *)((u_int8_t *)phdr + sizeof(int)), sizeof(int));
  875. qdf_print("SPECTRAL : HEADER A 0x%x (%d)\n", a, a);
  876. qdf_print("SPECTRAL : HEADER B 0x%x (%d)\n", b, b);
  877. return 0;
  878. }
  879. /*
  880. * Function : get_combined_rssi_sec80_segment_gen2
  881. * Description : Get approximate combined RSSI for Secondary 80 segment
  882. * Input : Pointer to spectral and pointer to search fft info
  883. * of secondary 80 segment
  884. * Output : Combined RSSI for secondary 80Mhz segment
  885. *
  886. */
  887. int8_t get_combined_rssi_sec80_segment_gen2(
  888. struct target_if_spectral *spectral,
  889. SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft_sec80)
  890. {
  891. uint32_t avgpwr_db = 0;
  892. uint32_t total_gain_db = 0;
  893. uint32_t offset = 0;
  894. int8_t comb_rssi = 0;
  895. /* Obtain required parameters for algorithm from search FFT report */
  896. avgpwr_db = p_sfft_sec80->avgpwr_db;
  897. total_gain_db = p_sfft_sec80->total_gain_info;
  898. /* Calculate offset */
  899. offset = target_if_get_offset_swar_sec80(spectral->ch_width);
  900. /* Calculate RSSI */
  901. comb_rssi = ((avgpwr_db - total_gain_db) + offset);
  902. return comb_rssi;
  903. }
  904. /*
  905. * Function : spectral_dump_tlv_gen2
  906. * Description : Dump Spectral TLV
  907. * Input : Pointer to Spectral Phyerr TLV, flag indicating whether
  908. * information provided by HW is in altered format for 802.11ac
  909. * 160/80+80 MHz support (QCA9984 onwards).
  910. * Output : Success/Failure
  911. *
  912. */
  913. int spectral_dump_tlv_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, bool is_160_format)
  914. {
  915. int ret = 0;
  916. /* TODO : Do not delete the following print
  917. * The scripts used to validate Spectral depend on this Print
  918. */
  919. qdf_print("SPECTRAL : TLV Length is 0x%x (%d)\n",
  920. ptlv->length, ptlv->length);
  921. switch (ptlv->tag) {
  922. case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
  923. ret = dump_summary_report_gen2(
  924. ptlv, ptlv->length, is_160_format);
  925. break;
  926. case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
  927. ret = dump_search_fft_report_gen2(
  928. ptlv, ptlv->length, is_160_format);
  929. break;
  930. case TLV_TAG_ADC_REPORT_GEN2:
  931. ret = dump_adc_report_gen2(
  932. ptlv, ptlv->length);
  933. break;
  934. default:
  935. qdf_print("SPECTRAL : INVALID TLV\n");
  936. ret = -1;
  937. break;
  938. }
  939. return ret;
  940. }
  941. /*
  942. * Function : spectral_dump_phyerr_data_gen2
  943. * Description : Dump Spectral related PHY Error TLVs
  944. * Input : Pointer to buffer, flag indicating whether information
  945. * provided by HW is in altered format for 802.11ac 160/80+80 MHz
  946. * support (QCA9984 onwards).
  947. * Output : Success/Failure
  948. *
  949. */
  950. int spectral_dump_phyerr_data_gen2(u_int8_t *data, u_int32_t datalen,
  951. bool is_160_format)
  952. {
  953. SPECTRAL_PHYERR_TLV_GEN2 *ptlv = NULL;
  954. u_int32_t bytes_processed = 0;
  955. u_int32_t bytes_remaining = datalen;
  956. u_int32_t curr_tlv_complete_size = 0;
  957. if (datalen < sizeof(SPECTRAL_PHYERR_TLV_GEN2)) {
  958. qdf_print("DRIVER: Total PHY error data length %u too short to contain"
  959. " any TLVs\n", datalen);
  960. return -EPERM;
  961. }
  962. while (bytes_processed < datalen) {
  963. if (bytes_remaining < sizeof(SPECTRAL_PHYERR_TLV_GEN2)) {
  964. qdf_print("DRIVER: Remaining PHY error data length %u too "
  965. "short to contain a TLV\n", bytes_remaining);
  966. return -EPERM;
  967. }
  968. ptlv = (SPECTRAL_PHYERR_TLV_GEN2 *)(data + bytes_processed);
  969. if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
  970. qdf_print("DRIVER : Invalid signature 0x%x!\n",
  971. ptlv->signature);
  972. return -EPERM;
  973. }
  974. curr_tlv_complete_size = sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
  975. ptlv->length;
  976. if (curr_tlv_complete_size > bytes_remaining) {
  977. qdf_print("DRIVER : Current indicated complete TLV size %u "
  978. "greater than number of bytes remaining to be "
  979. "processed %u",
  980. curr_tlv_complete_size,
  981. bytes_remaining);
  982. return -EPERM;
  983. }
  984. if (spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
  985. return -EPERM;
  986. bytes_processed += curr_tlv_complete_size;
  987. bytes_remaining = datalen - bytes_processed;
  988. }
  989. return 0;
  990. }
  991. /* END of spectral GEN II HW specific functions */
  992. /* START of spectral GEN III HW specific functions */
  993. /*
  994. * Function : process_search_fft_report_gen3
  995. * Description : Process Search FFT Report
  996. * Input : Pointer to Spectral fft report and pointer to search fft info
  997. * Output : Success/Failure
  998. *
  999. */
  1000. int process_search_fft_report_gen3(
  1001. struct spectral_phyerr_fft_report_gen3 *p_fft_report,
  1002. struct spectral_search_fft_info_gen3 *p_sfft)
  1003. {
  1004. /* For simplicity, everything is defined as uint32_t (except one).
  1005. * Proper code will later use the right sizes.
  1006. */
  1007. /* For easy comparision between MDK team and OS team, the MDK script
  1008. * variable names have been used
  1009. */
  1010. int32_t peak_sidx;
  1011. int32_t peak_mag;
  1012. /* Populate the Search FFT Info */
  1013. if (p_sfft) {
  1014. p_sfft->timestamp = p_fft_report->fft_timestamp;
  1015. p_sfft->fft_detector_id = get_bitfield(
  1016. p_fft_report->hdr_a,
  1017. 2,
  1018. 0);
  1019. p_sfft->fft_num = get_bitfield(
  1020. p_fft_report->hdr_a,
  1021. 3,
  1022. 2);
  1023. p_sfft->fft_radar_check = get_bitfield(
  1024. p_fft_report->hdr_a,
  1025. 12,
  1026. 5);
  1027. peak_sidx = get_bitfield(
  1028. p_fft_report->hdr_a,
  1029. 11,
  1030. 17);
  1031. p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
  1032. p_sfft->fft_chn_idx = get_bitfield(
  1033. p_fft_report->hdr_a,
  1034. 3,
  1035. 28);
  1036. p_sfft->fft_base_pwr_db = get_bitfield(
  1037. p_fft_report->hdr_b,
  1038. 9,
  1039. 0);
  1040. p_sfft->fft_total_gain_db = get_bitfield(
  1041. p_fft_report->hdr_b,
  1042. 8,
  1043. 9);
  1044. p_sfft->fft_num_str_bins_ib = get_bitfield(
  1045. p_fft_report->hdr_c,
  1046. 8,
  1047. 0);
  1048. peak_mag = get_bitfield(
  1049. p_fft_report->hdr_c,
  1050. 10,
  1051. 8);
  1052. p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
  1053. p_sfft->fft_avgpwr_db = get_bitfield(
  1054. p_fft_report->hdr_c,
  1055. 7,
  1056. 18);
  1057. p_sfft->fft_relpwr_db = get_bitfield(
  1058. p_fft_report->hdr_c,
  1059. 7,
  1060. 25);
  1061. }
  1062. return 0;
  1063. }
  1064. /*
  1065. * Function : spectral_dump_fft_report_gen3
  1066. * Description : Process Search FFT Report
  1067. * Input : Pointer to Spectral fft report and pointer to search fft info
  1068. * Output : Success/Failure
  1069. *
  1070. */
  1071. int spectral_dump_fft_report_gen3(
  1072. struct spectral_phyerr_fft_report_gen3 *p_fft_report,
  1073. struct spectral_search_fft_info_gen3 *p_sfft)
  1074. {
  1075. int i = 0;
  1076. int fft_mag = 0;
  1077. int fft_hdr_length = (p_fft_report->fft_hdr_length * 4);
  1078. int report_len = (fft_hdr_length + 8);
  1079. int fft_bin_len = (fft_hdr_length - 16);
  1080. qdf_print("##############################################"
  1081. "###############\n");
  1082. qdf_print("Spectral search fft_report\n");
  1083. qdf_print("fft_timestamp = 0x%x\n"
  1084. "fft_hdr_length = %d(32 bit words)\n"
  1085. "fft_hdr_tag = 0x%x\n"
  1086. "fft_hdr_sig = 0x%x\n",
  1087. p_fft_report->fft_timestamp,
  1088. p_fft_report->fft_hdr_length,
  1089. p_fft_report->fft_hdr_tag,
  1090. p_fft_report->fft_hdr_sig);
  1091. qdf_print("Length field in search fft report is %d(0x%x) bytes\n",
  1092. fft_hdr_length, fft_hdr_length);
  1093. qdf_print("Total length of search fft report is %d(0x%x) bytes\n",
  1094. report_len, report_len);
  1095. qdf_print("Number of fftbins in report is %d(0x%x)\n", fft_bin_len,
  1096. fft_bin_len);
  1097. qdf_print("fft_detector_id = %u\n"
  1098. "fft_num = %u\n"
  1099. "fft_radar_check = %u\n"
  1100. "fft_peak_sidx = %d\n"
  1101. "fft_chn_idx = %u\n"
  1102. "fft_base_pwr_db = %u\n"
  1103. "fft_total_gain_db = %u\n"
  1104. "fft_num_str_bins_ib = %u\n"
  1105. "fft_peak_mag = %d\n"
  1106. "fft_avgpwr_db = %u\n"
  1107. "fft_relpwr_db = %u\n",
  1108. p_sfft->fft_detector_id,
  1109. p_sfft->fft_num,
  1110. p_sfft->fft_radar_check,
  1111. p_sfft->fft_peak_sidx,
  1112. p_sfft->fft_chn_idx,
  1113. p_sfft->fft_base_pwr_db,
  1114. p_sfft->fft_total_gain_db,
  1115. p_sfft->fft_num_str_bins_ib,
  1116. p_sfft->fft_peak_mag,
  1117. p_sfft->fft_avgpwr_db,
  1118. p_sfft->fft_relpwr_db);
  1119. qdf_print("FFT bins:\n");
  1120. for (i = 0; i < (fft_hdr_length - 16); i++) {
  1121. fft_mag = ((u_int8_t *)p_fft_report)[SPECTRAL_FFT_BINS_POS + i];
  1122. qdf_print("%d: %d, ", i, fft_mag);
  1123. if (i % 16 == 0)
  1124. qdf_print("\n");
  1125. }
  1126. qdf_print("\n");
  1127. qdf_print("###########################################################"
  1128. "##\n");
  1129. return 0;
  1130. }
  1131. static int consume_searchfft_report_gen3(
  1132. struct target_if_spectral *spectral,
  1133. struct phyerr_info *pinfo)
  1134. {
  1135. /*
  1136. * XXX : The classifier do not use all the members of the SAMP
  1137. * message data format.
  1138. * The classifier only depends upon the following parameters
  1139. *
  1140. * 1. Frequency (freq, msg->freq)
  1141. * 2. Spectral RSSI (spectral_rssi,
  1142. * msg->samp_data.spectral_rssi)
  1143. * 3. Bin Power Count (bin_pwr_count,
  1144. * msg->samp_data.bin_pwr_count)
  1145. * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
  1146. * 5. Spectral Timestamp (spectral_tstamp,
  1147. * msg->samp_data.spectral_tstamp)
  1148. * 6. MAC Address (macaddr, msg->macaddr)
  1149. *
  1150. * This function prepares the params structure and populates it
  1151. * with
  1152. * relevant values, this is in turn passed to
  1153. * spectral_create_samp_msg()
  1154. * to prepare fully formatted Spectral SAMP message
  1155. *
  1156. * XXX : Need to verify
  1157. * 1. Order of FFT bin values
  1158. *
  1159. */
  1160. /* Unpack the arguments */
  1161. u_int32_t datalen = pinfo->datalen;
  1162. struct target_if_spectral_rfqual_info *p_rfqual = pinfo->p_rfqual;
  1163. struct target_if_spectral_chan_info *p_chaninfo = pinfo->p_chaninfo;
  1164. u_int64_t tsf64 = pinfo->tsf64;
  1165. struct target_if_spectral_acs_stats *acs_stats = pinfo->acs_stats;
  1166. struct target_if_samp_msg_params params;
  1167. struct spectral_search_fft_info_gen3 search_fft_info;
  1168. struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
  1169. int8_t rssi_up = 0;
  1170. int8_t rssi_low = 0;
  1171. int8_t chn_idx_highest_enabled = 0;
  1172. int8_t chn_idx_lowest_enabled = 0;
  1173. u_int8_t control_rssi = 0;
  1174. u_int8_t extension_rssi = 0;
  1175. u_int32_t tstamp = 0;
  1176. int fft_hdr_length = 0;
  1177. int report_len = 0;
  1178. int fft_bin_len = 0;
  1179. struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
  1180. struct spectral_phyerr_fft_report_gen3 *p_fft_report =
  1181. (struct spectral_phyerr_fft_report_gen3 *)(pinfo->data);
  1182. OS_MEMZERO(&params, sizeof(params));
  1183. fft_hdr_length = p_fft_report->fft_hdr_length * 4;
  1184. if (fft_hdr_length < 16) {
  1185. qdf_print("SPECTRAL : Unexpected TLV length %u for FFT Report! Hexdump"
  1186. " follows\n", fft_hdr_length);
  1187. goto fail;
  1188. }
  1189. report_len = (fft_hdr_length + 8);
  1190. fft_bin_len = (fft_hdr_length - 16);
  1191. if (datalen < report_len) {
  1192. qdf_print("DRIVER: Total PHY error data length %u too short to"
  1193. " contain the search fft report of length %u\n",
  1194. datalen, report_len);
  1195. goto fail;
  1196. }
  1197. process_search_fft_report_gen3(p_fft_report, p_sfft);
  1198. if (p_sfft->fft_detector_id != 0) {
  1199. qdf_print("Expected segid is 0 but we got %d\n",
  1200. p_sfft->fft_detector_id);
  1201. spectral->diag_stats.spectral_vhtseg1id_mismatch++;
  1202. goto fail;
  1203. }
  1204. if (spectral_debug_level & (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4))
  1205. spectral_dump_fft_report_gen3(p_fft_report, p_sfft);
  1206. tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
  1207. if (spectral->upper_is_control)
  1208. rssi_up = control_rssi;
  1209. else
  1210. rssi_up = extension_rssi;
  1211. if (spectral->lower_is_control)
  1212. rssi_low = control_rssi;
  1213. else
  1214. rssi_low = extension_rssi;
  1215. params.rssi = p_rfqual->rssi_comb;
  1216. params.lower_rssi = rssi_low;
  1217. params.upper_rssi = rssi_up;
  1218. if (spectral->sc_spectral_noise_pwr_cal) {
  1219. /* qdf_print("SPECTRAL : Needs to verified with FW\n"); */
  1220. params.chain_ctl_rssi[0] = p_rfqual->pc_rssi_info[0].rssi_pri20;
  1221. params.chain_ctl_rssi[1] = p_rfqual->pc_rssi_info[1].rssi_pri20;
  1222. params.chain_ctl_rssi[2] = p_rfqual->pc_rssi_info[2].rssi_pri20;
  1223. params.chain_ext_rssi[0] = p_rfqual->pc_rssi_info[0].rssi_sec20;
  1224. params.chain_ext_rssi[1] = p_rfqual->pc_rssi_info[1].rssi_sec20;
  1225. params.chain_ext_rssi[2] = p_rfqual->pc_rssi_info[2].rssi_sec20;
  1226. }
  1227. /*
  1228. * XXX : This actually depends on the programmed chain mask
  1229. * There are three chains in Peregrine and 4 chains in Beeliner &
  1230. * Cascade
  1231. * This value decides the per-chain enable mask to select
  1232. * the input ADC for search FTT.
  1233. * For modes upto VHT80, if more than one chain is enabled, the
  1234. * max valid chain
  1235. * is used. LSB corresponds to chain zero.
  1236. * For VHT80_80 and VHT160, the lowest enabled chain is used for
  1237. * primary
  1238. * detection and highest enabled chain is used for secondary
  1239. * detection.
  1240. *
  1241. * XXX: The current algorithm do not use these control and extension
  1242. * channel
  1243. * Instead, it just relies on the combined RSSI values only.
  1244. * For fool-proof detection algorithm, we should take these RSSI
  1245. * values
  1246. * in to account. This is marked for future enhancements.
  1247. */
  1248. /* qdf_print("SPECTRAL : TBD (Chainmask changes for 8x8)\n"); */
  1249. chn_idx_highest_enabled = ((spectral->params.ss_chn_mask & 0x8) ? 3 :
  1250. (spectral->params.ss_chn_mask & 0x4) ? 2 :
  1251. (spectral->params.ss_chn_mask & 0x2) ? 1 : 0);
  1252. chn_idx_lowest_enabled = ((spectral->params.ss_chn_mask & 0x1) ? 0 :
  1253. (spectral->params.ss_chn_mask & 0x2) ? 1 :
  1254. (spectral->params.ss_chn_mask & 0x4) ? 2 : 3);
  1255. control_rssi = (u_int8_t)
  1256. p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
  1257. extension_rssi = (u_int8_t)
  1258. p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
  1259. params.bwinfo = 0;
  1260. params.tstamp = 0;
  1261. params.max_mag = p_sfft->fft_peak_mag;
  1262. /* params.max_index = p_sfft->peak_inx; */
  1263. params.max_exp = 0;
  1264. params.peak = 0;
  1265. params.bin_pwr_data = (u_int8_t *)((uint8_t *)p_fft_report +
  1266. SPECTRAL_FFT_BINS_POS);
  1267. params.freq = p_sops->get_current_channel(spectral);
  1268. params.freq_loading = 0;
  1269. params.interf_list.count = 0;
  1270. params.max_lower_index = 0;
  1271. params.max_upper_index = 0;
  1272. params.nb_lower = 0;
  1273. params.nb_upper = 0;
  1274. /*
  1275. * For modes upto VHT80, the noise floor is populated with the one
  1276. * corresponding
  1277. * to the highest enabled antenna chain
  1278. */
  1279. params.noise_floor =
  1280. p_rfqual->noise_floor[chn_idx_highest_enabled];
  1281. params.datalen = (fft_hdr_length * 4);
  1282. params.pwr_count = fft_bin_len;
  1283. params.tstamp = (tsf64 & SPECTRAL_TSMASK);
  1284. acs_stats->ctrl_nf = params.noise_floor;
  1285. acs_stats->ext_nf = params.noise_floor;
  1286. acs_stats->nfc_ctl_rssi = control_rssi;
  1287. acs_stats->nfc_ext_rssi = extension_rssi;
  1288. if (spectral->ch_width == CH_WIDTH_160MHZ) {
  1289. /* We expect to see one more Search FFT report, and it should be
  1290. * equal in size to the current one.
  1291. */
  1292. if (datalen != (2 * report_len)) {
  1293. spectral->diag_stats.spectral_sec80_sfft_insufflen++;
  1294. goto fail;
  1295. }
  1296. p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)(
  1297. (uint8_t *)p_fft_report + report_len);
  1298. if (p_fft_report->fft_hdr_sig != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
  1299. spectral->diag_stats.spectral_mismatch++;
  1300. goto fail;
  1301. }
  1302. if (p_fft_report->fft_hdr_tag != TLV_TAG_SEARCH_FFT_REPORT_GEN3) {
  1303. spectral->diag_stats.spectral_no_sec80_sfft++;
  1304. goto fail;
  1305. }
  1306. fft_hdr_length = p_fft_report->fft_hdr_length * 4;
  1307. report_len = (fft_hdr_length + 8);
  1308. fft_bin_len = (fft_hdr_length - 16);
  1309. process_search_fft_report_gen3(p_fft_report, p_sfft);
  1310. if (p_sfft->fft_detector_id != 1) {
  1311. qdf_print("Expected segid is 1 but we got %d\n",
  1312. p_sfft->fft_detector_id);
  1313. spectral->diag_stats.spectral_vhtseg2id_mismatch++;
  1314. goto fail;
  1315. }
  1316. if (spectral_debug_level & (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4))
  1317. spectral_dump_fft_report_gen3(p_fft_report, p_sfft);
  1318. params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
  1319. params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
  1320. /* XXX: Confirm. TBD at SoD. */
  1321. params.rssi_sec80 = p_rfqual->rssi_comb;
  1322. /* if (spectral->is_sec80_rssi_war_required) { */
  1323. /* params.rssi_sec80 = get_combined_rssi_sec80_segment_gen3(spectral,
  1324. * &search_fft_info_sec80);
  1325. */
  1326. /* } */
  1327. /* XXX: Determine dynamically. TBD at SoD. */
  1328. /*
  1329. * For VHT80_80/VHT160, the noise floor for primary 80MHz segment is
  1330. * populated with the
  1331. * lowest enabled antenna chain and the noise floor for secondary 80MHz
  1332. * segment is populated
  1333. * with the highest enabled antenna chain
  1334. */
  1335. params.noise_floor_sec80 =
  1336. p_rfqual->noise_floor[chn_idx_highest_enabled];
  1337. params.noise_floor =
  1338. p_rfqual->noise_floor[chn_idx_lowest_enabled];
  1339. params.max_mag_sec80 = p_sfft->fft_peak_mag;
  1340. /* params.max_index_sec80 = p_sfft->peak_inx; */
  1341. /* XXX Does this definition of datalen *still hold? */
  1342. params.datalen_sec80 = fft_hdr_length;
  1343. params.pwr_count_sec80 = fft_bin_len;
  1344. params.bin_pwr_data_sec80 = (u_int8_t *)(
  1345. (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS);
  1346. }
  1347. qdf_mem_copy(
  1348. &params.classifier_params,
  1349. &spectral->classifier_params,
  1350. sizeof(struct spectral_classifier_params));
  1351. #ifdef SPECTRAL_DEBUG_SAMP_MSG
  1352. target_if_dbg_print_SAMP_param(&params);
  1353. #endif
  1354. target_if_spectral_create_samp_msg(spectral, &params);
  1355. return 0;
  1356. fail:
  1357. qdf_print("Error in function %s while processing search fft report\n",
  1358. __func__);
  1359. print_buf((uint8_t *)p_fft_report, fft_hdr_length + 8);
  1360. return -EPERM;
  1361. }
  1362. /*
  1363. * Function : spectral_process_phyerr_gen3
  1364. * Descrip_tion : Process PHY Error
  1365. * Input : Pointer to buffer
  1366. * Output : Success/Failure
  1367. *
  1368. */
  1369. int spectral_process_phyerr_gen3(
  1370. struct target_if_spectral *spectral,
  1371. u_int8_t *data,
  1372. u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
  1373. struct target_if_spectral_chan_info *p_chaninfo,
  1374. u_int64_t tsf64,
  1375. struct target_if_spectral_acs_stats *acs_stats)
  1376. {
  1377. uint8_t tag = 0;
  1378. uint8_t signature = 0;
  1379. struct phyerr_info pinfo;
  1380. int ret = 0;
  1381. /* pack arguments in a structure as there are
  1382. * more than 3 arguments
  1383. */
  1384. pinfo.data = data;
  1385. pinfo.datalen = datalen;
  1386. pinfo.p_rfqual = p_rfqual;
  1387. pinfo.p_chaninfo = p_chaninfo;
  1388. pinfo.tsf64 = tsf64;
  1389. pinfo.acs_stats = acs_stats;
  1390. if (spectral_debug_level &
  1391. (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4)) {
  1392. qdf_print("Printing the spectral phyerr buffer for debug "
  1393. "purpose\n");
  1394. qdf_print("Dalalength of buffer = 0x%x(%d)\n",
  1395. datalen, datalen);
  1396. #ifdef CONFIG_WIN
  1397. RAWSIM_PKT_HEXDUMP(data, datalen);
  1398. #endif
  1399. }
  1400. /* Peek into the data to figure out whether
  1401. * 1) Signature matches the expected value
  1402. * 2) What is inside the package (TAG ID is used for finding this)
  1403. */
  1404. tag = *(data + PHYERR_HDR_TAG_POS);
  1405. signature = *(data + PHYERR_HDR_SIG_POS);
  1406. if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
  1407. qdf_print("Unexpected signature %x in spectral phyerror "
  1408. "event\n", signature);
  1409. spectral->diag_stats.spectral_mismatch++;
  1410. ret = -1;
  1411. goto end;
  1412. }
  1413. switch (tag) {
  1414. case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3:
  1415. /* Place holder
  1416. * We don't use spectral scan report as of now
  1417. */
  1418. break;
  1419. case TLV_TAG_SEARCH_FFT_REPORT_GEN3:
  1420. ret = consume_searchfft_report_gen3(spectral, &pinfo);
  1421. break;
  1422. default:
  1423. qdf_print("Unknown tag %x in spectral phyerror event\n", tag);
  1424. break;
  1425. }
  1426. end:
  1427. if (spectral_debug_level & ATH_DEBUG_SPECTRAL4)
  1428. spectral_debug_level = ATH_DEBUG_SPECTRAL;
  1429. return ret;
  1430. }
  1431. /* END of spectral GEN III HW specific functions */
  1432. #endif /* WLAN_SPECTRAL_ENABLE */