spectral.c 14 KB

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