diff --git a/ath10k-4.13/core.c b/ath10k-4.13/core.c index 56d3079..18c5e2d 100644 --- a/ath10k-4.13/core.c +++ b/ath10k-4.13/core.c @@ -400,6 +400,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_NO_BMISS_CT] = "no-bmiss-CT", [ATH10K_FW_FEATURE_HAS_GET_TEMP_CT] = "get-temp-CT", [ATH10K_FW_FEATURE_HAS_TX_RC_CT] = "tx-rc-CT", + [ATH10K_FW_FEATURE_CUST_STATS_CT] = "cust-stats-CT", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -2110,6 +2111,7 @@ static void ath10k_core_restart(struct work_struct *work) * with conf_mutex it will deadlock. */ cancel_work_sync(&ar->set_coverage_class_work); + cancel_work_sync(&ar->stop_scan_work); mutex_lock(&ar->conf_mutex); @@ -2488,6 +2490,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); + ar->ok_tx_rate_status = false; ar->running_fw = fw; ath10k_bmi_start(ar); @@ -3206,6 +3209,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, INIT_WORK(&ar->restart_work, ath10k_core_restart); INIT_WORK(&ar->set_coverage_class_work, ath10k_core_set_coverage_class_work); + INIT_WORK(&ar->stop_scan_work, ath10k_wmi_stop_scan_work); init_dummy_netdev(&ar->napi_dev); diff --git a/ath10k-4.13/core.h b/ath10k-4.13/core.h index 14710e9..d2817d7 100644 --- a/ath10k-4.13/core.h +++ b/ath10k-4.13/core.h @@ -540,6 +540,7 @@ struct ath10k_fw_crash_data { struct ath10k_debug { struct dentry *debugfs_phy; + struct ath10k_rx_reorder_stats rx_reorder_stats; struct ath10k_fw_stats fw_stats; struct completion fw_stats_complete; bool fw_stats_done; @@ -570,6 +571,10 @@ struct ath10k_debug { /* These counters are kept in software. */ u64 rx_bytes; /* counter, total received bytes */ + u32 rx_drop_unchain_oom; /* AMSDU Dropped due to un-chain OOM case */ + u32 rx_drop_decap_non_raw_chained; + u32 rx_drop_no_freq; + u32 rx_drop_cac_running; u32 tx_ok; /* counter, OK tx status count. */ u32 tx_noack; /* counter, no-ack tx status count. */ @@ -760,6 +765,9 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_HAS_TX_RC_CT = 45, + /* Do we support requesting custom stats */ + ATH10K_FW_FEATURE_CUST_STATS_CT = 46, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -927,6 +935,7 @@ struct ath10k { enum ath10k_hw_rev hw_rev; u16 dev_id; + bool ok_tx_rate_status; /* Firmware is sending tx-rate status? (CT only) */ bool fw_powerup_failed; /* If true, might take reboot to recover. */ u32 chip_id; u32 target_version; @@ -1191,6 +1200,8 @@ struct ath10k { struct net_device napi_dev; struct napi_struct napi; + struct work_struct stop_scan_work; + struct work_struct set_coverage_class_work; /* protected by conf_mutex */ struct { diff --git a/ath10k-4.13/debug.c b/ath10k-4.13/debug.c index e97cff9..d0b22bc 100644 --- a/ath10k-4.13/debug.c +++ b/ath10k-4.13/debug.c @@ -494,7 +494,45 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); + /*ath10k_warn(ar, "fw-stats-process: stats-id: 0x%x(0x%x)\n", ev->stats_id, __le32_to_cpu(ev->stats_id));*/ /* CT Firmware only */ + if (__le32_to_cpu(ev->stats_id) == WMI_REQUEST_STAT_CUSTOM) { + __le32* data; + u32 stats_len; + u32 *my_stats = NULL; + u32 my_len = 0; + + if ((ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_2) || + (ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_4) || + (ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_2_4)) { + const struct wmi_10_2_stats_event *ev2 = (void *)skb->data; + data = (__le32*)(ev2->data); + stats_len = (skb->len - sizeof(*ev2)) / 4; + } else { + /* Must be 10.1 */ + data = (__le32*)(ev->data); + stats_len = (skb->len - sizeof(*ev)) / 4; + } + + if (ev->num_pdev_stats == WMI_STAT_CUSTOM_RX_REORDER_STATS) { + my_len = sizeof(ar->debug.rx_reorder_stats) / 4; + my_len = min(my_len, stats_len); + my_stats = (u32*)(&(ar->debug.rx_reorder_stats)); + } + + /* If we know about the stats, handle it here. */ + if (my_stats) { + int i; + for (i = 0; idebug.fw_stats_done = true; + complete(&ar->debug.fw_stats_complete); + /*ath10k_warn(ar, "Completed stat-custom, my_len: %u\n", my_len);*/ + goto free; + } + if (__le32_to_cpu(ev->stats_id) == WMI_REQUEST_REGISTER_DUMP) { struct ath10k_reg_dump* regdump; struct ath10k_fw_stats* sptr = &ar->debug.fw_stats; @@ -586,6 +624,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) break; }/* switch */ } + ar->debug.fw_stats_done = true; complete(&ar->debug.fw_stats_complete); goto free; } @@ -752,23 +791,29 @@ static int ath10k_fw_stats_release(struct inode *inode, struct file *file) return 0; } -int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type) +static int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type, u32 specifier) { int ret; unsigned long time_left; + /*ath10k_warn(ar, "Requesting stats (type 0x%x specifier %d jiffies: %lu)\n", + type, specifier, jiffies);*/ reinit_completion(&ar->debug.fw_stats_complete); - ret = ath10k_wmi_request_stats(ar, type); + ret = ath10k_wmi_request_stats(ar, type, specifier); if (ret) { - ath10k_warn(ar, "could not request stats (type %d ret %d)\n", - type, ret); + ath10k_warn(ar, "could not request stats (type %d ret %d specifier %d)\n", + type, ret, specifier); return ret; } /* ret means 'time-left' here */ time_left = wait_for_completion_timeout(&ar->debug.fw_stats_complete, 1*HZ); + + /* ath10k_warn(ar, "Requested stats (type 0x%x ret %d specifier %d jiffies: %lu time-left: %lu)\n", + type, ret, specifier, jiffies, time_left);*/ + if (time_left == 0) return -ETIMEDOUT; @@ -777,17 +822,112 @@ int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type) int ath10k_refresh_peer_stats(struct ath10k *ar) { - return ath10k_refresh_peer_stats_t(ar, ar->fw_stats_req_mask); + return ath10k_refresh_peer_stats_t(ar, ar->fw_stats_req_mask, 0); } int ath10k_refresh_target_regs(struct ath10k *ar) { if (test_bit(ATH10K_FW_FEATURE_REGDUMP_CT, ar->running_fw->fw_file.fw_features)) - return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_REGISTER_DUMP); + return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_REGISTER_DUMP, 0); return 0; /* fail silently if firmware does not support this option. */ } +int ath10k_refresh_target_rx_reorder_stats(struct ath10k *ar) +{ + if (test_bit(ATH10K_FW_FEATURE_CUST_STATS_CT, + ar->running_fw->fw_file.fw_features)) + return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_STAT_CUSTOM, WMI_STAT_CUSTOM_RX_REORDER_STATS); + return 0; /* fail silently if firmware does not support this option. */ +} + + +static ssize_t ath10k_read_rx_reorder_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + struct ath10k_rx_reorder_stats *rrs; + char *buf = NULL; + unsigned int len = 0, buf_len = 8000; + ssize_t ret_cnt = 0; + int ret; + + mutex_lock(&ar->conf_mutex); + + rrs = &ar->debug.rx_reorder_stats; + + if (ar->state != ATH10K_STATE_ON) + goto exit; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + goto exit; + + ret = ath10k_refresh_target_rx_reorder_stats(ar); + if (ret) + goto exit; + + len += scnprintf(buf + len, buf_len - len, "\n"); + len += scnprintf(buf + len, buf_len - len, "%30s\n", + "ath10k RX Reorder Stats"); + len += scnprintf(buf + len, buf_len - len, "%30s\n\n", + "================="); + +#define PRINT_MY_STATS(a) len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", #a, rrs->a) + /* Non QoS MPDUs received */ + PRINT_MY_STATS(deliver_non_qos); + /* MPDUs received in-order */ + PRINT_MY_STATS(deliver_in_order); + /* Flush due to reorder timer expired */ + PRINT_MY_STATS(deliver_flush_timeout); + /* Flush due to move out of window */ + PRINT_MY_STATS(deliver_flush_oow); + /* Flush due to DELBA */ + PRINT_MY_STATS(deliver_flush_delba); + /* MPDUs dropped due to FCS error */ + PRINT_MY_STATS(fcs_error); + /* MPDUs dropped due to monitor mode non-data packet */ + PRINT_MY_STATS(mgmt_ctrl); + /* MPDUs dropped due to invalid peer */ + PRINT_MY_STATS(invalid_peer); + /* MPDUs dropped due to duplication (non aggregation) */ + PRINT_MY_STATS(dup_non_aggr); + /* MPDUs dropped due to processed before */ + PRINT_MY_STATS(dup_past); + /* MPDUs dropped due to duplicate in reorder queue */ + PRINT_MY_STATS(dup_in_reorder); + /* Reorder timeout happened */ + PRINT_MY_STATS(reorder_timeout); + /* invalid bar ssn */ + PRINT_MY_STATS(invalid_bar_ssn); + /* reorder reset due to bar ssn */ + PRINT_MY_STATS(ssn_reset); + + /* Added by Ben */ + PRINT_MY_STATS(frag_invalid_peer); + PRINT_MY_STATS(frag_fcs_error); + PRINT_MY_STATS(frag_ok); + PRINT_MY_STATS(frag_discards); + + PRINT_MY_STATS(rx_chatter); + PRINT_MY_STATS(tkip_mic_error); + PRINT_MY_STATS(tkip_decrypt_error); + PRINT_MY_STATS(mpdu_length_error); + PRINT_MY_STATS(non_frag_unicast_ok); + + PRINT_MY_STATS(rx_flush_ind); // Flushed these due to timeout, etc. + PRINT_MY_STATS(rx_flush_ie_add); // Flushed these due to timeout, etc + + if (len > buf_len) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + +exit: + mutex_unlock(&ar->conf_mutex); + kfree(buf); + return ret_cnt; +} static ssize_t ath10k_read_fw_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -966,6 +1106,13 @@ static const struct file_operations fops_fw_regs = { .llseek = default_llseek, }; +static const struct file_operations fops_rx_reorder_stats = { + .read = ath10k_read_rx_reorder_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath10k_read_simulate_fw_crash(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2125,6 +2272,10 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_bytes_to_fw", /* sent to firmware, counts all failures */ "rx_pkts_nic", /* From firmware...maybe should be from driver for symmetry? */ "rx_bytes_nic", /* from driver, firmware does not keep this stat. */ + "rx_drop_unchain_oom", /* Dropped due to OOM pressure in unchain_msdu path */ + "rx_drop_decap_non_raw_chained", + "rx_drop_no_freq", + "rx_drop_cac_running", "d_noise_floor", "d_cycle_count", /* this is duty cycle counter, basically channel-time. 88MHz clock */ "d_tx_cycle_count", /* tx cycle count */ @@ -2243,6 +2394,10 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, data[i++] = ar->debug.tx_bytes; data[i++] = pdev_stats->htt_mpdus; data[i++] = ar->debug.rx_bytes; + data[i++] = ar->debug.rx_drop_unchain_oom; + data[i++] = ar->debug.rx_drop_decap_non_raw_chained; + data[i++] = ar->debug.rx_drop_no_freq; + data[i++] = ar->debug.rx_drop_cac_running; data[i++] = pdev_stats->ch_noise_floor; data[i++] = pdev_stats->cycle_count; data[i++] = pdev_stats->tx_frame_count; @@ -3541,6 +3696,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_regs", 0400, ar->debug.debugfs_phy, ar, &fops_fw_regs); + debugfs_create_file("rx_reorder_stats", 0400, ar->debug.debugfs_phy, ar, + &fops_rx_reorder_stats); + debugfs_create_file("wmi_services", 0400, ar->debug.debugfs_phy, ar, &fops_wmi_services); diff --git a/ath10k-4.13/htt_rx.c b/ath10k-4.13/htt_rx.c index 356bc50..83eb7b2 100644 --- a/ath10k-4.13/htt_rx.c +++ b/ath10k-4.13/htt_rx.c @@ -855,6 +855,8 @@ static void ath10k_htt_rx_h_signal(struct ath10k *ar, /* FIXME: Get real NF */ status->signal = ATH10K_DEFAULT_NOISE_FLOOR + rxd->ppdu_start.rssi_comb; + /* ath10k_warn(ar, "rx-h-sig, signal: %d chains: 0x%x chain[0]: %d chain[1]: %d chan[2]: %d\n", + status->signal, status->chains, status->chain_signal[0], status->chain_signal[1], status->chain_signal[2]); */ status->flag &= ~RX_FLAG_NO_SIGNAL_VAL; } @@ -1530,7 +1532,7 @@ static void ath10k_htt_rx_h_deliver(struct ath10k *ar, } } -static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) +static int ath10k_unchain_msdu(struct ath10k *ar, struct sk_buff_head *amsdu) { struct sk_buff *skb, *first; int space; @@ -1552,10 +1554,10 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) space = total_len - skb_tailroom(first); if ((space > 0) && (pskb_expand_head(first, 0, space, GFP_ATOMIC) < 0)) { - /* TODO: bump some rx-oom error stat */ /* put it back together so we can free the * whole list at once. */ + ar->debug.rx_drop_unchain_oom++; __skb_queue_head(amsdu, first); return -1; } @@ -1592,11 +1594,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, */ if (decap != RX_MSDU_DECAP_RAW || skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { + ar->debug.rx_drop_decap_non_raw_chained++; __skb_queue_purge(amsdu); return; } - ath10k_unchain_msdu(amsdu); + ath10k_unchain_msdu(ar, amsdu); } static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, @@ -1609,11 +1612,13 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, if (!rx_status->freq) { ath10k_warn(ar, "no channel configured; ignoring frame(s)!\n"); + ar->debug.rx_drop_no_freq++; return false; } if (test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags)) { ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx cac running\n"); + ar->debug.rx_drop_cac_running++; return false; } diff --git a/ath10k-4.13/mac.c b/ath10k-4.13/mac.c index 3c03edf..fb7a615 100644 --- a/ath10k-4.13/mac.c +++ b/ath10k-4.13/mac.c @@ -6296,6 +6296,9 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac hw-scan called, scan.state: %d\n", ar->scan.state); + switch (ar->scan.state) { case ATH10K_SCAN_IDLE: reinit_completion(&ar->scan.started); @@ -6309,6 +6312,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: ret = -EBUSY; + ath10k_warn(ar, "failed to start hw scan (busy): scan-state: %d\n", ar->scan.state); break; } spin_unlock_bh(&ar->data_lock); @@ -6383,6 +6387,8 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cancel-hw-scan called\n"); + mutex_lock(&ar->conf_mutex); ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); diff --git a/ath10k-4.13/txrx.c b/ath10k-4.13/txrx.c index cbfcadb..2f60442 100644 --- a/ath10k-4.13/txrx.c +++ b/ath10k-4.13/txrx.c @@ -201,7 +201,12 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, (info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - if (tx_done->tx_rate_code || tx_done->tx_rate_flags) { + if (tx_done->tx_rate_code || tx_done->tx_rate_flags || ar->ok_tx_rate_status) { + /* rate-code for 48Mbps is 0, with no flags, so we need to remember + * any other valid rates we might have seen and use that to know if + * firmware is sending tx rates. + */ + ar->ok_tx_rate_status = true; ath10k_set_tx_rate_status(ar, &info->status.rates[0], tx_done); /* Only in version 14 and higher of CT firmware */ diff --git a/ath10k-4.13/wmi-ops.h b/ath10k-4.13/wmi-ops.h index a95d42c..c7cdeec 100644 --- a/ath10k-4.13/wmi-ops.h +++ b/ath10k-4.13/wmi-ops.h @@ -122,7 +122,7 @@ struct wmi_ops { bool deliver_cab); struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, const struct wmi_wmm_params_all_arg *arg); - struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask); + struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask, u32 specifier); struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, enum wmi_force_fw_hang_type type, u32 delay_ms); @@ -938,14 +938,14 @@ ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, } static inline int -ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct sk_buff *skb; if (!ar->wmi.ops->gen_request_stats) return -EOPNOTSUPP; - skb = ar->wmi.ops->gen_request_stats(ar, stats_mask); + skb = ar->wmi.ops->gen_request_stats(ar, stats_mask, specifier); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/ath10k-4.13/wmi-tlv.c b/ath10k-4.13/wmi-tlv.c index 3244e20..9858637 100644 --- a/ath10k-4.13/wmi-tlv.c +++ b/ath10k-4.13/wmi-tlv.c @@ -2429,7 +2429,7 @@ ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct wmi_request_stats_cmd *cmd; struct wmi_tlv *tlv; diff --git a/ath10k-4.13/wmi.c b/ath10k-4.13/wmi.c index 905af93..0d2769b 100644 --- a/ath10k-4.13/wmi.c +++ b/ath10k-4.13/wmi.c @@ -1971,6 +1971,27 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar) } } +void ath10k_wmi_stop_scan_work(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, + stop_scan_work); + /* Kick firmware to get us back in sync */ + struct wmi_stop_scan_arg arg = { + .req_id = 1, /* FIXME */ + .req_type = WMI_SCAN_STOP_ONE, + .u.scan_id = ATH10K_SCAN_ID, + }; + int ret; + + ath10k_warn(ar, "calling wmi-stop-scan from wmi-stop-scan-work\n"); + + mutex_lock(&ar->conf_mutex); + ret = ath10k_wmi_stop_scan(ar, &arg); + if (ret) + ath10k_warn(ar, "stop-scan-work: failed to stop wmi scan: %d\n", ret); + mutex_unlock(&ar->conf_mutex); +} + static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar, enum wmi_scan_completion_reason reason) { @@ -1986,16 +2007,14 @@ static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar, break; case ATH10K_SCAN_STARTING: complete(&ar->scan.started); + __ath10k_scan_finish(ar); if (reason == WMI_SCAN_REASON_BUSY) { - /* Kick firmware to get us back in sync */ - struct wmi_stop_scan_arg arg = { - .req_id = 1, /* FIXME */ - .req_type = WMI_SCAN_STOP_ONE, - .u.scan_id = ATH10K_SCAN_ID, - }; - ath10k_wmi_stop_scan(ar, &arg); + /* Cannot make WMI calls directly here, we are under data_lock and at + * least sometimes in IRQ context. + */ + ath10k_warn(ar, "received scan start failed event in scan-starting state, will request stop-scan-work\n"); + queue_work(ar->workqueue, &ar->stop_scan_work); } - __ath10k_scan_finish(ar); break; } } @@ -2236,6 +2255,8 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, size_t pull_len; u32 msdu_len; u32 len; + u32 snr; + u32 channel; if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->running_fw->fw_file.fw_features)) { @@ -2259,6 +2280,24 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, arg->phy_mode = ev_hdr->phy_mode; arg->rate = ev_hdr->rate; + snr = __le32_to_cpu(arg->snr); + channel = __le32_to_cpu(arg->channel); + + /* Recent CT wave-1 firmware can report per-chain values if properly requested... */ + if ((snr & 0xFFFFFF00) || (channel & 0xFF000000)) { + /* pri20_mhz signal */ + arg->rssi_ctl[0] = snr >> 8; + arg->rssi_ctl[1] = snr >> 16; + arg->rssi_ctl[2] = snr >> 24; + snr = snr & 0xFF; + + arg->rssi_ctl[3] = channel >> 24; + channel = channel & 0xFFFFFF; + + arg->snr = __cpu_to_le32(snr); + arg->channel = __cpu_to_le32(channel); + } + msdu_len = __le32_to_cpu(arg->buf_len); if (skb->len < msdu_len) return -EPROTO; @@ -2287,6 +2326,7 @@ static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, u32 msdu_len; struct wmi_mgmt_rx_ext_info *ext_info; u32 len; + int i; ev = (struct wmi_10_4_mgmt_rx_event *)skb->data; ev_hdr = &ev->hdr; @@ -2302,6 +2342,8 @@ static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, arg->snr = ev_hdr->snr; arg->phy_mode = ev_hdr->phy_mode; arg->rate = ev_hdr->rate; + for (i = 0; i<4; i++) + arg->rssi_ctl[i] = ev_hdr->rssi_ctl[i]; msdu_len = __le32_to_cpu(arg->buf_len); if (skb->len < msdu_len) @@ -2357,6 +2399,13 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) u32 buf_len; u16 fc; int ret; + int i; + + /* Initialize the rssi to 'ignore-me' value, stock wave-1 + * firmware doesn't support it. + */ + for (i = 0; i<4; i++) + arg.rssi_ctl[i] = 0x80; ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg); if (ret) { @@ -2416,6 +2465,12 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) status->freq = ieee80211_channel_to_frequency(channel, status->band); status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; + for (i = 0; i<4; i++) { + if (arg.rssi_ctl[i] != 0x80) { + status->chains |= BIT(i); + status->chain_signal[i] = ATH10K_DEFAULT_NOISE_FLOOR + arg.rssi_ctl[i]; + } + } status->rate_idx = ath10k_mac_bitrate_to_idx(sband, rate / 100); hdr = (struct ieee80211_hdr *)skb->data; @@ -2451,8 +2506,11 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); ath10k_dbg(ar, ATH10K_DBG_MGMT, - "event mgmt rx freq %d band %d snr %d, rate_idx %d\n", + "event mgmt rx freq %d band %d snr %d chains: 0x%x(%d %d %d %d), rate_idx %d\n", status->freq, status->band, status->signal, + status->chains, + status->chain_signal[0], status->chain_signal[1], + status->chain_signal[2], status->chain_signal[3], status->rate_idx); ieee80211_rx(ar->hw, skb); @@ -6047,7 +6105,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar) else if (ar->request_nohwcrypt) { ath10k_err(ar, "nohwcrypt requested, but firmware does not support this feature. Disabling swcrypt.\n"); } - config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE); + config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE | ATH10k_MGT_CHAIN_RSSI_OK); /* Disable WoW in firmware, could make this module option perhaps? */ config.rx_decap_mode |= __cpu_to_le32(ATH10k_DISABLE_WOW); config.roam_offload_max_vdev = 0; /* disable roaming */ @@ -6161,7 +6219,7 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) if (test_bit(ATH10K_FW_FEATURE_TXRATE_CT, ar->running_fw->fw_file.fw_features)) - config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE); + config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE | ATH10k_MGT_CHAIN_RSSI_OK); /* Disable WoW in firmware, could make this module option perhaps? */ config.rx_decap_mode |= __cpu_to_le32(ATH10k_DISABLE_WOW); @@ -6290,7 +6348,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) if (test_bit(ATH10K_FW_FEATURE_TXRATE_CT, ar->running_fw->fw_file.fw_features)) { - config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE); + config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE | ATH10k_MGT_CHAIN_RSSI_OK); /* Must enable alloc_frag_desc_for_data_pkt for txrate support. This eats up * 4 extra bytes per msdu descriptor. */ @@ -7507,7 +7565,7 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; @@ -7518,6 +7576,7 @@ ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) cmd = (struct wmi_request_stats_cmd *)skb->data; cmd->stats_id = __cpu_to_le32(stats_mask); + cmd->vdev_id = __cpu_to_le32(specifier); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n", stats_mask); diff --git a/ath10k-4.13/wmi.h b/ath10k-4.13/wmi.h index a3ba191..bda8b74 100644 --- a/ath10k-4.13/wmi.h +++ b/ath10k-4.13/wmi.h @@ -2263,6 +2263,8 @@ struct wmi_resource_config { * that do not need WoW. */ #define ATH10k_DISABLE_WOW 0x40000 + /* Ask CT firmware to send back per-chain management frame RSSI info */ + #define ATH10k_MGT_CHAIN_RSSI_OK 0x80000 __le32 rx_decap_mode; /* what is the maximum number of scan requests that can be queued */ @@ -4296,8 +4298,12 @@ enum wmi_stats_id { WMI_STAT_BCNFLT = BIT(4), WMI_STAT_VDEV_RATE = BIT(5), WMI_REQUEST_REGISTER_DUMP = BIT(7), /* 0x80, CT Firmware only, request register dump. */ + WMI_REQUEST_STAT_CUSTOM = 0xF0000000, /* CT Firmware stats hack, in this case, + * vdev-id is 'stats-id' for requests */ }; +#define WMI_STAT_CUSTOM_RX_REORDER_STATS 0 + enum wmi_10_4_stats_id { WMI_10_4_STAT_PEER = BIT(0), WMI_10_4_STAT_AP = BIT(1), @@ -4305,6 +4311,56 @@ enum wmi_10_4_stats_id { WMI_10_4_STAT_PEER_EXTD = BIT(3), }; +/* + * Rx reorder statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct ath10k_rx_reorder_stats { + /* Non QoS MPDUs received */ + u32 deliver_non_qos; + /* MPDUs received in-order */ + u32 deliver_in_order; + /* Flush due to reorder timer expired */ + u32 deliver_flush_timeout; + /* Flush due to move out of window */ + u32 deliver_flush_oow; + /* Flush due to DELBA */ + u32 deliver_flush_delba; + /* MPDUs dropped due to FCS error */ + u32 fcs_error; + /* MPDUs dropped due to monitor mode non-data packet */ + u32 mgmt_ctrl; + /* MPDUs dropped due to invalid peer */ + u32 invalid_peer; + /* MPDUs dropped due to duplication (non aggregation) */ + u32 dup_non_aggr; + /* MPDUs dropped due to processed before */ + u32 dup_past; + /* MPDUs dropped due to duplicate in reorder queue */ + u32 dup_in_reorder; + /* Reorder timeout happened */ + u32 reorder_timeout; + /* invalid bar ssn */ + u32 invalid_bar_ssn; + /* reorder reset due to bar ssn */ + u32 ssn_reset; + + /* Added by Ben */ + u32 frag_invalid_peer; + u32 frag_fcs_error; + u32 frag_ok; + u32 frag_discards; + + u32 rx_chatter; + u32 tkip_mic_error; + u32 tkip_decrypt_error; + u32 mpdu_length_error; + u32 non_frag_unicast_ok; + + u32 rx_flush_ind; // Flushed these due to timeout, etc. + u32 rx_flush_ie_add; // Flushed these due to timeout, etc +}; + struct wlan_inst_rssi_args { __le16 cfg_retry_count; __le16 retry_count; @@ -4313,7 +4369,7 @@ struct wlan_inst_rssi_args { struct wmi_request_stats_cmd { __le32 stats_id; - __le32 vdev_id; + __le32 vdev_id; /* Or custom-stat identifier if stats_id == WMI_REQUEST_STAT_CUSTOM, CT FW only */ /* peer MAC address */ struct wmi_mac_addr peer_macaddr; @@ -4342,7 +4398,7 @@ struct wmi_stats_event { * number of pdev stats event structures * (wmi_pdev_stats) 0 or 1 */ - __le32 num_pdev_stats; + __le32 num_pdev_stats; /* Or custom-stats-type of stats_id == WMI_REQUEST_STAT_CUSTOM */ /* * number of vdev stats event structures * (wmi_vdev_stats) 0 or max vdevs @@ -6490,6 +6546,7 @@ struct wmi_scan_ev_arg { struct wmi_mgmt_rx_ev_arg { __le32 channel; __le32 snr; + u8 rssi_ctl[4]; __le32 rate; __le32 phy_mode; __le32 buf_len; @@ -6995,6 +7052,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype); int ath10k_wmi_barrier(struct ath10k *ar); +void ath10k_wmi_stop_scan_work(struct work_struct *work); #ifdef CONFIG_ATH10K_DEBUGFS /* TODO: Should really enable this all the time, not just when DEBUGFS is enabled. --Ben */ diff --git a/ath10k-4.9/core.c b/ath10k-4.9/core.c index a14cce4..003a830 100644 --- a/ath10k-4.9/core.c +++ b/ath10k-4.9/core.c @@ -348,6 +348,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_NO_BMISS_CT] = "no-bmiss-CT", [ATH10K_FW_FEATURE_HAS_GET_TEMP_CT] = "get-temp-CT", [ATH10K_FW_FEATURE_HAS_TX_RC_CT] = "tx-rc-CT", + [ATH10K_FW_FEATURE_CUST_STATS_CT] = "cust-stats-CT", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -1987,6 +1988,7 @@ static void ath10k_core_restart(struct work_struct *work) wake_up(&ar->htt.empty_tx_wq); wake_up(&ar->wmi.tx_credits_wq); wake_up(&ar->peer_mapping_wq); + cancel_work_sync(&ar->stop_scan_work); mutex_lock(&ar->conf_mutex); @@ -2350,6 +2352,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); + ar->ok_tx_rate_status = false; ar->running_fw = fw; ath10k_bmi_start(ar); @@ -3050,6 +3053,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, INIT_WORK(&ar->register_work, ath10k_core_register_work); INIT_WORK(&ar->restart_work, ath10k_core_restart); + INIT_WORK(&ar->stop_scan_work, ath10k_wmi_stop_scan_work); init_dummy_netdev(&ar->napi_dev); diff --git a/ath10k-4.9/core.h b/ath10k-4.9/core.h index a513c6c..b8a5bcc 100644 --- a/ath10k-4.9/core.h +++ b/ath10k-4.9/core.h @@ -500,6 +500,7 @@ struct ath10k_fw_crash_data { struct ath10k_debug { struct dentry *debugfs_phy; + struct ath10k_rx_reorder_stats rx_reorder_stats; struct ath10k_fw_stats fw_stats; struct completion fw_stats_complete; bool fw_stats_done; @@ -718,6 +719,9 @@ enum ath10k_fw_features { */ ATH10K_FW_FEATURE_HAS_TX_RC_CT = 45, + /* Do we support requesting custom stats */ + ATH10K_FW_FEATURE_CUST_STATS_CT = 46, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -889,6 +893,7 @@ struct ath10k { enum ath10k_hw_rev hw_rev; u16 dev_id; + bool ok_tx_rate_status; /* Firmware is sending tx-rate status? (CT only) */ bool fw_powerup_failed; /* If true, might take reboot to recover. */ u32 chip_id; u32 target_version; @@ -1145,6 +1150,8 @@ struct ath10k { struct net_device napi_dev; struct napi_struct napi; + struct work_struct stop_scan_work; + /* Index 0 is for 5Ghz, index 1 is for 2.4Ghz, CT firmware only. */ /* be sure to flush this to firmware after resets */ /* Includes various other backdoor hacks as well. */ diff --git a/ath10k-4.9/debug.c b/ath10k-4.9/debug.c index 0e82d4e..71acc7e 100644 --- a/ath10k-4.9/debug.c +++ b/ath10k-4.9/debug.c @@ -494,7 +494,45 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) spin_lock_bh(&ar->data_lock); + /*ath10k_warn(ar, "fw-stats-process: stats-id: 0x%x(0x%x)\n", ev->stats_id, __le32_to_cpu(ev->stats_id));*/ /* CT Firmware only */ + if (__le32_to_cpu(ev->stats_id) == WMI_REQUEST_STAT_CUSTOM) { + __le32* data; + u32 stats_len; + u32 *my_stats = NULL; + u32 my_len = 0; + + if ((ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_2) || + (ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_4) || + (ar->running_fw->fw_file.wmi_op_version == ATH10K_FW_WMI_OP_VERSION_10_2_4)) { + const struct wmi_10_2_stats_event *ev2 = (void *)skb->data; + data = (__le32*)(ev2->data); + stats_len = (skb->len - sizeof(*ev2)) / 4; + } else { + /* Must be 10.1 */ + data = (__le32*)(ev->data); + stats_len = (skb->len - sizeof(*ev)) / 4; + } + + if (ev->num_pdev_stats == WMI_STAT_CUSTOM_RX_REORDER_STATS) { + my_len = sizeof(ar->debug.rx_reorder_stats) / 4; + my_len = min(my_len, stats_len); + my_stats = (u32*)(&(ar->debug.rx_reorder_stats)); + } + + /* If we know about the stats, handle it here. */ + if (my_stats) { + int i; + for (i = 0; idebug.fw_stats_done = true; + complete(&ar->debug.fw_stats_complete); + /*ath10k_warn(ar, "Completed stat-custom, my_len: %u\n", my_len);*/ + goto free; + } + if (__le32_to_cpu(ev->stats_id) == WMI_REQUEST_REGISTER_DUMP) { struct ath10k_reg_dump* regdump; struct ath10k_fw_stats* sptr = &ar->debug.fw_stats; @@ -586,6 +624,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) break; }/* switch */ } + ar->debug.fw_stats_done = true; complete(&ar->debug.fw_stats_complete); goto free; } @@ -749,23 +788,29 @@ static int ath10k_fw_stats_release(struct inode *inode, struct file *file) return 0; } -int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type) +static int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type, u32 specifier) { int ret; unsigned long time_left; + /*ath10k_warn(ar, "Requesting stats (type 0x%x specifier %d jiffies: %lu)\n", + type, specifier, jiffies);*/ reinit_completion(&ar->debug.fw_stats_complete); - ret = ath10k_wmi_request_stats(ar, type); + ret = ath10k_wmi_request_stats(ar, type, specifier); if (ret) { - ath10k_warn(ar, "could not request stats (type %d ret %d)\n", - type, ret); + ath10k_warn(ar, "could not request stats (type %d ret %d specifier %d)\n", + type, ret, specifier); return ret; } /* ret means 'time-left' here */ time_left = wait_for_completion_timeout(&ar->debug.fw_stats_complete, 1*HZ); + + /* ath10k_warn(ar, "Requested stats (type 0x%x ret %d specifier %d jiffies: %lu time-left: %lu)\n", + type, ret, specifier, jiffies, time_left);*/ + if (time_left == 0) return -ETIMEDOUT; @@ -774,17 +819,112 @@ int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type) int ath10k_refresh_peer_stats(struct ath10k *ar) { - return ath10k_refresh_peer_stats_t(ar, ar->fw_stats_req_mask); + return ath10k_refresh_peer_stats_t(ar, ar->fw_stats_req_mask, 0); } int ath10k_refresh_target_regs(struct ath10k *ar) { if (test_bit(ATH10K_FW_FEATURE_REGDUMP_CT, ar->running_fw->fw_file.fw_features)) - return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_REGISTER_DUMP); + return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_REGISTER_DUMP, 0); return 0; /* fail silently if firmware does not support this option. */ } +int ath10k_refresh_target_rx_reorder_stats(struct ath10k *ar) +{ + if (test_bit(ATH10K_FW_FEATURE_CUST_STATS_CT, + ar->running_fw->fw_file.fw_features)) + return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_STAT_CUSTOM, WMI_STAT_CUSTOM_RX_REORDER_STATS); + return 0; /* fail silently if firmware does not support this option. */ +} + + +static ssize_t ath10k_read_rx_reorder_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + struct ath10k_rx_reorder_stats *rrs; + char *buf = NULL; + unsigned int len = 0, buf_len = 8000; + ssize_t ret_cnt = 0; + int ret; + + mutex_lock(&ar->conf_mutex); + + rrs = &ar->debug.rx_reorder_stats; + + if (ar->state != ATH10K_STATE_ON) + goto exit; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + goto exit; + + ret = ath10k_refresh_target_rx_reorder_stats(ar); + if (ret) + goto exit; + + len += scnprintf(buf + len, buf_len - len, "\n"); + len += scnprintf(buf + len, buf_len - len, "%30s\n", + "ath10k RX Reorder Stats"); + len += scnprintf(buf + len, buf_len - len, "%30s\n\n", + "================="); + +#define PRINT_MY_STATS(a) len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", #a, rrs->a) + /* Non QoS MPDUs received */ + PRINT_MY_STATS(deliver_non_qos); + /* MPDUs received in-order */ + PRINT_MY_STATS(deliver_in_order); + /* Flush due to reorder timer expired */ + PRINT_MY_STATS(deliver_flush_timeout); + /* Flush due to move out of window */ + PRINT_MY_STATS(deliver_flush_oow); + /* Flush due to DELBA */ + PRINT_MY_STATS(deliver_flush_delba); + /* MPDUs dropped due to FCS error */ + PRINT_MY_STATS(fcs_error); + /* MPDUs dropped due to monitor mode non-data packet */ + PRINT_MY_STATS(mgmt_ctrl); + /* MPDUs dropped due to invalid peer */ + PRINT_MY_STATS(invalid_peer); + /* MPDUs dropped due to duplication (non aggregation) */ + PRINT_MY_STATS(dup_non_aggr); + /* MPDUs dropped due to processed before */ + PRINT_MY_STATS(dup_past); + /* MPDUs dropped due to duplicate in reorder queue */ + PRINT_MY_STATS(dup_in_reorder); + /* Reorder timeout happened */ + PRINT_MY_STATS(reorder_timeout); + /* invalid bar ssn */ + PRINT_MY_STATS(invalid_bar_ssn); + /* reorder reset due to bar ssn */ + PRINT_MY_STATS(ssn_reset); + + /* Added by Ben */ + PRINT_MY_STATS(frag_invalid_peer); + PRINT_MY_STATS(frag_fcs_error); + PRINT_MY_STATS(frag_ok); + PRINT_MY_STATS(frag_discards); + + PRINT_MY_STATS(rx_chatter); + PRINT_MY_STATS(tkip_mic_error); + PRINT_MY_STATS(tkip_decrypt_error); + PRINT_MY_STATS(mpdu_length_error); + PRINT_MY_STATS(non_frag_unicast_ok); + + PRINT_MY_STATS(rx_flush_ind); // Flushed these due to timeout, etc. + PRINT_MY_STATS(rx_flush_ie_add); // Flushed these due to timeout, etc + + if (len > buf_len) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + +exit: + mutex_unlock(&ar->conf_mutex); + kfree(buf); + return ret_cnt; +} static ssize_t ath10k_read_fw_regs(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -964,6 +1104,13 @@ static const struct file_operations fops_fw_regs = { .llseek = default_llseek, }; +static const struct file_operations fops_rx_reorder_stats = { + .read = ath10k_read_rx_reorder_stats, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + static ssize_t ath10k_read_simulate_fw_crash(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -3467,6 +3614,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_wmi_services); + debugfs_create_file("rx_reorder_stats", 0400, ar->debug.debugfs_phy, ar, + &fops_rx_reorder_stats); + debugfs_create_file("set_rates", S_IRUSR | S_IWUSR, ar->debug.debugfs_phy, ar, &fops_set_rates); diff --git a/ath10k-4.9/mac.c b/ath10k-4.9/mac.c index 9d676e6..fdfbbaf 100644 --- a/ath10k-4.9/mac.c +++ b/ath10k-4.9/mac.c @@ -6185,6 +6185,9 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac hw-scan called, scan.state: %d\n", ar->scan.state); + switch (ar->scan.state) { case ATH10K_SCAN_IDLE: reinit_completion(&ar->scan.started); @@ -6198,6 +6201,7 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, case ATH10K_SCAN_RUNNING: case ATH10K_SCAN_ABORTING: ret = -EBUSY; + ath10k_warn(ar, "failed to start hw scan (busy): scan-state: %d\n", ar->scan.state); break; } spin_unlock_bh(&ar->data_lock); @@ -6272,6 +6276,8 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac cancel-hw-scan called\n"); + mutex_lock(&ar->conf_mutex); ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); diff --git a/ath10k-4.9/txrx.c b/ath10k-4.9/txrx.c index 8feca63..df7f9f8 100644 --- a/ath10k-4.9/txrx.c +++ b/ath10k-4.9/txrx.c @@ -193,7 +193,12 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, (info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - if (tx_done->tx_rate_code || tx_done->tx_rate_flags) { + if (tx_done->tx_rate_code || tx_done->tx_rate_flags || ar->ok_tx_rate_status) { + /* rate-code for 48Mbps is 0, with no flags, so we need to remember + * any other valid rates we might have seen and use that to know if + * firmware is sending tx rates. + */ + ar->ok_tx_rate_status = true; ath10k_set_tx_rate_status(ar, &info->status.rates[0], tx_done); /* Only in version 14 and higher of CT firmware */ diff --git a/ath10k-4.9/wmi-ops.h b/ath10k-4.9/wmi-ops.h index 606796e..f0b8e82 100644 --- a/ath10k-4.9/wmi-ops.h +++ b/ath10k-4.9/wmi-ops.h @@ -122,7 +122,7 @@ struct wmi_ops { bool deliver_cab); struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, const struct wmi_wmm_params_all_arg *arg); - struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask); + struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask, u32 specifier); struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, enum wmi_force_fw_hang_type type, u32 delay_ms); @@ -937,14 +937,14 @@ ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, } static inline int -ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct sk_buff *skb; if (!ar->wmi.ops->gen_request_stats) return -EOPNOTSUPP; - skb = ar->wmi.ops->gen_request_stats(ar, stats_mask); + skb = ar->wmi.ops->gen_request_stats(ar, stats_mask, specifier); if (IS_ERR(skb)) return PTR_ERR(skb); diff --git a/ath10k-4.9/wmi-tlv.c b/ath10k-4.9/wmi-tlv.c index f08508e..146d7ae 100644 --- a/ath10k-4.9/wmi-tlv.c +++ b/ath10k-4.9/wmi-tlv.c @@ -2423,7 +2423,7 @@ ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct wmi_request_stats_cmd *cmd; struct wmi_tlv *tlv; diff --git a/ath10k-4.9/wmi.c b/ath10k-4.9/wmi.c index 77323d5..ca26526 100644 --- a/ath10k-4.9/wmi.c +++ b/ath10k-4.9/wmi.c @@ -1973,6 +1973,27 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar) } } +void ath10k_wmi_stop_scan_work(struct work_struct *work) +{ + struct ath10k *ar = container_of(work, struct ath10k, + stop_scan_work); + /* Kick firmware to get us back in sync */ + struct wmi_stop_scan_arg arg = { + .req_id = 1, /* FIXME */ + .req_type = WMI_SCAN_STOP_ONE, + .u.scan_id = ATH10K_SCAN_ID, + }; + int ret; + + ath10k_warn(ar, "calling wmi-stop-scan from wmi-stop-scan-work\n"); + + mutex_lock(&ar->conf_mutex); + ret = ath10k_wmi_stop_scan(ar, &arg); + if (ret) + ath10k_warn(ar, "stop-scan-work: failed to stop wmi scan: %d\n", ret); + mutex_unlock(&ar->conf_mutex); +} + static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar, enum wmi_scan_completion_reason reason) { @@ -1988,16 +2009,14 @@ static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar, break; case ATH10K_SCAN_STARTING: complete(&ar->scan.started); + __ath10k_scan_finish(ar); if (reason == WMI_SCAN_REASON_BUSY) { - /* Kick firmware to get us back in sync */ - struct wmi_stop_scan_arg arg = { - .req_id = 1, /* FIXME */ - .req_type = WMI_SCAN_STOP_ONE, - .u.scan_id = ATH10K_SCAN_ID, - }; - ath10k_wmi_stop_scan(ar, &arg); + /* Cannot make WMI calls directly here, we are under data_lock and at + * least sometimes in IRQ context. + */ + ath10k_warn(ar, "received scan start failed event in scan-starting state, will request stop-scan-work\n"); + queue_work(ar->workqueue, &ar->stop_scan_work); } - __ath10k_scan_finish(ar); break; } } @@ -7427,7 +7446,7 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, } static struct sk_buff * -ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) +ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask, u32 specifier) { struct wmi_request_stats_cmd *cmd; struct sk_buff *skb; @@ -7438,6 +7457,7 @@ ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) cmd = (struct wmi_request_stats_cmd *)skb->data; cmd->stats_id = __cpu_to_le32(stats_mask); + cmd->vdev_id = __cpu_to_le32(specifier); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n", stats_mask); diff --git a/ath10k-4.9/wmi.h b/ath10k-4.9/wmi.h index 84b7abd..c6a0984 100644 --- a/ath10k-4.9/wmi.h +++ b/ath10k-4.9/wmi.h @@ -4293,8 +4293,12 @@ enum wmi_stats_id { WMI_STAT_BCNFLT = BIT(4), WMI_STAT_VDEV_RATE = BIT(5), WMI_REQUEST_REGISTER_DUMP = BIT(7), /* 0x80, CT Firmware only, request register dump. */ + WMI_REQUEST_STAT_CUSTOM = 0xF0000000, /* CT Firmware stats hack, in this case, + * vdev-id is 'stats-id' for requests */ }; +#define WMI_STAT_CUSTOM_RX_REORDER_STATS 0 + enum wmi_10_4_stats_id { WMI_10_4_STAT_PEER = BIT(0), WMI_10_4_STAT_AP = BIT(1), @@ -4302,6 +4306,56 @@ enum wmi_10_4_stats_id { WMI_10_4_STAT_PEER_EXTD = BIT(3), }; +/* + * Rx reorder statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct ath10k_rx_reorder_stats { + /* Non QoS MPDUs received */ + u32 deliver_non_qos; + /* MPDUs received in-order */ + u32 deliver_in_order; + /* Flush due to reorder timer expired */ + u32 deliver_flush_timeout; + /* Flush due to move out of window */ + u32 deliver_flush_oow; + /* Flush due to DELBA */ + u32 deliver_flush_delba; + /* MPDUs dropped due to FCS error */ + u32 fcs_error; + /* MPDUs dropped due to monitor mode non-data packet */ + u32 mgmt_ctrl; + /* MPDUs dropped due to invalid peer */ + u32 invalid_peer; + /* MPDUs dropped due to duplication (non aggregation) */ + u32 dup_non_aggr; + /* MPDUs dropped due to processed before */ + u32 dup_past; + /* MPDUs dropped due to duplicate in reorder queue */ + u32 dup_in_reorder; + /* Reorder timeout happened */ + u32 reorder_timeout; + /* invalid bar ssn */ + u32 invalid_bar_ssn; + /* reorder reset due to bar ssn */ + u32 ssn_reset; + + /* Added by Ben */ + u32 frag_invalid_peer; + u32 frag_fcs_error; + u32 frag_ok; + u32 frag_discards; + + u32 rx_chatter; + u32 tkip_mic_error; + u32 tkip_decrypt_error; + u32 mpdu_length_error; + u32 non_frag_unicast_ok; + + u32 rx_flush_ind; // Flushed these due to timeout, etc. + u32 rx_flush_ie_add; // Flushed these due to timeout, etc +}; + struct wlan_inst_rssi_args { __le16 cfg_retry_count; __le16 retry_count; @@ -4310,7 +4364,7 @@ struct wlan_inst_rssi_args { struct wmi_request_stats_cmd { __le32 stats_id; - __le32 vdev_id; + __le32 vdev_id; /* Or custom-stat identifier if stats_id == WMI_REQUEST_STAT_CUSTOM, CT FW only */ /* peer MAC address */ struct wmi_mac_addr peer_macaddr; @@ -4339,7 +4393,7 @@ struct wmi_stats_event { * number of pdev stats event structures * (wmi_pdev_stats) 0 or 1 */ - __le32 num_pdev_stats; + __le32 num_pdev_stats; /* Or custom-stats-type of stats_id == WMI_REQUEST_STAT_CUSTOM */ /* * number of vdev stats event structures * (wmi_vdev_stats) 0 or max vdevs @@ -6963,6 +7017,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype); int ath10k_wmi_barrier(struct ath10k *ar); +void ath10k_wmi_stop_scan_work(struct work_struct *work); #ifdef CONFIG_ATH10K_DEBUGFS /* TODO: Should really enable this all the time, not just when DEBUGFS is enabled. --Ben */