diff options
author | Janusz Dziedzic <janusz.dziedzic@tieto.com> | 2013-11-20 02:59:41 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2013-11-20 02:59:41 -0500 |
commit | 9702c686081240bff1f05150c78335152d37ac8d (patch) | |
tree | fec0e4e91baf4545aa7efb0de7455fc3d7a4f270 | |
parent | 5d04e4120a6ef2eac3a3a80bda6a16bb90f2da2c (diff) |
ath10k: add phyerr/dfs handling
Handle phyerr, dfs event, radar_report and fft_report.
Add also debugfs dfs_simulate_radar and dfs_stats files.
Use ath dfs pattern detector.
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
-rw-r--r-- | drivers/net/wireless/ath/ath10k/core.h | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.c | 90 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/debug.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 24 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 244 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.h | 85 |
6 files changed, 461 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index be35df2902c4..afbc7449b137 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "wmi.h" | 30 | #include "wmi.h" |
31 | #include "../ath.h" | 31 | #include "../ath.h" |
32 | #include "../regd.h" | 32 | #include "../regd.h" |
33 | #include "../dfs_pattern_detector.h" | ||
33 | 34 | ||
34 | #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) | 35 | #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) |
35 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) | 36 | #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) |
@@ -192,6 +193,14 @@ struct ath10k_target_stats { | |||
192 | 193 | ||
193 | }; | 194 | }; |
194 | 195 | ||
196 | struct ath10k_dfs_stats { | ||
197 | u32 phy_errors; | ||
198 | u32 pulses_total; | ||
199 | u32 pulses_detected; | ||
200 | u32 pulses_discarded; | ||
201 | u32 radar_detected; | ||
202 | }; | ||
203 | |||
195 | #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */ | 204 | #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */ |
196 | 205 | ||
197 | struct ath10k_peer { | 206 | struct ath10k_peer { |
@@ -261,6 +270,8 @@ struct ath10k_debug { | |||
261 | 270 | ||
262 | unsigned long htt_stats_mask; | 271 | unsigned long htt_stats_mask; |
263 | struct delayed_work htt_stats_dwork; | 272 | struct delayed_work htt_stats_dwork; |
273 | struct ath10k_dfs_stats dfs_stats; | ||
274 | struct ath_dfs_pool_stats dfs_pool_stats; | ||
264 | }; | 275 | }; |
265 | 276 | ||
266 | enum ath10k_state { | 277 | enum ath10k_state { |
@@ -428,6 +439,8 @@ struct ath10k { | |||
428 | u32 survey_last_cycle_count; | 439 | u32 survey_last_cycle_count; |
429 | struct survey_info survey[ATH10K_NUM_CHANS]; | 440 | struct survey_info survey[ATH10K_NUM_CHANS]; |
430 | 441 | ||
442 | struct dfs_pattern_detector *dfs_detector; | ||
443 | |||
431 | #ifdef CONFIG_ATH10K_DEBUGFS | 444 | #ifdef CONFIG_ATH10K_DEBUGFS |
432 | struct ath10k_debug debug; | 445 | struct ath10k_debug debug; |
433 | #endif | 446 | #endif |
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 760ff2289e3c..13705d41795e 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c | |||
@@ -639,6 +639,86 @@ void ath10k_debug_stop(struct ath10k *ar) | |||
639 | cancel_delayed_work(&ar->debug.htt_stats_dwork); | 639 | cancel_delayed_work(&ar->debug.htt_stats_dwork); |
640 | } | 640 | } |
641 | 641 | ||
642 | static ssize_t ath10k_write_simulate_radar(struct file *file, | ||
643 | const char __user *user_buf, | ||
644 | size_t count, loff_t *ppos) | ||
645 | { | ||
646 | struct ath10k *ar = file->private_data; | ||
647 | |||
648 | ieee80211_radar_detected(ar->hw); | ||
649 | |||
650 | return count; | ||
651 | } | ||
652 | |||
653 | static const struct file_operations fops_simulate_radar = { | ||
654 | .write = ath10k_write_simulate_radar, | ||
655 | .open = simple_open, | ||
656 | .owner = THIS_MODULE, | ||
657 | .llseek = default_llseek, | ||
658 | }; | ||
659 | |||
660 | #define ATH10K_DFS_STAT(s, p) (\ | ||
661 | len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ | ||
662 | ar->debug.dfs_stats.p)) | ||
663 | |||
664 | #define ATH10K_DFS_POOL_STAT(s, p) (\ | ||
665 | len += scnprintf(buf + len, size - len, "%-28s : %10u\n", s, \ | ||
666 | ar->debug.dfs_pool_stats.p)) | ||
667 | |||
668 | static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf, | ||
669 | size_t count, loff_t *ppos) | ||
670 | { | ||
671 | int retval = 0, len = 0; | ||
672 | const int size = 8000; | ||
673 | struct ath10k *ar = file->private_data; | ||
674 | char *buf; | ||
675 | |||
676 | buf = kzalloc(size, GFP_KERNEL); | ||
677 | if (buf == NULL) | ||
678 | return -ENOMEM; | ||
679 | |||
680 | if (!ar->dfs_detector) { | ||
681 | len += scnprintf(buf + len, size - len, "DFS not enabled\n"); | ||
682 | goto exit; | ||
683 | } | ||
684 | |||
685 | ar->debug.dfs_pool_stats = | ||
686 | ar->dfs_detector->get_stats(ar->dfs_detector); | ||
687 | |||
688 | len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n"); | ||
689 | |||
690 | ATH10K_DFS_STAT("reported phy errors", phy_errors); | ||
691 | ATH10K_DFS_STAT("pulse events reported", pulses_total); | ||
692 | ATH10K_DFS_STAT("DFS pulses detected", pulses_detected); | ||
693 | ATH10K_DFS_STAT("DFS pulses discarded", pulses_discarded); | ||
694 | ATH10K_DFS_STAT("Radars detected", radar_detected); | ||
695 | |||
696 | len += scnprintf(buf + len, size - len, "Global Pool statistics:\n"); | ||
697 | ATH10K_DFS_POOL_STAT("Pool references", pool_reference); | ||
698 | ATH10K_DFS_POOL_STAT("Pulses allocated", pulse_allocated); | ||
699 | ATH10K_DFS_POOL_STAT("Pulses alloc error", pulse_alloc_error); | ||
700 | ATH10K_DFS_POOL_STAT("Pulses in use", pulse_used); | ||
701 | ATH10K_DFS_POOL_STAT("Seqs. allocated", pseq_allocated); | ||
702 | ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error); | ||
703 | ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used); | ||
704 | |||
705 | exit: | ||
706 | if (len > size) | ||
707 | len = size; | ||
708 | |||
709 | retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); | ||
710 | kfree(buf); | ||
711 | |||
712 | return retval; | ||
713 | } | ||
714 | |||
715 | static const struct file_operations fops_dfs_stats = { | ||
716 | .read = ath10k_read_dfs_stats, | ||
717 | .open = simple_open, | ||
718 | .owner = THIS_MODULE, | ||
719 | .llseek = default_llseek, | ||
720 | }; | ||
721 | |||
642 | int ath10k_debug_create(struct ath10k *ar) | 722 | int ath10k_debug_create(struct ath10k *ar) |
643 | { | 723 | { |
644 | ar->debug.debugfs_phy = debugfs_create_dir("ath10k", | 724 | ar->debug.debugfs_phy = debugfs_create_dir("ath10k", |
@@ -667,6 +747,16 @@ int ath10k_debug_create(struct ath10k *ar) | |||
667 | debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, | 747 | debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy, |
668 | ar, &fops_htt_stats_mask); | 748 | ar, &fops_htt_stats_mask); |
669 | 749 | ||
750 | if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { | ||
751 | debugfs_create_file("dfs_simulate_radar", S_IWUSR, | ||
752 | ar->debug.debugfs_phy, ar, | ||
753 | &fops_simulate_radar); | ||
754 | |||
755 | debugfs_create_file("dfs_stats", S_IRUSR, | ||
756 | ar->debug.debugfs_phy, ar, | ||
757 | &fops_dfs_stats); | ||
758 | } | ||
759 | |||
670 | return 0; | 760 | return 0; |
671 | } | 761 | } |
672 | 762 | ||
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index 46e640a6968d..92f1a5e1aa71 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h | |||
@@ -33,6 +33,7 @@ enum ath10k_debug_mask { | |||
33 | ATH10K_DBG_MGMT = 0x00000100, | 33 | ATH10K_DBG_MGMT = 0x00000100, |
34 | ATH10K_DBG_DATA = 0x00000200, | 34 | ATH10K_DBG_DATA = 0x00000200, |
35 | ATH10K_DBG_BMI = 0x00000400, | 35 | ATH10K_DBG_BMI = 0x00000400, |
36 | ATH10K_DBG_REGULATORY = 0x00000800, | ||
36 | ATH10K_DBG_ANY = 0xffffffff, | 37 | ATH10K_DBG_ANY = 0xffffffff, |
37 | }; | 38 | }; |
38 | 39 | ||
@@ -53,6 +54,8 @@ void ath10k_debug_read_service_map(struct ath10k *ar, | |||
53 | void ath10k_debug_read_target_stats(struct ath10k *ar, | 54 | void ath10k_debug_read_target_stats(struct ath10k *ar, |
54 | struct wmi_stats_event *ev); | 55 | struct wmi_stats_event *ev); |
55 | 56 | ||
57 | #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) | ||
58 | |||
56 | #else | 59 | #else |
57 | static inline int ath10k_debug_start(struct ath10k *ar) | 60 | static inline int ath10k_debug_start(struct ath10k *ar) |
58 | { | 61 | { |
@@ -82,6 +85,9 @@ static inline void ath10k_debug_read_target_stats(struct ath10k *ar, | |||
82 | struct wmi_stats_event *ev) | 85 | struct wmi_stats_event *ev) |
83 | { | 86 | { |
84 | } | 87 | } |
88 | |||
89 | #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) | ||
90 | |||
85 | #endif /* CONFIG_ATH10K_DEBUGFS */ | 91 | #endif /* CONFIG_ATH10K_DEBUGFS */ |
86 | 92 | ||
87 | #ifdef CONFIG_ATH10K_DEBUG | 93 | #ifdef CONFIG_ATH10K_DEBUG |
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index db819429134a..c95a3985209d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c | |||
@@ -1442,9 +1442,20 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, | |||
1442 | { | 1442 | { |
1443 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | 1443 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); |
1444 | struct ath10k *ar = hw->priv; | 1444 | struct ath10k *ar = hw->priv; |
1445 | bool result; | ||
1445 | 1446 | ||
1446 | ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); | 1447 | ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory); |
1447 | 1448 | ||
1449 | if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) { | ||
1450 | ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs region 0x%x\n", | ||
1451 | request->dfs_region); | ||
1452 | result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector, | ||
1453 | request->dfs_region); | ||
1454 | if (!result) | ||
1455 | ath10k_warn("dfs region 0x%X not supported, will trigger radar for every pulse\n", | ||
1456 | request->dfs_region); | ||
1457 | } | ||
1458 | |||
1448 | mutex_lock(&ar->conf_mutex); | 1459 | mutex_lock(&ar->conf_mutex); |
1449 | if (ar->state == ATH10K_STATE_ON) | 1460 | if (ar->state == ATH10K_STATE_ON) |
1450 | ath10k_regd_update(ar); | 1461 | ath10k_regd_update(ar); |
@@ -3531,6 +3542,16 @@ int ath10k_mac_register(struct ath10k *ar) | |||
3531 | 3542 | ||
3532 | ar->hw->netdev_features = NETIF_F_HW_CSUM; | 3543 | ar->hw->netdev_features = NETIF_F_HW_CSUM; |
3533 | 3544 | ||
3545 | if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { | ||
3546 | /* Init ath dfs pattern detector */ | ||
3547 | ar->ath_common.debug_mask = ATH_DBG_DFS; | ||
3548 | ar->dfs_detector = dfs_pattern_detector_init(&ar->ath_common, | ||
3549 | NL80211_DFS_UNSET); | ||
3550 | |||
3551 | if (!ar->dfs_detector) | ||
3552 | ath10k_warn("dfs pattern detector init failed\n"); | ||
3553 | } | ||
3554 | |||
3534 | ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, | 3555 | ret = ath_regd_init(&ar->ath_common.regulatory, ar->hw->wiphy, |
3535 | ath10k_reg_notifier); | 3556 | ath10k_reg_notifier); |
3536 | if (ret) { | 3557 | if (ret) { |
@@ -3566,6 +3587,9 @@ void ath10k_mac_unregister(struct ath10k *ar) | |||
3566 | { | 3587 | { |
3567 | ieee80211_unregister_hw(ar->hw); | 3588 | ieee80211_unregister_hw(ar->hw); |
3568 | 3589 | ||
3590 | if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) | ||
3591 | ar->dfs_detector->exit(ar->dfs_detector); | ||
3592 | |||
3569 | kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); | 3593 | kfree(ar->mac.sbands[IEEE80211_BAND_2GHZ].channels); |
3570 | kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); | 3594 | kfree(ar->mac.sbands[IEEE80211_BAND_5GHZ].channels); |
3571 | 3595 | ||
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f79f17ce5dc6..f0bc94abbc74 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c | |||
@@ -1381,9 +1381,251 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, | |||
1381 | ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); | 1381 | ath10k_dbg(ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n"); |
1382 | } | 1382 | } |
1383 | 1383 | ||
1384 | static void ath10k_dfs_radar_report(struct ath10k *ar, | ||
1385 | struct wmi_single_phyerr_rx_event *event, | ||
1386 | struct phyerr_radar_report *rr, | ||
1387 | u64 tsf) | ||
1388 | { | ||
1389 | u32 reg0, reg1, tsf32l; | ||
1390 | struct pulse_event pe; | ||
1391 | u64 tsf64; | ||
1392 | u8 rssi, width; | ||
1393 | |||
1394 | reg0 = __le32_to_cpu(rr->reg0); | ||
1395 | reg1 = __le32_to_cpu(rr->reg1); | ||
1396 | |||
1397 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1398 | "wmi phyerr radar report chirp %d max_width %d agc_total_gain %d pulse_delta_diff %d\n", | ||
1399 | MS(reg0, RADAR_REPORT_REG0_PULSE_IS_CHIRP), | ||
1400 | MS(reg0, RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH), | ||
1401 | MS(reg0, RADAR_REPORT_REG0_AGC_TOTAL_GAIN), | ||
1402 | MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_DIFF)); | ||
1403 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1404 | "wmi phyerr radar report pulse_delta_pean %d pulse_sidx %d fft_valid %d agc_mb_gain %d subchan_mask %d\n", | ||
1405 | MS(reg0, RADAR_REPORT_REG0_PULSE_DELTA_PEAK), | ||
1406 | MS(reg0, RADAR_REPORT_REG0_PULSE_SIDX), | ||
1407 | MS(reg1, RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID), | ||
1408 | MS(reg1, RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN), | ||
1409 | MS(reg1, RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK)); | ||
1410 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1411 | "wmi phyerr radar report pulse_tsf_offset 0x%X pulse_dur: %d\n", | ||
1412 | MS(reg1, RADAR_REPORT_REG1_PULSE_TSF_OFFSET), | ||
1413 | MS(reg1, RADAR_REPORT_REG1_PULSE_DUR)); | ||
1414 | |||
1415 | if (!ar->dfs_detector) | ||
1416 | return; | ||
1417 | |||
1418 | /* report event to DFS pattern detector */ | ||
1419 | tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp); | ||
1420 | tsf64 = tsf & (~0xFFFFFFFFULL); | ||
1421 | tsf64 |= tsf32l; | ||
1422 | |||
1423 | width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR); | ||
1424 | rssi = event->hdr.rssi_combined; | ||
1425 | |||
1426 | /* hardware store this as 8 bit signed value, | ||
1427 | * set to zero if negative number | ||
1428 | */ | ||
1429 | if (rssi & 0x80) | ||
1430 | rssi = 0; | ||
1431 | |||
1432 | pe.ts = tsf64; | ||
1433 | pe.freq = ar->hw->conf.chandef.chan->center_freq; | ||
1434 | pe.width = width; | ||
1435 | pe.rssi = rssi; | ||
1436 | |||
1437 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1438 | "dfs add pulse freq: %d, width: %d, rssi %d, tsf: %llX\n", | ||
1439 | pe.freq, pe.width, pe.rssi, pe.ts); | ||
1440 | |||
1441 | ATH10K_DFS_STAT_INC(ar, pulses_detected); | ||
1442 | |||
1443 | if (!ar->dfs_detector->add_pulse(ar->dfs_detector, &pe)) { | ||
1444 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1445 | "dfs no pulse pattern detected, yet\n"); | ||
1446 | return; | ||
1447 | } | ||
1448 | |||
1449 | ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs radar detected\n"); | ||
1450 | ATH10K_DFS_STAT_INC(ar, radar_detected); | ||
1451 | ieee80211_radar_detected(ar->hw); | ||
1452 | } | ||
1453 | |||
1454 | static int ath10k_dfs_fft_report(struct ath10k *ar, | ||
1455 | struct wmi_single_phyerr_rx_event *event, | ||
1456 | struct phyerr_fft_report *fftr, | ||
1457 | u64 tsf) | ||
1458 | { | ||
1459 | u32 reg0, reg1; | ||
1460 | u8 rssi, peak_mag; | ||
1461 | |||
1462 | reg0 = __le32_to_cpu(fftr->reg0); | ||
1463 | reg1 = __le32_to_cpu(fftr->reg1); | ||
1464 | rssi = event->hdr.rssi_combined; | ||
1465 | |||
1466 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1467 | "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", | ||
1468 | MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB), | ||
1469 | MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB), | ||
1470 | MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX), | ||
1471 | MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX)); | ||
1472 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1473 | "wmi phyerr fft report rel_pwr_db %d avgpwr_db %d peak_mag %d num_store_bin %d\n", | ||
1474 | MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB), | ||
1475 | MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB), | ||
1476 | MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG), | ||
1477 | MS(reg1, SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB)); | ||
1478 | |||
1479 | peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); | ||
1480 | |||
1481 | /* false event detection */ | ||
1482 | if (rssi == DFS_RSSI_POSSIBLY_FALSE && | ||
1483 | peak_mag < 2 * DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE) { | ||
1484 | ath10k_dbg(ATH10K_DBG_REGULATORY, "dfs false pulse detected\n"); | ||
1485 | ATH10K_DFS_STAT_INC(ar, pulses_discarded); | ||
1486 | return -EINVAL; | ||
1487 | } | ||
1488 | |||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | static void ath10k_wmi_event_dfs(struct ath10k *ar, | ||
1493 | struct wmi_single_phyerr_rx_event *event, | ||
1494 | u64 tsf) | ||
1495 | { | ||
1496 | int buf_len, tlv_len, res, i = 0; | ||
1497 | struct phyerr_tlv *tlv; | ||
1498 | struct phyerr_radar_report *rr; | ||
1499 | struct phyerr_fft_report *fftr; | ||
1500 | u8 *tlv_buf; | ||
1501 | |||
1502 | buf_len = __le32_to_cpu(event->hdr.buf_len); | ||
1503 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1504 | "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", | ||
1505 | event->hdr.phy_err_code, event->hdr.rssi_combined, | ||
1506 | __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); | ||
1507 | |||
1508 | /* Skip event if DFS disabled */ | ||
1509 | if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) | ||
1510 | return; | ||
1511 | |||
1512 | ATH10K_DFS_STAT_INC(ar, pulses_total); | ||
1513 | |||
1514 | while (i < buf_len) { | ||
1515 | if (i + sizeof(*tlv) > buf_len) { | ||
1516 | ath10k_warn("too short buf for tlv header (%d)\n", i); | ||
1517 | return; | ||
1518 | } | ||
1519 | |||
1520 | tlv = (struct phyerr_tlv *)&event->bufp[i]; | ||
1521 | tlv_len = __le16_to_cpu(tlv->len); | ||
1522 | tlv_buf = &event->bufp[i + sizeof(*tlv)]; | ||
1523 | ath10k_dbg(ATH10K_DBG_REGULATORY, | ||
1524 | "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", | ||
1525 | tlv_len, tlv->tag, tlv->sig); | ||
1526 | |||
1527 | switch (tlv->tag) { | ||
1528 | case PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY: | ||
1529 | if (i + sizeof(*tlv) + sizeof(*rr) > buf_len) { | ||
1530 | ath10k_warn("too short radar pulse summary (%d)\n", | ||
1531 | i); | ||
1532 | return; | ||
1533 | } | ||
1534 | |||
1535 | rr = (struct phyerr_radar_report *)tlv_buf; | ||
1536 | ath10k_dfs_radar_report(ar, event, rr, tsf); | ||
1537 | break; | ||
1538 | case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: | ||
1539 | if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { | ||
1540 | ath10k_warn("too short fft report (%d)\n", i); | ||
1541 | return; | ||
1542 | } | ||
1543 | |||
1544 | fftr = (struct phyerr_fft_report *)tlv_buf; | ||
1545 | res = ath10k_dfs_fft_report(ar, event, fftr, tsf); | ||
1546 | if (res) | ||
1547 | return; | ||
1548 | break; | ||
1549 | } | ||
1550 | |||
1551 | i += sizeof(*tlv) + tlv_len; | ||
1552 | } | ||
1553 | } | ||
1554 | |||
1555 | static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, | ||
1556 | struct wmi_single_phyerr_rx_event *event, | ||
1557 | u64 tsf) | ||
1558 | { | ||
1559 | ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n"); | ||
1560 | } | ||
1561 | |||
1384 | static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) | 1562 | static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) |
1385 | { | 1563 | { |
1386 | ath10k_dbg(ATH10K_DBG_WMI, "WMI_PHYERR_EVENTID\n"); | 1564 | struct wmi_comb_phyerr_rx_event *comb_event; |
1565 | struct wmi_single_phyerr_rx_event *event; | ||
1566 | u32 count, i, buf_len, phy_err_code; | ||
1567 | u64 tsf; | ||
1568 | int left_len = skb->len; | ||
1569 | |||
1570 | ATH10K_DFS_STAT_INC(ar, phy_errors); | ||
1571 | |||
1572 | /* Check if combined event available */ | ||
1573 | if (left_len < sizeof(*comb_event)) { | ||
1574 | ath10k_warn("wmi phyerr combined event wrong len\n"); | ||
1575 | return; | ||
1576 | } | ||
1577 | |||
1578 | left_len -= sizeof(*comb_event); | ||
1579 | |||
1580 | /* Check number of included events */ | ||
1581 | comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data; | ||
1582 | count = __le32_to_cpu(comb_event->hdr.num_phyerr_events); | ||
1583 | |||
1584 | tsf = __le32_to_cpu(comb_event->hdr.tsf_u32); | ||
1585 | tsf <<= 32; | ||
1586 | tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); | ||
1587 | |||
1588 | ath10k_dbg(ATH10K_DBG_WMI, | ||
1589 | "wmi event phyerr count %d tsf64 0x%llX\n", | ||
1590 | count, tsf); | ||
1591 | |||
1592 | event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp; | ||
1593 | for (i = 0; i < count; i++) { | ||
1594 | /* Check if we can read event header */ | ||
1595 | if (left_len < sizeof(*event)) { | ||
1596 | ath10k_warn("single event (%d) wrong head len\n", i); | ||
1597 | return; | ||
1598 | } | ||
1599 | |||
1600 | left_len -= sizeof(*event); | ||
1601 | |||
1602 | buf_len = __le32_to_cpu(event->hdr.buf_len); | ||
1603 | phy_err_code = event->hdr.phy_err_code; | ||
1604 | |||
1605 | if (left_len < buf_len) { | ||
1606 | ath10k_warn("single event (%d) wrong buf len\n", i); | ||
1607 | return; | ||
1608 | } | ||
1609 | |||
1610 | left_len -= buf_len; | ||
1611 | |||
1612 | switch (phy_err_code) { | ||
1613 | case PHY_ERROR_RADAR: | ||
1614 | ath10k_wmi_event_dfs(ar, event, tsf); | ||
1615 | break; | ||
1616 | case PHY_ERROR_SPECTRAL_SCAN: | ||
1617 | ath10k_wmi_event_spectral_scan(ar, event, tsf); | ||
1618 | break; | ||
1619 | case PHY_ERROR_FALSE_RADAR_EXT: | ||
1620 | ath10k_wmi_event_dfs(ar, event, tsf); | ||
1621 | ath10k_wmi_event_spectral_scan(ar, event, tsf); | ||
1622 | break; | ||
1623 | default: | ||
1624 | break; | ||
1625 | } | ||
1626 | |||
1627 | event += sizeof(*event) + buf_len; | ||
1628 | } | ||
1387 | } | 1629 | } |
1388 | 1630 | ||
1389 | static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) | 1631 | static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) |
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 8b824f9c2f1e..e71273e65c5d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h | |||
@@ -1978,6 +1978,10 @@ struct wmi_mgmt_rx_event_v2 { | |||
1978 | #define WMI_RX_STATUS_ERR_MIC 0x10 | 1978 | #define WMI_RX_STATUS_ERR_MIC 0x10 |
1979 | #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS 0x20 | 1979 | #define WMI_RX_STATUS_ERR_KEY_CACHE_MISS 0x20 |
1980 | 1980 | ||
1981 | #define PHY_ERROR_SPECTRAL_SCAN 0x26 | ||
1982 | #define PHY_ERROR_FALSE_RADAR_EXT 0x24 | ||
1983 | #define PHY_ERROR_RADAR 0x05 | ||
1984 | |||
1981 | struct wmi_single_phyerr_rx_hdr { | 1985 | struct wmi_single_phyerr_rx_hdr { |
1982 | /* TSF timestamp */ | 1986 | /* TSF timestamp */ |
1983 | __le32 tsf_timestamp; | 1987 | __le32 tsf_timestamp; |
@@ -2069,6 +2073,87 @@ struct wmi_comb_phyerr_rx_event { | |||
2069 | u8 bufp[0]; | 2073 | u8 bufp[0]; |
2070 | } __packed; | 2074 | } __packed; |
2071 | 2075 | ||
2076 | #define PHYERR_TLV_SIG 0xBB | ||
2077 | #define PHYERR_TLV_TAG_SEARCH_FFT_REPORT 0xFB | ||
2078 | #define PHYERR_TLV_TAG_RADAR_PULSE_SUMMARY 0xF8 | ||
2079 | |||
2080 | struct phyerr_radar_report { | ||
2081 | __le32 reg0; /* RADAR_REPORT_REG0_* */ | ||
2082 | __le32 reg1; /* REDAR_REPORT_REG1_* */ | ||
2083 | } __packed; | ||
2084 | |||
2085 | #define RADAR_REPORT_REG0_PULSE_IS_CHIRP_MASK 0x80000000 | ||
2086 | #define RADAR_REPORT_REG0_PULSE_IS_CHIRP_LSB 31 | ||
2087 | |||
2088 | #define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_MASK 0x40000000 | ||
2089 | #define RADAR_REPORT_REG0_PULSE_IS_MAX_WIDTH_LSB 30 | ||
2090 | |||
2091 | #define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_MASK 0x3FF00000 | ||
2092 | #define RADAR_REPORT_REG0_AGC_TOTAL_GAIN_LSB 20 | ||
2093 | |||
2094 | #define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_MASK 0x000F0000 | ||
2095 | #define RADAR_REPORT_REG0_PULSE_DELTA_DIFF_LSB 16 | ||
2096 | |||
2097 | #define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_MASK 0x0000FC00 | ||
2098 | #define RADAR_REPORT_REG0_PULSE_DELTA_PEAK_LSB 10 | ||
2099 | |||
2100 | #define RADAR_REPORT_REG0_PULSE_SIDX_MASK 0x000003FF | ||
2101 | #define RADAR_REPORT_REG0_PULSE_SIDX_LSB 0 | ||
2102 | |||
2103 | #define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_MASK 0x80000000 | ||
2104 | #define RADAR_REPORT_REG1_PULSE_SRCH_FFT_VALID_LSB 31 | ||
2105 | |||
2106 | #define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_MASK 0x7F000000 | ||
2107 | #define RADAR_REPORT_REG1_PULSE_AGC_MB_GAIN_LSB 24 | ||
2108 | |||
2109 | #define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_MASK 0x00FF0000 | ||
2110 | #define RADAR_REPORT_REG1_PULSE_SUBCHAN_MASK_LSB 16 | ||
2111 | |||
2112 | #define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_MASK 0x0000FF00 | ||
2113 | #define RADAR_REPORT_REG1_PULSE_TSF_OFFSET_LSB 8 | ||
2114 | |||
2115 | #define RADAR_REPORT_REG1_PULSE_DUR_MASK 0x000000FF | ||
2116 | #define RADAR_REPORT_REG1_PULSE_DUR_LSB 0 | ||
2117 | |||
2118 | struct phyerr_fft_report { | ||
2119 | __le32 reg0; /* SEARCH_FFT_REPORT_REG0_ * */ | ||
2120 | __le32 reg1; /* SEARCH_FFT_REPORT_REG1_ * */ | ||
2121 | } __packed; | ||
2122 | |||
2123 | #define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_MASK 0xFF800000 | ||
2124 | #define SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB_LSB 23 | ||
2125 | |||
2126 | #define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_MASK 0x007FC000 | ||
2127 | #define SEARCH_FFT_REPORT_REG0_BASE_PWR_DB_LSB 14 | ||
2128 | |||
2129 | #define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_MASK 0x00003000 | ||
2130 | #define SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX_LSB 12 | ||
2131 | |||
2132 | #define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_MASK 0x00000FFF | ||
2133 | #define SEARCH_FFT_REPORT_REG0_PEAK_SIDX_LSB 0 | ||
2134 | |||
2135 | #define SEARCH_FFT_REPORT_REG1_RELPWR_DB_MASK 0xFC000000 | ||
2136 | #define SEARCH_FFT_REPORT_REG1_RELPWR_DB_LSB 26 | ||
2137 | |||
2138 | #define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_MASK 0x03FC0000 | ||
2139 | #define SEARCH_FFT_REPORT_REG1_AVGPWR_DB_LSB 18 | ||
2140 | |||
2141 | #define SEARCH_FFT_REPORT_REG1_PEAK_MAG_MASK 0x0003FF00 | ||
2142 | #define SEARCH_FFT_REPORT_REG1_PEAK_MAG_LSB 8 | ||
2143 | |||
2144 | #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_MASK 0x000000FF | ||
2145 | #define SEARCH_FFT_REPORT_REG1_NUM_STR_BINS_IB_LSB 0 | ||
2146 | |||
2147 | |||
2148 | struct phyerr_tlv { | ||
2149 | __le16 len; | ||
2150 | u8 tag; | ||
2151 | u8 sig; | ||
2152 | } __packed; | ||
2153 | |||
2154 | #define DFS_RSSI_POSSIBLY_FALSE 50 | ||
2155 | #define DFS_PEAK_MAG_THOLD_POSSIBLY_FALSE 40 | ||
2156 | |||
2072 | struct wmi_mgmt_tx_hdr { | 2157 | struct wmi_mgmt_tx_hdr { |
2073 | __le32 vdev_id; | 2158 | __le32 vdev_id; |
2074 | struct wmi_mac_addr peer_macaddr; | 2159 | struct wmi_mac_addr peer_macaddr; |