aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/wmi.c
diff options
context:
space:
mode:
authorJanusz Dziedzic <janusz.dziedzic@tieto.com>2013-11-20 02:59:41 -0500
committerKalle Valo <kvalo@qca.qualcomm.com>2013-11-20 02:59:41 -0500
commit9702c686081240bff1f05150c78335152d37ac8d (patch)
treefec0e4e91baf4545aa7efb0de7455fc3d7a4f270 /drivers/net/wireless/ath/ath10k/wmi.c
parent5d04e4120a6ef2eac3a3a80bda6a16bb90f2da2c (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>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c244
1 files changed, 243 insertions, 1 deletions
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
1384static 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
1454static 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
1492static 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
1555static 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
1384static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) 1562static 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
1389static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb) 1631static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)