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 /drivers/net/wireless/ath/ath10k/wmi.c | |
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>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/wmi.c | 244 |
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 | ||
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) |