spectral.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <linux/relay.h>
  17. #include "core.h"
  18. #include "debug.h"
  19. static void send_fft_sample(struct ath10k *ar,
  20. const struct fft_sample_tlv *fft_sample_tlv)
  21. {
  22. int length;
  23. if (!ar->spectral.rfs_chan_spec_scan)
  24. return;
  25. length = __be16_to_cpu(fft_sample_tlv->length) +
  26. sizeof(*fft_sample_tlv);
  27. relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
  28. }
  29. static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
  30. u8 *data)
  31. {
  32. int dc_pos;
  33. u8 max_exp;
  34. dc_pos = bin_len / 2;
  35. /* peak index outside of bins */
  36. if (dc_pos < max_index || -dc_pos >= max_index)
  37. return 0;
  38. for (max_exp = 0; max_exp < 8; max_exp++) {
  39. if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
  40. break;
  41. }
  42. /* max_exp not found */
  43. if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
  44. return 0;
  45. return max_exp;
  46. }
  47. int ath10k_spectral_process_fft(struct ath10k *ar,
  48. struct wmi_single_phyerr_rx_event *event,
  49. struct phyerr_fft_report *fftr,
  50. size_t bin_len, u64 tsf)
  51. {
  52. struct fft_sample_ath10k *fft_sample;
  53. u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
  54. u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
  55. u32 reg0, reg1, nf_list1, nf_list2;
  56. u8 chain_idx, *bins;
  57. int dc_pos;
  58. fft_sample = (struct fft_sample_ath10k *)&buf;
  59. if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
  60. return -EINVAL;
  61. reg0 = __le32_to_cpu(fftr->reg0);
  62. reg1 = __le32_to_cpu(fftr->reg1);
  63. length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
  64. fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
  65. fft_sample->tlv.length = __cpu_to_be16(length);
  66. /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
  67. * but the results/plots suggest that its actually 22/44/88 MHz.
  68. */
  69. switch (event->hdr.chan_width_mhz) {
  70. case 20:
  71. fft_sample->chan_width_mhz = 22;
  72. break;
  73. case 40:
  74. fft_sample->chan_width_mhz = 44;
  75. break;
  76. case 80:
  77. /* TODO: As experiments with an analogue sender and various
  78. * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
  79. * show, the particular configuration of 80 MHz/64 bins does
  80. * not match with the other smaples at all. Until the reason
  81. * for that is found, don't report these samples.
  82. */
  83. if (bin_len == 64)
  84. return -EINVAL;
  85. fft_sample->chan_width_mhz = 88;
  86. break;
  87. default:
  88. fft_sample->chan_width_mhz = event->hdr.chan_width_mhz;
  89. }
  90. fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
  91. fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
  92. peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
  93. fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
  94. fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
  95. fft_sample->rssi = event->hdr.rssi_combined;
  96. total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
  97. base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
  98. fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
  99. fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
  100. freq1 = __le16_to_cpu(event->hdr.freq1);
  101. freq2 = __le16_to_cpu(event->hdr.freq2);
  102. fft_sample->freq1 = __cpu_to_be16(freq1);
  103. fft_sample->freq2 = __cpu_to_be16(freq2);
  104. nf_list1 = __le32_to_cpu(event->hdr.nf_list_1);
  105. nf_list2 = __le32_to_cpu(event->hdr.nf_list_2);
  106. chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
  107. switch (chain_idx) {
  108. case 0:
  109. fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu);
  110. break;
  111. case 1:
  112. fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu);
  113. break;
  114. case 2:
  115. fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu);
  116. break;
  117. case 3:
  118. fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu);
  119. break;
  120. }
  121. bins = (u8 *)fftr;
  122. bins += sizeof(*fftr);
  123. fft_sample->tsf = __cpu_to_be64(tsf);
  124. /* max_exp has been directly reported by previous hardware (ath9k),
  125. * maybe its possible to get it by other means?
  126. */
  127. fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
  128. bin_len, bins);
  129. memcpy(fft_sample->data, bins, bin_len);
  130. /* DC value (value in the middle) is the blind spot of the spectral
  131. * sample and invalid, interpolate it.
  132. */
  133. dc_pos = bin_len / 2;
  134. fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
  135. fft_sample->data[dc_pos - 1]) / 2;
  136. send_fft_sample(ar, &fft_sample->tlv);
  137. return 0;
  138. }
  139. static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
  140. {
  141. struct ath10k_vif *arvif;
  142. lockdep_assert_held(&ar->conf_mutex);
  143. if (list_empty(&ar->arvifs))
  144. return NULL;
  145. /* if there already is a vif doing spectral, return that. */
  146. list_for_each_entry(arvif, &ar->arvifs, list)
  147. if (arvif->spectral_enabled)
  148. return arvif;
  149. /* otherwise, return the first vif. */
  150. return list_first_entry(&ar->arvifs, typeof(*arvif), list);
  151. }
  152. static int ath10k_spectral_scan_trigger(struct ath10k *ar)
  153. {
  154. struct ath10k_vif *arvif;
  155. int res;
  156. int vdev_id;
  157. lockdep_assert_held(&ar->conf_mutex);
  158. arvif = ath10k_get_spectral_vdev(ar);
  159. if (!arvif)
  160. return -ENODEV;
  161. vdev_id = arvif->vdev_id;
  162. if (ar->spectral.mode == SPECTRAL_DISABLED)
  163. return 0;
  164. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  165. WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
  166. WMI_SPECTRAL_ENABLE_CMD_ENABLE);
  167. if (res < 0)
  168. return res;
  169. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  170. WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
  171. WMI_SPECTRAL_ENABLE_CMD_ENABLE);
  172. if (res < 0)
  173. return res;
  174. return 0;
  175. }
  176. static int ath10k_spectral_scan_config(struct ath10k *ar,
  177. enum ath10k_spectral_mode mode)
  178. {
  179. struct wmi_vdev_spectral_conf_arg arg;
  180. struct ath10k_vif *arvif;
  181. int vdev_id, count, res = 0;
  182. lockdep_assert_held(&ar->conf_mutex);
  183. arvif = ath10k_get_spectral_vdev(ar);
  184. if (!arvif)
  185. return -ENODEV;
  186. vdev_id = arvif->vdev_id;
  187. arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
  188. ar->spectral.mode = mode;
  189. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  190. WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
  191. WMI_SPECTRAL_ENABLE_CMD_DISABLE);
  192. if (res < 0) {
  193. ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
  194. return res;
  195. }
  196. if (mode == SPECTRAL_DISABLED)
  197. return 0;
  198. if (mode == SPECTRAL_BACKGROUND)
  199. count = WMI_SPECTRAL_COUNT_DEFAULT;
  200. else
  201. count = max_t(u8, 1, ar->spectral.config.count);
  202. arg.vdev_id = vdev_id;
  203. arg.scan_count = count;
  204. arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
  205. arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
  206. arg.scan_fft_size = ar->spectral.config.fft_size;
  207. arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
  208. arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
  209. arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
  210. arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
  211. arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
  212. arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
  213. arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
  214. arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
  215. arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
  216. arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
  217. arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
  218. arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  219. arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
  220. arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
  221. res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
  222. if (res < 0) {
  223. ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
  224. return res;
  225. }
  226. return 0;
  227. }
  228. static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
  229. size_t count, loff_t *ppos)
  230. {
  231. struct ath10k *ar = file->private_data;
  232. char *mode = "";
  233. unsigned int len;
  234. enum ath10k_spectral_mode spectral_mode;
  235. mutex_lock(&ar->conf_mutex);
  236. spectral_mode = ar->spectral.mode;
  237. mutex_unlock(&ar->conf_mutex);
  238. switch (spectral_mode) {
  239. case SPECTRAL_DISABLED:
  240. mode = "disable";
  241. break;
  242. case SPECTRAL_BACKGROUND:
  243. mode = "background";
  244. break;
  245. case SPECTRAL_MANUAL:
  246. mode = "manual";
  247. break;
  248. }
  249. len = strlen(mode);
  250. return simple_read_from_buffer(user_buf, count, ppos, mode, len);
  251. }
  252. static ssize_t write_file_spec_scan_ctl(struct file *file,
  253. const char __user *user_buf,
  254. size_t count, loff_t *ppos)
  255. {
  256. struct ath10k *ar = file->private_data;
  257. char buf[32];
  258. ssize_t len;
  259. int res;
  260. len = min(count, sizeof(buf) - 1);
  261. if (copy_from_user(buf, user_buf, len))
  262. return -EFAULT;
  263. buf[len] = '\0';
  264. mutex_lock(&ar->conf_mutex);
  265. if (strncmp("trigger", buf, 7) == 0) {
  266. if (ar->spectral.mode == SPECTRAL_MANUAL ||
  267. ar->spectral.mode == SPECTRAL_BACKGROUND) {
  268. /* reset the configuration to adopt possibly changed
  269. * debugfs parameters
  270. */
  271. res = ath10k_spectral_scan_config(ar,
  272. ar->spectral.mode);
  273. if (res < 0) {
  274. ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
  275. res);
  276. }
  277. res = ath10k_spectral_scan_trigger(ar);
  278. if (res < 0) {
  279. ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
  280. res);
  281. }
  282. } else {
  283. res = -EINVAL;
  284. }
  285. } else if (strncmp("background", buf, 9) == 0) {
  286. res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
  287. } else if (strncmp("manual", buf, 6) == 0) {
  288. res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
  289. } else if (strncmp("disable", buf, 7) == 0) {
  290. res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
  291. } else {
  292. res = -EINVAL;
  293. }
  294. mutex_unlock(&ar->conf_mutex);
  295. if (res < 0)
  296. return res;
  297. return count;
  298. }
  299. static const struct file_operations fops_spec_scan_ctl = {
  300. .read = read_file_spec_scan_ctl,
  301. .write = write_file_spec_scan_ctl,
  302. .open = simple_open,
  303. .owner = THIS_MODULE,
  304. .llseek = default_llseek,
  305. };
  306. static ssize_t read_file_spectral_count(struct file *file,
  307. char __user *user_buf,
  308. size_t count, loff_t *ppos)
  309. {
  310. struct ath10k *ar = file->private_data;
  311. char buf[32];
  312. unsigned int len;
  313. u8 spectral_count;
  314. mutex_lock(&ar->conf_mutex);
  315. spectral_count = ar->spectral.config.count;
  316. mutex_unlock(&ar->conf_mutex);
  317. len = sprintf(buf, "%d\n", spectral_count);
  318. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  319. }
  320. static ssize_t write_file_spectral_count(struct file *file,
  321. const char __user *user_buf,
  322. size_t count, loff_t *ppos)
  323. {
  324. struct ath10k *ar = file->private_data;
  325. unsigned long val;
  326. char buf[32];
  327. ssize_t len;
  328. len = min(count, sizeof(buf) - 1);
  329. if (copy_from_user(buf, user_buf, len))
  330. return -EFAULT;
  331. buf[len] = '\0';
  332. if (kstrtoul(buf, 0, &val))
  333. return -EINVAL;
  334. if (val < 0 || val > 255)
  335. return -EINVAL;
  336. mutex_lock(&ar->conf_mutex);
  337. ar->spectral.config.count = val;
  338. mutex_unlock(&ar->conf_mutex);
  339. return count;
  340. }
  341. static const struct file_operations fops_spectral_count = {
  342. .read = read_file_spectral_count,
  343. .write = write_file_spectral_count,
  344. .open = simple_open,
  345. .owner = THIS_MODULE,
  346. .llseek = default_llseek,
  347. };
  348. static ssize_t read_file_spectral_bins(struct file *file,
  349. char __user *user_buf,
  350. size_t count, loff_t *ppos)
  351. {
  352. struct ath10k *ar = file->private_data;
  353. char buf[32];
  354. unsigned int len, bins, fft_size, bin_scale;
  355. mutex_lock(&ar->conf_mutex);
  356. fft_size = ar->spectral.config.fft_size;
  357. bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  358. bins = 1 << (fft_size - bin_scale);
  359. mutex_unlock(&ar->conf_mutex);
  360. len = sprintf(buf, "%d\n", bins);
  361. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  362. }
  363. static ssize_t write_file_spectral_bins(struct file *file,
  364. const char __user *user_buf,
  365. size_t count, loff_t *ppos)
  366. {
  367. struct ath10k *ar = file->private_data;
  368. unsigned long val;
  369. char buf[32];
  370. ssize_t len;
  371. len = min(count, sizeof(buf) - 1);
  372. if (copy_from_user(buf, user_buf, len))
  373. return -EFAULT;
  374. buf[len] = '\0';
  375. if (kstrtoul(buf, 0, &val))
  376. return -EINVAL;
  377. if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
  378. return -EINVAL;
  379. if (!is_power_of_2(val))
  380. return -EINVAL;
  381. mutex_lock(&ar->conf_mutex);
  382. ar->spectral.config.fft_size = ilog2(val);
  383. ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  384. mutex_unlock(&ar->conf_mutex);
  385. return count;
  386. }
  387. static const struct file_operations fops_spectral_bins = {
  388. .read = read_file_spectral_bins,
  389. .write = write_file_spectral_bins,
  390. .open = simple_open,
  391. .owner = THIS_MODULE,
  392. .llseek = default_llseek,
  393. };
  394. static struct dentry *create_buf_file_handler(const char *filename,
  395. struct dentry *parent,
  396. umode_t mode,
  397. struct rchan_buf *buf,
  398. int *is_global)
  399. {
  400. struct dentry *buf_file;
  401. buf_file = debugfs_create_file(filename, mode, parent, buf,
  402. &relay_file_operations);
  403. *is_global = 1;
  404. return buf_file;
  405. }
  406. static int remove_buf_file_handler(struct dentry *dentry)
  407. {
  408. debugfs_remove(dentry);
  409. return 0;
  410. }
  411. static struct rchan_callbacks rfs_spec_scan_cb = {
  412. .create_buf_file = create_buf_file_handler,
  413. .remove_buf_file = remove_buf_file_handler,
  414. };
  415. int ath10k_spectral_start(struct ath10k *ar)
  416. {
  417. struct ath10k_vif *arvif;
  418. lockdep_assert_held(&ar->conf_mutex);
  419. list_for_each_entry(arvif, &ar->arvifs, list)
  420. arvif->spectral_enabled = 0;
  421. ar->spectral.mode = SPECTRAL_DISABLED;
  422. ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
  423. ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
  424. return 0;
  425. }
  426. int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
  427. {
  428. if (!arvif->spectral_enabled)
  429. return 0;
  430. return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
  431. }
  432. int ath10k_spectral_create(struct ath10k *ar)
  433. {
  434. ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
  435. ar->debug.debugfs_phy,
  436. 1024, 256,
  437. &rfs_spec_scan_cb, NULL);
  438. debugfs_create_file("spectral_scan_ctl",
  439. S_IRUSR | S_IWUSR,
  440. ar->debug.debugfs_phy, ar,
  441. &fops_spec_scan_ctl);
  442. debugfs_create_file("spectral_count",
  443. S_IRUSR | S_IWUSR,
  444. ar->debug.debugfs_phy, ar,
  445. &fops_spectral_count);
  446. debugfs_create_file("spectral_bins",
  447. S_IRUSR | S_IWUSR,
  448. ar->debug.debugfs_phy, ar,
  449. &fops_spectral_bins);
  450. return 0;
  451. }
  452. void ath10k_spectral_destroy(struct ath10k *ar)
  453. {
  454. if (ar->spectral.rfs_chan_spec_scan) {
  455. relay_close(ar->spectral.rfs_chan_spec_scan);
  456. ar->spectral.rfs_chan_spec_scan = NULL;
  457. }
  458. }