spectral.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. const struct wmi_phyerr *phyerr,
  49. const 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;
  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 (phyerr->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 = phyerr->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 = phyerr->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(phyerr->freq1);
  101. freq2 = __le16_to_cpu(phyerr->freq2);
  102. fft_sample->freq1 = __cpu_to_be16(freq1);
  103. fft_sample->freq2 = __cpu_to_be16(freq2);
  104. chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
  105. fft_sample->noise = __cpu_to_be16(
  106. __le16_to_cpu(phyerr->nf_chains[chain_idx]));
  107. bins = (u8 *)fftr;
  108. bins += sizeof(*fftr);
  109. fft_sample->tsf = __cpu_to_be64(tsf);
  110. /* max_exp has been directly reported by previous hardware (ath9k),
  111. * maybe its possible to get it by other means?
  112. */
  113. fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
  114. bin_len, bins);
  115. memcpy(fft_sample->data, bins, bin_len);
  116. /* DC value (value in the middle) is the blind spot of the spectral
  117. * sample and invalid, interpolate it.
  118. */
  119. dc_pos = bin_len / 2;
  120. fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
  121. fft_sample->data[dc_pos - 1]) / 2;
  122. send_fft_sample(ar, &fft_sample->tlv);
  123. return 0;
  124. }
  125. static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
  126. {
  127. struct ath10k_vif *arvif;
  128. lockdep_assert_held(&ar->conf_mutex);
  129. if (list_empty(&ar->arvifs))
  130. return NULL;
  131. /* if there already is a vif doing spectral, return that. */
  132. list_for_each_entry(arvif, &ar->arvifs, list)
  133. if (arvif->spectral_enabled)
  134. return arvif;
  135. /* otherwise, return the first vif. */
  136. return list_first_entry(&ar->arvifs, typeof(*arvif), list);
  137. }
  138. static int ath10k_spectral_scan_trigger(struct ath10k *ar)
  139. {
  140. struct ath10k_vif *arvif;
  141. int res;
  142. int vdev_id;
  143. lockdep_assert_held(&ar->conf_mutex);
  144. arvif = ath10k_get_spectral_vdev(ar);
  145. if (!arvif)
  146. return -ENODEV;
  147. vdev_id = arvif->vdev_id;
  148. if (ar->spectral.mode == SPECTRAL_DISABLED)
  149. return 0;
  150. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  151. WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
  152. WMI_SPECTRAL_ENABLE_CMD_ENABLE);
  153. if (res < 0)
  154. return res;
  155. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  156. WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
  157. WMI_SPECTRAL_ENABLE_CMD_ENABLE);
  158. if (res < 0)
  159. return res;
  160. return 0;
  161. }
  162. static int ath10k_spectral_scan_config(struct ath10k *ar,
  163. enum ath10k_spectral_mode mode)
  164. {
  165. struct wmi_vdev_spectral_conf_arg arg;
  166. struct ath10k_vif *arvif;
  167. int vdev_id, count, res = 0;
  168. lockdep_assert_held(&ar->conf_mutex);
  169. arvif = ath10k_get_spectral_vdev(ar);
  170. if (!arvif)
  171. return -ENODEV;
  172. vdev_id = arvif->vdev_id;
  173. arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
  174. ar->spectral.mode = mode;
  175. res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
  176. WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
  177. WMI_SPECTRAL_ENABLE_CMD_DISABLE);
  178. if (res < 0) {
  179. ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
  180. return res;
  181. }
  182. if (mode == SPECTRAL_DISABLED)
  183. return 0;
  184. if (mode == SPECTRAL_BACKGROUND)
  185. count = WMI_SPECTRAL_COUNT_DEFAULT;
  186. else
  187. count = max_t(u8, 1, ar->spectral.config.count);
  188. arg.vdev_id = vdev_id;
  189. arg.scan_count = count;
  190. arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
  191. arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
  192. arg.scan_fft_size = ar->spectral.config.fft_size;
  193. arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
  194. arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
  195. arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
  196. arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
  197. arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
  198. arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
  199. arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
  200. arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
  201. arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
  202. arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
  203. arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
  204. arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  205. arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
  206. arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
  207. res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
  208. if (res < 0) {
  209. ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
  210. return res;
  211. }
  212. return 0;
  213. }
  214. static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
  215. size_t count, loff_t *ppos)
  216. {
  217. struct ath10k *ar = file->private_data;
  218. char *mode = "";
  219. unsigned int len;
  220. enum ath10k_spectral_mode spectral_mode;
  221. mutex_lock(&ar->conf_mutex);
  222. spectral_mode = ar->spectral.mode;
  223. mutex_unlock(&ar->conf_mutex);
  224. switch (spectral_mode) {
  225. case SPECTRAL_DISABLED:
  226. mode = "disable";
  227. break;
  228. case SPECTRAL_BACKGROUND:
  229. mode = "background";
  230. break;
  231. case SPECTRAL_MANUAL:
  232. mode = "manual";
  233. break;
  234. }
  235. len = strlen(mode);
  236. return simple_read_from_buffer(user_buf, count, ppos, mode, len);
  237. }
  238. static ssize_t write_file_spec_scan_ctl(struct file *file,
  239. const char __user *user_buf,
  240. size_t count, loff_t *ppos)
  241. {
  242. struct ath10k *ar = file->private_data;
  243. char buf[32];
  244. ssize_t len;
  245. int res;
  246. len = min(count, sizeof(buf) - 1);
  247. if (copy_from_user(buf, user_buf, len))
  248. return -EFAULT;
  249. buf[len] = '\0';
  250. mutex_lock(&ar->conf_mutex);
  251. if (strncmp("trigger", buf, 7) == 0) {
  252. if (ar->spectral.mode == SPECTRAL_MANUAL ||
  253. ar->spectral.mode == SPECTRAL_BACKGROUND) {
  254. /* reset the configuration to adopt possibly changed
  255. * debugfs parameters
  256. */
  257. res = ath10k_spectral_scan_config(ar,
  258. ar->spectral.mode);
  259. if (res < 0) {
  260. ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
  261. res);
  262. }
  263. res = ath10k_spectral_scan_trigger(ar);
  264. if (res < 0) {
  265. ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
  266. res);
  267. }
  268. } else {
  269. res = -EINVAL;
  270. }
  271. } else if (strncmp("background", buf, 9) == 0) {
  272. res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
  273. } else if (strncmp("manual", buf, 6) == 0) {
  274. res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
  275. } else if (strncmp("disable", buf, 7) == 0) {
  276. res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
  277. } else {
  278. res = -EINVAL;
  279. }
  280. mutex_unlock(&ar->conf_mutex);
  281. if (res < 0)
  282. return res;
  283. return count;
  284. }
  285. static const struct file_operations fops_spec_scan_ctl = {
  286. .read = read_file_spec_scan_ctl,
  287. .write = write_file_spec_scan_ctl,
  288. .open = simple_open,
  289. .owner = THIS_MODULE,
  290. .llseek = default_llseek,
  291. };
  292. static ssize_t read_file_spectral_count(struct file *file,
  293. char __user *user_buf,
  294. size_t count, loff_t *ppos)
  295. {
  296. struct ath10k *ar = file->private_data;
  297. char buf[32];
  298. unsigned int len;
  299. u8 spectral_count;
  300. mutex_lock(&ar->conf_mutex);
  301. spectral_count = ar->spectral.config.count;
  302. mutex_unlock(&ar->conf_mutex);
  303. len = sprintf(buf, "%d\n", spectral_count);
  304. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  305. }
  306. static ssize_t write_file_spectral_count(struct file *file,
  307. const char __user *user_buf,
  308. size_t count, loff_t *ppos)
  309. {
  310. struct ath10k *ar = file->private_data;
  311. unsigned long val;
  312. char buf[32];
  313. ssize_t len;
  314. len = min(count, sizeof(buf) - 1);
  315. if (copy_from_user(buf, user_buf, len))
  316. return -EFAULT;
  317. buf[len] = '\0';
  318. if (kstrtoul(buf, 0, &val))
  319. return -EINVAL;
  320. if (val < 0 || val > 255)
  321. return -EINVAL;
  322. mutex_lock(&ar->conf_mutex);
  323. ar->spectral.config.count = val;
  324. mutex_unlock(&ar->conf_mutex);
  325. return count;
  326. }
  327. static const struct file_operations fops_spectral_count = {
  328. .read = read_file_spectral_count,
  329. .write = write_file_spectral_count,
  330. .open = simple_open,
  331. .owner = THIS_MODULE,
  332. .llseek = default_llseek,
  333. };
  334. static ssize_t read_file_spectral_bins(struct file *file,
  335. char __user *user_buf,
  336. size_t count, loff_t *ppos)
  337. {
  338. struct ath10k *ar = file->private_data;
  339. char buf[32];
  340. unsigned int len, bins, fft_size, bin_scale;
  341. mutex_lock(&ar->conf_mutex);
  342. fft_size = ar->spectral.config.fft_size;
  343. bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  344. bins = 1 << (fft_size - bin_scale);
  345. mutex_unlock(&ar->conf_mutex);
  346. len = sprintf(buf, "%d\n", bins);
  347. return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  348. }
  349. static ssize_t write_file_spectral_bins(struct file *file,
  350. const char __user *user_buf,
  351. size_t count, loff_t *ppos)
  352. {
  353. struct ath10k *ar = file->private_data;
  354. unsigned long val;
  355. char buf[32];
  356. ssize_t len;
  357. len = min(count, sizeof(buf) - 1);
  358. if (copy_from_user(buf, user_buf, len))
  359. return -EFAULT;
  360. buf[len] = '\0';
  361. if (kstrtoul(buf, 0, &val))
  362. return -EINVAL;
  363. if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
  364. return -EINVAL;
  365. if (!is_power_of_2(val))
  366. return -EINVAL;
  367. mutex_lock(&ar->conf_mutex);
  368. ar->spectral.config.fft_size = ilog2(val);
  369. ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
  370. mutex_unlock(&ar->conf_mutex);
  371. return count;
  372. }
  373. static const struct file_operations fops_spectral_bins = {
  374. .read = read_file_spectral_bins,
  375. .write = write_file_spectral_bins,
  376. .open = simple_open,
  377. .owner = THIS_MODULE,
  378. .llseek = default_llseek,
  379. };
  380. static struct dentry *create_buf_file_handler(const char *filename,
  381. struct dentry *parent,
  382. umode_t mode,
  383. struct rchan_buf *buf,
  384. int *is_global)
  385. {
  386. struct dentry *buf_file;
  387. buf_file = debugfs_create_file(filename, mode, parent, buf,
  388. &relay_file_operations);
  389. *is_global = 1;
  390. return buf_file;
  391. }
  392. static int remove_buf_file_handler(struct dentry *dentry)
  393. {
  394. debugfs_remove(dentry);
  395. return 0;
  396. }
  397. static struct rchan_callbacks rfs_spec_scan_cb = {
  398. .create_buf_file = create_buf_file_handler,
  399. .remove_buf_file = remove_buf_file_handler,
  400. };
  401. int ath10k_spectral_start(struct ath10k *ar)
  402. {
  403. struct ath10k_vif *arvif;
  404. lockdep_assert_held(&ar->conf_mutex);
  405. list_for_each_entry(arvif, &ar->arvifs, list)
  406. arvif->spectral_enabled = 0;
  407. ar->spectral.mode = SPECTRAL_DISABLED;
  408. ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
  409. ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
  410. return 0;
  411. }
  412. int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
  413. {
  414. if (!arvif->spectral_enabled)
  415. return 0;
  416. return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
  417. }
  418. int ath10k_spectral_create(struct ath10k *ar)
  419. {
  420. ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
  421. ar->debug.debugfs_phy,
  422. 1024, 256,
  423. &rfs_spec_scan_cb, NULL);
  424. debugfs_create_file("spectral_scan_ctl",
  425. S_IRUSR | S_IWUSR,
  426. ar->debug.debugfs_phy, ar,
  427. &fops_spec_scan_ctl);
  428. debugfs_create_file("spectral_count",
  429. S_IRUSR | S_IWUSR,
  430. ar->debug.debugfs_phy, ar,
  431. &fops_spectral_count);
  432. debugfs_create_file("spectral_bins",
  433. S_IRUSR | S_IWUSR,
  434. ar->debug.debugfs_phy, ar,
  435. &fops_spectral_bins);
  436. return 0;
  437. }
  438. void ath10k_spectral_destroy(struct ath10k *ar)
  439. {
  440. if (ar->spectral.rfs_chan_spec_scan) {
  441. relay_close(ar->spectral.rfs_chan_spec_scan);
  442. ar->spectral.rfs_chan_spec_scan = NULL;
  443. }
  444. }