[PATCH] mac80211: Clear beacon_int in ieee80211_do_stop

2018-10-23 Thread greearb
From: Ben Greear 

This fixes stale beacon-int values that would keep a netdev
from going up.

To reproduce:

Create two VAP on one radio.
vap1 has beacon-int 100, start it.
vap2 has beacon-int 240, start it (and it will fail
  because beacon-int mismatch).
reconfigure vap2 to have beacon-int 100 and start it.
  It will fail because the stale beacon-int 240 will be used
  in the ifup path and hostapd never gets a chance to set the
  new beacon interval.

Signed-off-by: Ben Greear 
---
 net/mac80211/iface.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 90a59ce..f699cc84 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1059,6 +1059,8 @@ static void ieee80211_do_stop(struct 
ieee80211_sub_if_data *sdata,
if (local->open_count == 0)
ieee80211_clear_tx_pending(local);
 
+   sdata->vif.bss_conf.beacon_int = 0;
+
/*
 * If the interface goes down while suspended, presumably because
 * the device was unplugged and that happens before our resume,
-- 
2.4.11



[PATCH] mac80211: Improve connection-loss probing.

2018-09-27 Thread greearb
From: Ben Greear 

This makes the mlme code probe multiple times spread out across
the time-out period instead of lots of probes all at once.

It also makes the ap-probe and the nullfunc probe logic
act similarly, which allows us to remove some code.

Signed-off-by: Ben Greear 
---
 net/mac80211/ieee80211_i.h |  1 -
 net/mac80211/mlme.c| 62 ++
 2 files changed, 24 insertions(+), 39 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 17de2d0..0a0f693 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -444,7 +444,6 @@ struct ieee80211_if_managed {
unsigned long beacon_timeout;
unsigned long probe_timeout;
int probe_send_count;
-   bool nullfunc_failed;
bool connection_loss;
 
struct cfg80211_bss *associated;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a1b08af..eb784ac 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2203,8 +2203,6 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data 
*sdata,
sdata->u.mgd.probe_send_count > 0) {
if (ack)
ieee80211_sta_reset_conn_monitor(sdata);
-   else
-   sdata->u.mgd.nullfunc_failed = true;
ieee80211_queue_work(>local->hw, >work);
return;
}
@@ -2220,6 +2218,7 @@ static void ieee80211_mgd_probe_ap_send(struct 
ieee80211_sub_if_data *sdata)
u8 *dst = ifmgd->associated->bssid;
u8 unicast_limit = max(1, max_probe_tries - 3);
struct sta_info *sta;
+   u32 max_tries;
 
/*
 * Try sending broadcast probe requests for the last three
@@ -2247,11 +2246,13 @@ static void ieee80211_mgd_probe_ap_send(struct 
ieee80211_sub_if_data *sdata)
}
 
if (ieee80211_hw_check(>local->hw, REPORTS_TX_ACK_STATUS)) {
-   ifmgd->nullfunc_failed = false;
+   max_tries = max_nullfunc_tries;
ieee80211_send_nullfunc(sdata->local, sdata, false);
} else {
int ssid_len;
 
+   max_tries = max_probe_tries;
+
rcu_read_lock();
ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
if (WARN_ON_ONCE(ssid == NULL))
@@ -2266,7 +2267,8 @@ static void ieee80211_mgd_probe_ap_send(struct 
ieee80211_sub_if_data *sdata)
rcu_read_unlock();
}
 
-   ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
+   ifmgd->probe_timeout = jiffies +
+   msecs_to_jiffies(probe_wait_ms / max_tries);
run_again(sdata, ifmgd->probe_timeout);
 }
 
@@ -3978,54 +3980,38 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data 
*sdata)
ifmgd->associated) {
u8 bssid[ETH_ALEN];
int max_tries;
+   bool ack_status = ieee80211_hw_check(>hw,
+REPORTS_TX_ACK_STATUS);
 
memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
 
-   if (ieee80211_hw_check(>hw, REPORTS_TX_ACK_STATUS))
+   if (ack_status)
max_tries = max_nullfunc_tries;
else
max_tries = max_probe_tries;
 
/* ACK received for nullfunc probing frame */
-   if (!ifmgd->probe_send_count)
+   if (!ifmgd->probe_send_count) {
+   /* probe_send_count of zero means probe succeeded */
ieee80211_reset_ap_probe(sdata);
-   else if (ifmgd->nullfunc_failed) {
-   if (ifmgd->probe_send_count < max_tries) {
-   mlme_dbg(sdata,
-"No ack for nullfunc frame to AP %pM, 
try %d/%i\n",
-bssid, ifmgd->probe_send_count,
-max_tries);
-   ieee80211_mgd_probe_ap_send(sdata);
-   } else {
-   mlme_wrn(sdata,
-"No ack for nullfunc frame to AP %pM, 
disconnecting.\n",
-bssid);
-   ieee80211_sta_connection_lost(sdata, bssid,
-   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-   false);
-   }
-   } else if (time_is_after_jiffies(ifmgd->probe_timeout))
+   } else if (time_is_after_jiffies(ifmgd->probe_timeout)) {
+   /* probe_timeout is after current jiffies
+* Not time to (re)probe yet
+*/
run_again(sdata, ifmgd->probe_timeout);
-   else if (ieee80211_hw_check(>hw, REPORTS_TX_ACK_STATUS)) 
{
- 

[PATCH v2 3/3] ath10k: Support survey dump for ath10k-ct 10.1 firmware.

2018-05-14 Thread greearb
From: Ben Greear 

Recent ath10k-ct 10.1 firmware supports survey results, and
advertises the appropriate service flags.  This confuses
the ath10k driver because the 10.1 wmi commands are not set up
for survey information.  So, this patch adds support for
handling survey information.  Example output:

Survey data from wlan0
frequency:  5180 MHz [in use]
noise:  -97 dBm
channel active time:44 ms
channel busy time:  15 ms
channel receive time:   7 ms
channel transmit time:  7 ms
Survey data from wlan0
frequency:  5200 MHz
noise:  -98 dBm
channel active time:46 ms
channel busy time:  2 ms
...

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 54 +++
 drivers/net/wireless/ath/ath10k/wmi.h |  8 ++
 2 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index df2e92a..3497873 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -365,7 +365,8 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED,
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
-   .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
+   .pdev_bss_chan_info_request_cmdid =
+   WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
 };
 
@@ -2830,9 +2831,15 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k 
*ar,
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10x_peer_stats *src;
struct ath10k_fw_stats_peer *dst;
+   int stats_len;
+
+   if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
+   stats_len = sizeof(struct wmi_10x_peer_stats_ct_ext);
+   else
+   stats_len = sizeof(*src);
 
src = (void *)skb->data;
-   if (!skb_pull(skb, sizeof(*src)))
+   if (!skb_pull(skb, stats_len))
return -EPROTO;
 
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
@@ -2843,6 +2850,12 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k 
*ar,
 
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
 
+   if (ath10k_peer_stats_enabled(ar)) {
+   struct wmi_10x_peer_stats_ct_ext *src2 = (void *)(src);
+
+   dst->rx_duration = __le32_to_cpu(src2->rx_duration);
+   }
+
list_add_tail(>list, >peers);
}
 
@@ -5488,7 +5501,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct 
sk_buff *skb)
ath10k_wmi_event_service_available(ar, skb);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (main) eventid: %d\n", id);
break;
}
 
@@ -5618,8 +5631,11 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
case WMI_10X_PDEV_UTF_EVENTID:
/* ignore utf events */
break;
+   case WMI_10_1_PDEV_BSS_CHAN_INFO_EVENTID: /* Newer CT 10.1 firmware */
+   ath10k_wmi_event_pdev_bss_chan_info(ar, skb);
+   break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.1) eventid: %d\n", id);
break;
}
 
@@ -5765,7 +5781,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
   "received event id %d not implemented\n", id);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.2) eventid: %d\n", id);
break;
}
 
@@ -5879,7 +5895,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
ath10k_wmi_event_tpc_final_table(ar, skb);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.4) eventid: %d\n", id);
break;
}
 
@@ -6174,6 +6190,26 @@ static struct sk_buff 
*ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
 
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ar->running_fw->fw_file.fw_features)) {
+   u32 features = 0;
+
+ 

[PATCH v2 2/3] ath10k: Don't try un-supported idle_ps_config command.

2018-05-14 Thread greearb
From: Ben Greear 

The warning the the logs does not give user a clue as to what
command is failing, so it is worth it to check for un-supported
command before trying the call.

And add return-code to survey error message.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 3d7119a..1185d0c2 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4680,10 +4680,13 @@ static int ath10k_start(struct ieee80211_hw *hw)
}
 
param = ar->wmi.pdev_param->idle_ps_config;
-   ret = ath10k_wmi_pdev_set_param(ar, param, 1);
-   if (ret && ret != -EOPNOTSUPP) {
-   ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret);
-   goto err_core_stop;
+   if (param != WMI_PDEV_PARAM_UNSUPPORTED) {
+   ret = ath10k_wmi_pdev_set_param(ar, param, 1);
+   if (ret) {
+   ath10k_warn(ar, "failed to enable idle_ps_config: %d\n",
+   ret);
+   goto err_core_stop;
+   }
}
 
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
@@ -6770,7 +6773,8 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar,
 
ret = ath10k_wmi_pdev_bss_chan_info_request(ar, type);
if (ret) {
-   ath10k_warn(ar, "failed to send pdev bss chan info request\n");
+   ath10k_warn(ar, "failed to send pdev bss chan info request: 
%d\n",
+   ret);
return;
}
 
-- 
2.4.11



[PATCH 2/3] ath10k: Don't try un-supported idle_ps_config command.

2018-05-11 Thread greearb
From: Ben Greear 

The warning the the logs does not give user a clue as to what
command is failing, so it is worth it to check for un-supported
command before trying the call.

And add return-code to survey error message.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 3d7119a..1185d0c2 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4680,10 +4680,13 @@ static int ath10k_start(struct ieee80211_hw *hw)
}
 
param = ar->wmi.pdev_param->idle_ps_config;
-   ret = ath10k_wmi_pdev_set_param(ar, param, 1);
-   if (ret && ret != -EOPNOTSUPP) {
-   ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret);
-   goto err_core_stop;
+   if (param != WMI_PDEV_PARAM_UNSUPPORTED) {
+   ret = ath10k_wmi_pdev_set_param(ar, param, 1);
+   if (ret) {
+   ath10k_warn(ar, "failed to enable idle_ps_config: %d\n",
+   ret);
+   goto err_core_stop;
+   }
}
 
__ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask);
@@ -6770,7 +6773,8 @@ ath10k_mac_update_bss_chan_survey(struct ath10k *ar,
 
ret = ath10k_wmi_pdev_bss_chan_info_request(ar, type);
if (ret) {
-   ath10k_warn(ar, "failed to send pdev bss chan info request\n");
+   ath10k_warn(ar, "failed to send pdev bss chan info request: 
%d\n",
+   ret);
return;
}
 
-- 
2.4.11



[PATCH 1/3] ath10k: Add ath10k-ct firmware feature flags and descriptions.

2018-05-11 Thread greearb
From: Ben Greear 

These feature flags are used by ath10k-ct firmware.  Add these
so we can use them in future patches and so there are no warings
about feature flags on loading ath10k-ct firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 17 +
 drivers/net/wireless/ath/ath10k/core.h | 67 ++
 2 files changed, 84 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 4cf54a7..f2f8f61 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -552,6 +552,23 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_NO_PS] = "no-ps",
[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",
[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",
+   [ATH10K_FW_FEATURE_WMI_10X_CT] = "wmi-10.x-CT",
+   [ATH10K_FW_FEATURE_CT_RXSWCRYPT] = "rxswcrypt-CT",
+   [ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK] = "txstatus-noack",
+   [ATH10K_FW_FEATURE_CT_RATEMASK] = "ratemask-CT",
+   [ATH10K_FW_FEATURE_HAS_SAFE_BURST] = "safe-burst",
+   [ATH10K_FW_FEATURE_REGDUMP_CT] = "regdump-CT",
+   [ATH10K_FW_FEATURE_TXRATE_CT] = "txrate-CT",
+   [ATH10K_FW_FEATURE_FLUSH_ALL_CT] = "flush-all-CT",
+   [ATH10K_FW_FEATURE_PINGPONG_READ_CT] = "pingpong-CT",
+   [ATH10K_FW_FEATURE_SKIP_CH_RES_CT] = "ch-regs-CT",
+   [ATH10K_FW_FEATURE_NOP_CT] = "nop-CT",
+   [ATH10K_FW_FEATURE_HTT_MGT_CT] = "htt-mgt-CT",
+   [ATH10K_FW_FEATURE_SET_SPECIAL_CT] = "set-special-CT",
+   [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,
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index e4ac8f2..c1342c5 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -711,6 +711,73 @@ enum ath10k_fw_features {
/* Firmware load is done externally, not by bmi */
ATH10K_FW_FEATURE_NON_BMI = 19,
 
+   /* tx-status has the noack bits (CT firmware version 14 and higher ) */
+   ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK = 30,
+
+   /* Firmware from Candela Technologies, enables more VIFs, etc */
+   ATH10K_FW_FEATURE_WMI_10X_CT = 31,
+
+   /* Firmware from Candela Technologies with rx-software-crypt.
+* Required for multiple stations connected to same AP when using
+* encryption (ie, commercial version of CT firmware)
+*/
+   ATH10K_FW_FEATURE_CT_RXSWCRYPT = 32,
+
+   /* Firmware supports extended wmi_common_peer_assoc_complete_cmd that
+* contains an array of rate-disable masks.  This allows the host to
+* have better control over what rates the firmware will use.  CT
+* Firmware only (v15 and higher)
+*/
+   ATH10K_FW_FEATURE_CT_RATEMASK = 33,
+
+   /* Versions of firmware before approximately 10.2.4.72 would corrupt
+* txop fields during burst.  Since this is fixed now, add a flag to
+* denote this.
+*/
+   ATH10K_FW_FEATURE_HAS_SAFE_BURST = 34,
+
+   /* Register-dump is supported. */
+   ATH10K_FW_FEATURE_REGDUMP_CT = 35,
+
+   /* TX-Rate is reported. */
+   ATH10K_FW_FEATURE_TXRATE_CT = 36,
+
+   /* Firmware can flush all peers. */
+   ATH10K_FW_FEATURE_FLUSH_ALL_CT = 37,
+
+   /* Firmware can read memory with ping-pong protocol. */
+   ATH10K_FW_FEATURE_PINGPONG_READ_CT = 38,
+
+   /* Firmware can skip channel reservation. */
+   ATH10K_FW_FEATURE_SKIP_CH_RES_CT = 39,
+
+   /* Firmware supports NOP keep-alive message. */
+   ATH10K_FW_FEATURE_NOP_CT = 40,
+
+   /* Firmware supports CT HTT MGT feature. */
+   ATH10K_FW_FEATURE_HTT_MGT_CT = 41,
+
+   /* Set-special cmd-id is supported. */
+   ATH10K_FW_FEATURE_SET_SPECIAL_CT = 42,
+
+   /* SW Beacon Miss is disabled in this kernel, so you have to
+* let mac80211 manage the connection.
+*/
+   ATH10K_FW_FEATURE_NO_BMISS_CT = 43,
+
+   /* 10.1 firmware that supports getting temperature.  Stock
+* 10.1 cannot.
+*/
+   ATH10K_FW_FEATURE_HAS_GET_TEMP_CT = 44,
+
+   /* Can peer-id be over-ridden to provide rix + retries for raw pkts?
+*  CT only option.
+*/
+   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,
 };
-- 
2.4.11



[PATCH 3/3] ath10k: Support survey dump for ath10k-ct 10.1 firmware.

2018-05-11 Thread greearb
From: Ben Greear 

Recent ath10k-ct 10.1 firmware supports survey results, and
advertises the appropriate service flags.  This confuses
the ath10k driver because the 10.1 wmi commands are not set up
for survey information.  So, this patch adds support for
handling survey information.  Example output:

Survey data from wlan0
frequency:  5180 MHz [in use]
noise:  -97 dBm
channel active time:44 ms
channel busy time:  15 ms
channel receive time:   7 ms
channel transmit time:  7 ms
Survey data from wlan0
frequency:  5200 MHz
noise:  -98 dBm
channel active time:46 ms
channel busy time:  2 ms
...

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 54 +++
 drivers/net/wireless/ath/ath10k/wmi.h |  8 ++
 2 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index df2e92a..3497873 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -365,7 +365,8 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED,
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
-   .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
+   .pdev_bss_chan_info_request_cmdid =
+   WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
 };
 
@@ -2830,9 +2831,15 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k 
*ar,
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10x_peer_stats *src;
struct ath10k_fw_stats_peer *dst;
+   int stats_len;
+
+   if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
+   stats_len = sizeof(struct wmi_10x_peer_stats_ct_ext);
+   else
+   stats_len = sizeof(*src);
 
src = (void *)skb->data;
-   if (!skb_pull(skb, sizeof(*src)))
+   if (!skb_pull(skb, stats_len))
return -EPROTO;
 
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
@@ -2843,6 +2850,12 @@ static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k 
*ar,
 
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
 
+   if (ath10k_peer_stats_enabled(ar)) {
+   struct wmi_10x_peer_stats_ct_ext *src2 = (void *)(src);
+
+   dst->rx_duration = __le32_to_cpu(src2->rx_duration);
+   }
+
list_add_tail(>list, >peers);
}
 
@@ -5488,7 +5501,7 @@ static void ath10k_wmi_op_rx(struct ath10k *ar, struct 
sk_buff *skb)
ath10k_wmi_event_service_available(ar, skb);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (main) eventid: %d\n", id);
break;
}
 
@@ -5618,8 +5631,11 @@ static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
case WMI_10X_PDEV_UTF_EVENTID:
/* ignore utf events */
break;
+   case WMI_10_1_PDEV_BSS_CHAN_INFO_EVENTID: /* Newer CT 10.1 firmware */
+   ath10k_wmi_event_pdev_bss_chan_info(ar, skb);
+   break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.1) eventid: %d\n", id);
break;
}
 
@@ -5765,7 +5781,7 @@ static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
   "received event id %d not implemented\n", id);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.2) eventid: %d\n", id);
break;
}
 
@@ -5879,7 +5895,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, 
struct sk_buff *skb)
ath10k_wmi_event_tpc_final_table(ar, skb);
break;
default:
-   ath10k_warn(ar, "Unknown eventid: %d\n", id);
+   ath10k_warn(ar, "Unknown (10.4) eventid: %d\n", id);
break;
}
 
@@ -6174,6 +6190,26 @@ static struct sk_buff 
*ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
 
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ar->running_fw->fw_file.fw_features)) {
+   u32 features = 0;
+
+ 

[PATCH v2 3/3] ath10k: Support ethtool gstats2 API.

2018-04-19 Thread greearb
From: Ben Greear 

Skip a firmware stats update when calling
code indicates the stats refresh is not needed.

Signed-off-by: Ben Greear 
---

v2:  Convert to new flag name, attempt to fix build
   when there is not DEBUGFS enabled for ath10k.

 drivers/net/wireless/ath/ath10k/debug.c | 18 +++---
 drivers/net/wireless/ath/ath10k/debug.h |  5 +
 drivers/net/wireless/ath/ath10k/mac.c   |  1 +
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index bac832c..235cd04 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1159,9 +1159,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 flags)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -1170,6 +1171,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (flags & ETHTOOL_GS2_NO_REFRESH_FW)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_debug_fw_stats_request(ar);
if (ret) {
@@ -1180,6 +1184,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -1244,6 +1249,13 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 0afca5c..e953dd0 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -117,6 +117,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
@@ -195,6 +199,7 @@ static inline u32 ath10k_debug_get_fw_dbglog_level(struct 
ath10k *ar)
 #define ath10k_debug_get_et_strings NULL
 #define ath10k_debug_get_et_sset_count NULL
 #define ath10k_debug_get_et_stats NULL
+#define ath10k_debug_get_et_stats2 NULL
 
 #endif /* CONFIG_ATH10K_DEBUGFS */
 #ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index bf05a36..27b793c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7734,6 +7734,7 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
-- 
2.4.11



[PATCH v2 2/3] mac80211: Add support for ethtool gstats2 API.

2018-04-19 Thread greearb
From: Ben Greear 

This enables users to request fewer stats to be refreshed
in cases where firmware does not need to be probed.

Signed-off-by: Ben Greear 
---

v2:  No changes.

 include/net/mac80211.h|  6 ++
 net/mac80211/driver-ops.h |  9 +++--
 net/mac80211/ethtool.c| 18 +-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d2279b2..4854f33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3361,6 +3361,8 @@ enum ieee80211_reconfig_type {
  *
  * @get_et_stats:  Ethtool API to get a set of u64 stats.
  *
+ * @get_et_stats2:  Ethtool API to get a set of u64 stats, with flags.
+ *
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  * and perhaps other supported types of ethtool data-sets.
  *
@@ -3692,6 +3694,10 @@ struct ieee80211_ops {
void(*get_et_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+   void(*get_et_stats2)(struct ieee80211_hw *hw,
+struct ieee80211_vif *vif,
+struct ethtool_stats *stats, u64 *data,
+u32 flags);
void(*get_et_strings)(struct ieee80211_hw *hw,
  struct ieee80211_vif *vif,
  u32 sset, u8 *data);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4d82fe7..519d2db 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -58,10 +58,15 @@ static inline void drv_get_et_strings(struct 
ieee80211_sub_if_data *sdata,
 
 static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
struct ethtool_stats *stats,
-   u64 *data)
+   u64 *data, u32 flags)
 {
struct ieee80211_local *local = sdata->local;
-   if (local->ops->get_et_stats) {
+   if (local->ops->get_et_stats2) {
+   trace_drv_get_et_stats(local);
+   local->ops->get_et_stats2(>hw, >vif, stats, data,
+ flags);
+   trace_drv_return_void(local);
+   } else if (local->ops->get_et_stats) {
trace_drv_get_et_stats(local);
local->ops->get_et_stats(>hw, >vif, stats, data);
trace_drv_return_void(local);
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 9cc986d..b67520e 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -61,9 +61,9 @@ static int ieee80211_get_sset_count(struct net_device *dev, 
int sset)
return rv;
 }
 
-static void ieee80211_get_stats(struct net_device *dev,
-   struct ethtool_stats *stats,
-   u64 *data)
+static void ieee80211_get_stats2(struct net_device *dev,
+struct ethtool_stats *stats,
+u64 *data, u32 flags)
 {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -199,7 +199,14 @@ static void ieee80211_get_stats(struct net_device *dev,
if (WARN_ON(i != STA_STATS_LEN))
return;
 
-   drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+   drv_get_et_stats(sdata, stats, [STA_STATS_LEN], flags);
+}
+
+static void ieee80211_get_stats(struct net_device *dev,
+   struct ethtool_stats *stats,
+   u64 *data)
+{
+   ieee80211_get_stats2(dev, stats, data, 0);
 }
 
 static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@@ -211,7 +218,7 @@ static void ieee80211_get_strings(struct net_device *dev, 
u32 sset, u8 *data)
sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
}
-   drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
+   drv_get_et_strings(sdata, sset, [sz_sta_stats]);
 }
 
 static int ieee80211_get_regs_len(struct net_device *dev)
@@ -238,5 +245,6 @@ const struct ethtool_ops ieee80211_ethtool_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_strings = ieee80211_get_strings,
.get_ethtool_stats = ieee80211_get_stats,
+   .get_ethtool_stats2 = ieee80211_get_stats2,
.get_sset_count = ieee80211_get_sset_count,
 };
-- 
2.4.11



[PATCH 3/3] ath10k: Support ethtool gstats2 API.

2018-04-17 Thread greearb
From: Ben Greear 

Skip a firmware stats update when calling
code indicates the stats refresh is not needed.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 18 +++---
 drivers/net/wireless/ath/ath10k/debug.h |  4 
 drivers/net/wireless/ath/ath10k/mac.c   |  1 +
 3 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index bac832c..d559a3f 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1159,9 +1159,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 flags)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -1170,6 +1171,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (flags & ETHTOOL_GS2_SKIP_FW)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_debug_fw_stats_request(ar);
if (ret) {
@@ -1180,6 +1184,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -1244,6 +1249,13 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 0afca5c..595d964 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -117,6 +117,10 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data,
+   u32 level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index bf05a36..27b793c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7734,6 +7734,7 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
-- 
2.4.11



[PATCH 1/3] ethtool: Support ETHTOOL_GSTATS2 command.

2018-04-17 Thread greearb
From: Ben Greear 

This is similar to ETHTOOL_GSTATS, but it allows you to specify
flags.  These flags can be used by the driver to decrease the
amount of stats refreshed.  In particular, this helps with ath10k
since getting the firmware stats can be slow.

Signed-off-by: Ben Greear 
---
 include/linux/ethtool.h  | 12 
 include/uapi/linux/ethtool.h | 10 ++
 net/core/ethtool.c   | 40 +++-
 3 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index ebe4181..a4aa11f 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -243,6 +243,15 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
  * @get_ethtool_stats: Return extended statistics about the device.
  * This is only useful if the device maintains statistics not
  * included in  rtnl_link_stats64.
+ * @get_ethtool_stats2: Return extended statistics about the device.
+ * This is only useful if the device maintains statistics not
+ * included in  rtnl_link_stats64.
+ *  Takes a flags argument:  0 means all (same as get_ethtool_stats),
+ *  0x1 (ETHTOOL_GS2_SKIP_FW) means skip firmware stats.
+ *  Other flags are reserved for now.
+ *  Same number of stats will be returned, but some of them might
+ *  not be as accurate/refreshed.  This is to allow not querying
+ *  firmware or other expensive-to-read stats, for instance.
  * @begin: Function to be called before any other operation.  Returns a
  * negative error code or zero.
  * @complete: Function to be called after any other operation except
@@ -355,6 +364,9 @@ struct ethtool_ops {
int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
void(*get_ethtool_stats)(struct net_device *,
 struct ethtool_stats *, u64 *);
+   void(*get_ethtool_stats2)(struct net_device *dev,
+ struct ethtool_stats *gstats, u64 *data,
+ u32 flags);
int (*begin)(struct net_device *);
void(*complete)(struct net_device *);
u32 (*get_priv_flags)(struct net_device *);
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 4ca65b5..1c74f3e 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1396,11 +1396,21 @@ enum ethtool_fec_config_bits {
 #define ETHTOOL_PHY_STUNABLE   0x004f /* Set PHY tunable configuration */
 #define ETHTOOL_GFECPARAM  0x0050 /* Get FEC settings */
 #define ETHTOOL_SFECPARAM  0x0051 /* Set FEC settings */
+#define ETHTOOL_GSTATS20x0052 /* get NIC-specific 
statistics
+   * with ability to specify flags.
+   * See ETHTOOL_GS2* below.
+   */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET ETHTOOL_GSET
 #define SPARC_ETH_SSET ETHTOOL_SSET
 
+/* GSTATS2 flags */
+#define ETHTOOL_GS2_SKIP_NONE (0)/* default is to update all stats */
+#define ETHTOOL_GS2_SKIP_FW   (1<<0) /* Skip reading stats that probe firmware,
+ * and thus are slow/expensive.
+ */
+
 /* Link mode bit indices */
 enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_10baseT_Half_BIT  = 0,
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 03416e6..6ec3413 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -1952,16 +1952,14 @@ static int ethtool_phys_id(struct net_device *dev, void 
__user *useraddr)
return rc;
 }
 
-static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
+static int _ethtool_get_stats(struct net_device *dev, void __user *useraddr,
+ u32 flags)
 {
struct ethtool_stats stats;
const struct ethtool_ops *ops = dev->ethtool_ops;
u64 *data;
int ret, n_stats;
 
-   if (!ops->get_ethtool_stats || !ops->get_sset_count)
-   return -EOPNOTSUPP;
-
n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
if (n_stats < 0)
return n_stats;
@@ -1976,7 +1974,10 @@ static int ethtool_get_stats(struct net_device *dev, 
void __user *useraddr)
if (n_stats && !data)
return -ENOMEM;
 
-   ops->get_ethtool_stats(dev, , data);
+   if (flags != ETHTOOL_GS2_SKIP_NONE)
+   ops->get_ethtool_stats2(dev, , data, flags);
+   else
+   ops->get_ethtool_stats(dev, , data);
 
ret = -EFAULT;
if (copy_to_user(useraddr, , sizeof(stats)))
@@ -1991,6 +1992,31 @@ static int ethtool_get_stats(struct net_device *dev, 
void __user *useraddr)
return ret;
 }
 
+static int ethtool_get_stats(struct 

[PATCH 2/3] mac80211: Add support for ethtool gstats2 API.

2018-04-17 Thread greearb
From: Ben Greear 

This enables users to request fewer stats to be refreshed
in cases where firmware does not need to be probed.

Signed-off-by: Ben Greear 
---
 include/net/mac80211.h|  6 ++
 net/mac80211/driver-ops.h |  9 +++--
 net/mac80211/ethtool.c| 18 +-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d2279b2..4854f33 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3361,6 +3361,8 @@ enum ieee80211_reconfig_type {
  *
  * @get_et_stats:  Ethtool API to get a set of u64 stats.
  *
+ * @get_et_stats2:  Ethtool API to get a set of u64 stats, with flags.
+ *
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  * and perhaps other supported types of ethtool data-sets.
  *
@@ -3692,6 +3694,10 @@ struct ieee80211_ops {
void(*get_et_stats)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+   void(*get_et_stats2)(struct ieee80211_hw *hw,
+struct ieee80211_vif *vif,
+struct ethtool_stats *stats, u64 *data,
+u32 flags);
void(*get_et_strings)(struct ieee80211_hw *hw,
  struct ieee80211_vif *vif,
  u32 sset, u8 *data);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4d82fe7..519d2db 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -58,10 +58,15 @@ static inline void drv_get_et_strings(struct 
ieee80211_sub_if_data *sdata,
 
 static inline void drv_get_et_stats(struct ieee80211_sub_if_data *sdata,
struct ethtool_stats *stats,
-   u64 *data)
+   u64 *data, u32 flags)
 {
struct ieee80211_local *local = sdata->local;
-   if (local->ops->get_et_stats) {
+   if (local->ops->get_et_stats2) {
+   trace_drv_get_et_stats(local);
+   local->ops->get_et_stats2(>hw, >vif, stats, data,
+ flags);
+   trace_drv_return_void(local);
+   } else if (local->ops->get_et_stats) {
trace_drv_get_et_stats(local);
local->ops->get_et_stats(>hw, >vif, stats, data);
trace_drv_return_void(local);
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 9cc986d..b67520e 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -61,9 +61,9 @@ static int ieee80211_get_sset_count(struct net_device *dev, 
int sset)
return rv;
 }
 
-static void ieee80211_get_stats(struct net_device *dev,
-   struct ethtool_stats *stats,
-   u64 *data)
+static void ieee80211_get_stats2(struct net_device *dev,
+struct ethtool_stats *stats,
+u64 *data, u32 flags)
 {
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chanctx_conf *chanctx_conf;
@@ -199,7 +199,14 @@ static void ieee80211_get_stats(struct net_device *dev,
if (WARN_ON(i != STA_STATS_LEN))
return;
 
-   drv_get_et_stats(sdata, stats, &(data[STA_STATS_LEN]));
+   drv_get_et_stats(sdata, stats, [STA_STATS_LEN], flags);
+}
+
+static void ieee80211_get_stats(struct net_device *dev,
+   struct ethtool_stats *stats,
+   u64 *data)
+{
+   ieee80211_get_stats2(dev, stats, data, 0);
 }
 
 static void ieee80211_get_strings(struct net_device *dev, u32 sset, u8 *data)
@@ -211,7 +218,7 @@ static void ieee80211_get_strings(struct net_device *dev, 
u32 sset, u8 *data)
sz_sta_stats = sizeof(ieee80211_gstrings_sta_stats);
memcpy(data, ieee80211_gstrings_sta_stats, sz_sta_stats);
}
-   drv_get_et_strings(sdata, sset, &(data[sz_sta_stats]));
+   drv_get_et_strings(sdata, sset, [sz_sta_stats]);
 }
 
 static int ieee80211_get_regs_len(struct net_device *dev)
@@ -238,5 +245,6 @@ const struct ethtool_ops ieee80211_ethtool_ops = {
.set_ringparam = ieee80211_set_ringparam,
.get_strings = ieee80211_get_strings,
.get_ethtool_stats = ieee80211_get_stats,
+   .get_ethtool_stats2 = ieee80211_get_stats2,
.get_sset_count = ieee80211_get_sset_count,
 };
-- 
2.4.11



[RFC] ethtool: Support ETHTOOL_GSTATS2 command.

2018-03-07 Thread greearb
From: Ben Greear 

This is similar to ETHTOOL_GSTATS, but it allows you to specify
a 'level'.  This level can be used by the driver to decrease the
amount of stats refreshed.  In particular, this helps with ath10k
since getting the firmware stats can be slow.

Signed-off-by: Ben Greear 
---

NOTE:  I know to make it upstream I would need to split the patch and
remove the #define for 'backporting' that I added.  But, is the
feature in general wanted?  If so, I'll do the patch split and
other tweaks that might be suggested.

 drivers/net/wireless/ath/ath10k/debug.c | 18 ++--
 drivers/net/wireless/ath/ath10k/debug.h |  3 ++
 drivers/net/wireless/ath/ath10k/mac.c   |  3 ++
 include/linux/ethtool.h | 10 +++
 include/net/mac80211.h  |  6 
 include/uapi/linux/ethtool.h|  4 +++
 net/core/ethtool.c  | 52 +
 net/mac80211/driver-ops.h   |  9 --
 net/mac80211/ethtool.c  | 16 +++---
 9 files changed, 112 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 65e0a33..2545c24 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2389,9 +2389,9 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw 
*hw,
return 0;
 }
 
-void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
-  struct ieee80211_vif *vif,
-  struct ethtool_stats *stats, u64 *data)
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data, u32 
level)
 {
struct ath10k *ar = hw->priv;
static const struct ath10k_fw_stats_pdev zero_stats = {};
@@ -2401,6 +2401,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
mutex_lock(>conf_mutex);
 
+   if (level && level < 5)
+   goto skip_query_fw_stats;
+
if (ar->state == ATH10K_STATE_ON) {
ath10k_refresh_target_regs(ar); /* Request some CT FW stats. */
ret = ath10k_debug_fw_stats_request(ar);
@@ -2412,6 +2415,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
}
}
 
+skip_query_fw_stats:
pdev_stats = list_first_entry_or_null(>debug.fw_stats.pdevs,
  struct ath10k_fw_stats_pdev,
  list);
@@ -2497,6 +2501,14 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
WARN_ON(i != ATH10K_SSTATS_LEN);
 }
 
+void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+  struct ieee80211_vif *vif,
+  struct ethtool_stats *stats, u64 *data)
+{
+   ath10k_debug_get_et_stats2(hw, vif, stats, data, 0);
+}
+
+
 static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 74d1728..f33c88f 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -108,6 +108,9 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
 void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
   struct ieee80211_vif *vif,
   struct ethtool_stats *stats, u64 *data);
+void ath10k_debug_get_et_stats2(struct ieee80211_hw *hw,
+   struct ieee80211_vif *vif,
+   struct ethtool_stats *stats, u64 *data, u32 
level);
 
 static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
 {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index e962c0e..eed0a9f 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8472,6 +8472,9 @@ static const struct ieee80211_ops ath10k_ops = {
.ampdu_action   = ath10k_ampdu_action,
.get_et_sset_count  = ath10k_debug_get_et_sset_count,
.get_et_stats   = ath10k_debug_get_et_stats,
+#ifdef MAC80211_HAS_ET_STATS2
+   .get_et_stats2  = ath10k_debug_get_et_stats2,
+#endif
.get_et_strings = ath10k_debug_get_et_strings,
.add_chanctx= ath10k_mac_op_add_chanctx,
.remove_chanctx = ath10k_mac_op_remove_chanctx,
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 83cc986..9745175 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -221,6 +221,14 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 
*legacy_u32,
  * 

[PATCH] ath10k: Clear rx status enc_flags

2018-02-28 Thread greearb
From: Ben Greear 

Otherwise, rx rate encodings are wrong as SGI flag may be set
when it should not be.  Maybe other issues as well.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/htt_rx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 83eb7b2..8446dfc 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -901,6 +901,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
status->rate_idx = 0;
status->nss = 0;
status->encoding = RX_ENC_LEGACY;
+   status->enc_flags = 0;
status->bw = RATE_INFO_BW_20;
status->flag &= ~RX_FLAG_MACTIME_END;
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
-- 
2.4.11



[PATCH] ath10k: Attempt to work around napi_synchronize hang.

2018-02-28 Thread greearb
From: Ben Greear 

Calling napi_disable twice in a row (w/out starting it and/or without
having NAPI active leads to deadlock because napi_disable sets
NAPI_STATE_SCHED and NAPI_STATE_NPSVC when it returns, as far as I
can tell.  So, guard this call to napi_disable.  I believe the
failure case is something like this:
 rmmod ath10k_pci ath10k_core
   Firmware crashes before hif_stop is called by the rmmod path
   The crash handling logic calls hif_stop
   Then rmmod gets around to calling hif_stop, but spins endlessly
   in napi_synchronize.

I think one way this could happen is that ath10k_stop checks
for state != ATH10K_STATE_OFF, but STATE_RESTARTING is also
a possibility.  That might be how we can have hif_stop called twice
without a hif_start in between. --Ben

Signed-off-by: Ben Greear 
---
* since RFC:  Added similar code to ahb
  This seems needed back to at least 4.9 kernels.

 drivers/net/wireless/ath/ath10k/ahb.c  |  9 +++--
 drivers/net/wireless/ath/ath10k/core.h |  1 +
 drivers/net/wireless/ath/ath10k/pci.c  | 25 +++--
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/ahb.c 
b/drivers/net/wireless/ath/ath10k/ahb.c
index da770af..f826c59 100644
--- a/drivers/net/wireless/ath/ath10k/ahb.c
+++ b/drivers/net/wireless/ath/ath10k/ahb.c
@@ -641,6 +641,8 @@ static int ath10k_ahb_hif_start(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n");
 
napi_enable(>napi);
+   ar->napi_enabled = true;
+
ath10k_ce_enable_interrupts(ar);
ath10k_pci_enable_legacy_irq(ar);
 
@@ -660,8 +662,11 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar)
 
ath10k_pci_flush(ar);
 
-   napi_synchronize(>napi);
-   napi_disable(>napi);
+   if (ar->napi_enabled) {
+   napi_synchronize(>napi);
+   napi_disable(>napi);
+   ar->napi_enabled = false;
+   }
 }
 
 static int ath10k_ahb_hif_power_up(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 72b4495..c7ba49f 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1205,6 +1205,7 @@ struct ath10k {
/* NAPI */
struct net_device napi_dev;
struct napi_struct napi;
+   bool napi_enabled;
 
struct work_struct stop_scan_work;
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 398e413..9131e15 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1956,6 +1956,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
 
napi_enable(>napi);
+   ar->napi_enabled = true;
 
ath10k_pci_irq_enable(ar);
ath10k_pci_rx_post(ar);
@@ -2086,8 +2087,28 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
-   napi_synchronize(>napi);
-   napi_disable(>napi);
+
+   /* Calling napi_disable twice in a row (w/out starting it and/or without
+* having NAPI active leads to deadlock because napi_disable sets
+* NAPI_STATE_SCHED and NAPI_STATE_NPSVC when it returns, as far as I
+* can tell.  So, guard this call to napi_disable.  I believe the
+* failure case is something like this:
+* rmmod ath10k_pci ath10k_core
+*   Firmware crashes before hif_stop is called by the rmmod path
+*   The crash handling logic calls hif_stop
+ *   Then rmmod gets around to calling hif_stop, but spins endlessly
+*   in napi_synchronize.
+*
+*  I think one way this could happen is that ath10k_stop checks
+*  for state != ATH10K_STATE_OFF, but STATE_RESTARTING is also
+*  a possibility.  That might be how we can have hif_stop called twice
+*  without a hif_start in between. --Ben
+*/
+   if (ar->napi_enabled) {
+   napi_synchronize(>napi);
+   napi_disable(>napi);
+   ar->napi_enabled = false;
+   }
 
spin_lock_irqsave(_pci->ps_lock, flags);
WARN_ON(ar_pci->ps_wake_refcount > 0);
-- 
2.4.11



[RFC] ath10k: Attempt to work around napi_synchronize hang.

2018-02-27 Thread greearb
From: Ben Greear 

Calling napi_disable twice in a row (w/out starting it and/or without
having NAPI active leads to deadlock because napi_disable sets
NAPI_STATE_SCHED and NAPI_STATE_NPSVC when it returns, as far as I
can tell.  So, guard this call to napi_disable.  I believe the
failure case is something like this:
 rmmod ath10k_pci ath10k_core
   Firmware crashes before hif_stop is called by the rmmod path
   The crash handling logic calls hif_stop
   Then rmmod gets around to calling hif_stop, but spins endlessly
   in napi_synchronize.

I think one way this could happen is that ath10k_stop checks
for state != ATH10K_STATE_OFF, but STATE_RESTARTING is also
a possibility.  That might be how we can have hif_stop called twice
without a hif_start in between. --Ben

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h |  1 +
 drivers/net/wireless/ath/ath10k/pci.c  | 25 +++--
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 72b4495..c7ba49f 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1205,6 +1205,7 @@ struct ath10k {
/* NAPI */
struct net_device napi_dev;
struct napi_struct napi;
+   bool napi_enabled;
 
struct work_struct stop_scan_work;
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 398e413..9131e15 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1956,6 +1956,7 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
 
napi_enable(>napi);
+   ar->napi_enabled = true;
 
ath10k_pci_irq_enable(ar);
ath10k_pci_rx_post(ar);
@@ -2086,8 +2087,28 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
-   napi_synchronize(>napi);
-   napi_disable(>napi);
+
+   /* Calling napi_disable twice in a row (w/out starting it and/or without
+* having NAPI active leads to deadlock because napi_disable sets
+* NAPI_STATE_SCHED and NAPI_STATE_NPSVC when it returns, as far as I
+* can tell.  So, guard this call to napi_disable.  I believe the
+* failure case is something like this:
+* rmmod ath10k_pci ath10k_core
+*   Firmware crashes before hif_stop is called by the rmmod path
+*   The crash handling logic calls hif_stop
+ *   Then rmmod gets around to calling hif_stop, but spins endlessly
+*   in napi_synchronize.
+*
+*  I think one way this could happen is that ath10k_stop checks
+*  for state != ATH10K_STATE_OFF, but STATE_RESTARTING is also
+*  a possibility.  That might be how we can have hif_stop called twice
+*  without a hif_start in between. --Ben
+*/
+   if (ar->napi_enabled) {
+   napi_synchronize(>napi);
+   napi_disable(>napi);
+   ar->napi_enabled = false;
+   }
 
spin_lock_irqsave(_pci->ps_lock, flags);
WARN_ON(ar_pci->ps_wake_refcount > 0);
-- 
2.4.11



[PATCH] ath9k: break out of irq handler after 5 jiffies

2018-02-06 Thread greearb
From: Ben Greear 

In case where the system is sluggish, we should probably break out
early.  Maybe this will fix issues where the OS thinks the IRQ handler
is not responding and disables the IRQ because 'nobody cared'

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath9k/recv.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c 
b/drivers/net/wireless/ath/ath9k/recv.c
index b90ea2b..274814c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1084,6 +1084,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool 
hp)
dma_addr_t new_buf_addr;
unsigned int budget = 512;
struct ieee80211_hdr *hdr;
+   unsigned long expires_jiffies = jiffies + 5;
 
if (edma)
dma_type = DMA_BIDIRECTIONAL;
@@ -1241,6 +1242,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool 
hp)
 
if (!budget--)
break;
+
+   if (time_is_before_jiffies(expires_jiffies))
+   break;
} while (1);
 
if (!(ah->imask & ATH9K_INT_RXEOL)) {
-- 
2.4.11



[PATCH v2] ath10k: Support mgt frame per-chain rssi

2018-02-06 Thread greearb
From: Ben Greear 

This provides per-chain rssi for management frames received
over wmi.

Signed-off-by: Ben Greear 
---

v2:  Fix 'rssh' typo in commit message.

 drivers/net/wireless/ath/ath10k/wmi.c | 21 -
 drivers/net/wireless/ath/ath10k/wmi.h |  1 +
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index 905af93..ff37274 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2287,6 +2287,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 = >hdr;
@@ -2302,6 +2303,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 +2360,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, );
if (ret) {
@@ -2416,6 +2426,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 +2467,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);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index a3ba191..d198772 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6490,6 +6490,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;
-- 
2.4.11



[PATCH] ath10k: Support mgt frame per-chain rssi

2018-02-01 Thread greearb
From: Ben Greear 

This provides per-chain rssh for management frames received
over wmi.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 21 -
 drivers/net/wireless/ath/ath10k/wmi.h |  1 +
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index 905af93..ff37274 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2287,6 +2287,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 = >hdr;
@@ -2302,6 +2303,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 +2360,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, );
if (ret) {
@@ -2416,6 +2426,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 +2467,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);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index a3ba191..d198772 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6490,6 +6490,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;
-- 
2.4.11



[PATCH v2] mac80211: Add txq flags to debugfs

2018-01-26 Thread greearb
From: Ben Greear 

Might help one figure out why aqm drivers may fail to transmit
frames sometimes.

Signed-off-by: Ben Greear 
---

v2:  Fix checking wrong flag for NO-AMSDU

 net/mac80211/debugfs_sta.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b15412c..bf101bd 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -160,12 +160,12 @@ static ssize_t sta_aqm_read(struct file *file, char 
__user *userbuf,
   sta->cparams.ecn ? "yes" : "no");
p += scnprintf(p,
   bufsz+buf-p,
-  "tid ac backlog-bytes backlog-packets new-flows drops 
marks overlimit collisions tx-bytes tx-packets\n");
+  "tid ac backlog-bytes backlog-packets new-flows drops 
marks overlimit collisions tx-bytes tx-packets flags\n");
 
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
txqi = to_txq_info(sta->sta.txq[i]);
p += scnprintf(p, bufsz+buf-p,
-  "%d %d %u %u %u %u %u %u %u %u %u\n",
+  "%d %d %u %u %u %u %u %u %u %u %u 
0x%lx(%s%s%s)\n",
   txqi->txq.tid,
   txqi->txq.ac,
   txqi->tin.backlog_bytes,
@@ -176,7 +176,11 @@ static ssize_t sta_aqm_read(struct file *file, char __user 
*userbuf,
   txqi->tin.overlimit,
   txqi->tin.collisions,
   txqi->tin.tx_bytes,
-  txqi->tin.tx_packets);
+  txqi->tin.tx_packets,
+  txqi->flags,
+  txqi->flags & (1<flags & (1<flags & (1<

[PATCH] mac80211: Add txq flags to debugfs

2018-01-26 Thread greearb
From: Ben Greear 

Might help one figure out why aqm drivers may fail to transmit
frames sometimes.

Signed-off-by: Ben Greear 
---
 net/mac80211/debugfs_sta.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index b15412c..570bc27 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -160,12 +160,12 @@ static ssize_t sta_aqm_read(struct file *file, char 
__user *userbuf,
   sta->cparams.ecn ? "yes" : "no");
p += scnprintf(p,
   bufsz+buf-p,
-  "tid ac backlog-bytes backlog-packets new-flows drops 
marks overlimit collisions tx-bytes tx-packets\n");
+  "tid ac backlog-bytes backlog-packets new-flows drops 
marks overlimit collisions tx-bytes tx-packets flags\n");
 
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
txqi = to_txq_info(sta->sta.txq[i]);
p += scnprintf(p, bufsz+buf-p,
-  "%d %d %u %u %u %u %u %u %u %u %u\n",
+  "%d %d %u %u %u %u %u %u %u %u %u 
0x%lx(%s%s%s)\n",
   txqi->txq.tid,
   txqi->txq.ac,
   txqi->tin.backlog_bytes,
@@ -176,7 +176,11 @@ static ssize_t sta_aqm_read(struct file *file, char __user 
*userbuf,
   txqi->tin.overlimit,
   txqi->tin.collisions,
   txqi->tin.tx_bytes,
-  txqi->tin.tx_packets);
+  txqi->tin.tx_packets,
+  txqi->flags,
+  txqi->flags & (1<flags & (1<flags & (1<

[PATCH] ath9k: Print has_queued in debugfs.

2018-01-26 Thread greearb
From: Ben Greear 

The PAUSED field was never printed per tid.  Replace that
with has_queued, which might help someone track down strange
bugs related to aqm.

And, make tx-queue debug info show peer BSSID as well as vdev
MAC to aid debugging with multiple stations connected to the
same peer.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath9k/debug_sta.c | 10 ++
 drivers/net/wireless/ath/ath9k/xmit.c  |  5 +++--
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c 
b/drivers/net/wireless/ath/ath9k/debug_sta.c
index efc692e..a45f1f5 100644
--- a/drivers/net/wireless/ath/ath9k/debug_sta.c
+++ b/drivers/net/wireless/ath/ath9k/debug_sta.c
@@ -48,9 +48,10 @@ static ssize_t read_file_node_aggr(struct file *file, char 
__user *user_buf,
 an->mpdudensity);
 
len += scnprintf(buf + len, size - len,
-"\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",
+"\n%3s%11s%10s%10s%10s%10s%9s%6s%9s\n",
 "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
-"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
+"BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED",
+"HAS-QUED");
 
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
tid = ath_node_to_tid(an, tidno);
@@ -58,7 +59,7 @@ static ssize_t read_file_node_aggr(struct file *file, char 
__user *user_buf,
ath_txq_lock(sc, txq);
if (tid->active) {
len += scnprintf(buf + len, size - len,
-"%3d%11d%10d%10d%10d%10d%9d%6d\n",
+"%3d%11d%10d%10d%10d%10d%9d%6d%9d\n",
 tid->tidno,
 tid->seq_start,
 tid->seq_next,
@@ -66,7 +67,8 @@ static ssize_t read_file_node_aggr(struct file *file, char 
__user *user_buf,
 tid->baw_head,
 tid->baw_tail,
 tid->bar_index,
-!list_empty(>list));
+!list_empty(>list),
+tid->has_queued);
}
ath_txq_unlock(sc, txq);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c 
b/drivers/net/wireless/ath/ath9k/xmit.c
index 26bf9d4..c28f62f 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -157,8 +157,9 @@ void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct 
ieee80211_txq *queue)
struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv;
struct ath_txq *txq = tid->txq;
 
-   ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n",
-   queue->sta ? queue->sta->addr : queue->vif->addr,
+   ath_dbg(common, QUEUE,
+   "Waking TX queue: sta-addr %pM vif: %pM (tid %d)\n",
+   queue->sta ? queue->sta->addr : NULL, queue->vif->addr,
tid->tidno);
 
ath_txq_lock(sc, txq);
-- 
2.4.11



[PATCH] ath10k: Support use of channel 173

2018-01-02 Thread greearb
From: Ben Greear 

The India regulatory domain allows CH 173, so add that to the
available channel list.  I verified basic connectivity between
a 9880 and 9984 NIC.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h | 3 ++-
 drivers/net/wireless/ath/ath10k/mac.c  | 3 +++
 drivers/net/wireless/ath/ath10k/wmi.c  | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index bcee3ec..cdcdff1 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -46,7 +46,8 @@
 #define WMI_READY_TIMEOUT (5 * HZ)
 #define ATH10K_FLUSH_TIMEOUT_HZ (5 * HZ)
 #define ATH10K_CONNECTION_LOSS_HZ (3 * HZ)
-#define ATH10K_NUM_CHANS 40
+#define ATH10K_NUM_CHANS 41
+#define ATH10K_MAX_5G_CHAN 173
 
 /* Antenna noise floor */
 #define ATH10K_DEFAULT_NOISE_FLOOR -95
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index c715ba1..3c03edf 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8540,6 +8540,9 @@ static const struct ieee80211_channel 
ath10k_5ghz_channels[] = {
CHAN5G(161, 5805, 0),
CHAN5G(165, 5825, 0),
CHAN5G(169, 5845, 0),
+   CHAN5G(173, 5865, 0),
+   /* If you add more, you may need to change ATH10K_MAX_5G_CHAN */
+   /* And you will definitely need to change ATH10K_NUM_CHANS in core.h */
 };
 
 struct ath10k *ath10k_mac_create(size_t priv_size)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index f29ce83..905af93 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -2398,7 +2398,7 @@ int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct 
sk_buff *skb)
 */
if (channel >= 1 && channel <= 14) {
status->band = NL80211_BAND_2GHZ;
-   } else if (channel >= 36 && channel <= 169) {
+   } else if (channel >= 36 && channel <= ATH10K_MAX_5G_CHAN) {
status->band = NL80211_BAND_5GHZ;
} else {
/* Shouldn't happen unless list of advertised channels to
-- 
2.4.11



[PATCH] ath10k: Report and display mem use for 10.4, 10.2 firmware.

2018-01-02 Thread greearb
From: Ben Greear 

The 10.4 'mem' reporting struct had the wrong order vs the 10.2,
so just make a new _10_4 specific struct.  Save these reported
values and make them available via debugfs.

Stock 10.4 firmware probably reports zero values
for this currently, but they will be notified of a fix
for this shortly.

I did not test 10.2 firmware, so not sure what it reports.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h |  5 +
 drivers/net/wireless/ath/ath10k/wmi.c  | 13 +
 drivers/net/wireless/ath/ath10k/wmi.h  |  9 +++--
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 1aacc9b8..bcee3ec 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -289,6 +289,11 @@ struct ath10k_fw_stats_pdev {
s32 mpdu_errs;
s32 rx_ovfl_errs;
s32 rx_timeout_errs;
+
+   /* Other PDEV stats */
+   s32 dram_free;
+   s32 iram_free;
+   s32 sram_free;
 };
 
 struct ath10k_fw_stats {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index cba6dad..f29ce83 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3046,6 +3046,9 @@ static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k 
*ar,
ath10k_wmi_pull_pdev_stats_base(>base, dst);
ath10k_wmi_pull_pdev_stats_tx(>tx, dst);
ath10k_wmi_pull_pdev_stats_rx(>rx, dst);
+   dst->rx_timeout_errs = __le32_to_cpu(src->pdev_rx_timeout);
+   dst->dram_free = __le32_to_cpu(src->mem.dram_free);
+   dst->iram_free = __le32_to_cpu(src->mem.iram_free);
ath10k_wmi_pull_pdev_stats_extra(>extra, dst);
/* FIXME: expose 10.2 specific values */
 
@@ -3219,6 +3222,9 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k 
*ar,
ath10k_wmi_pull_pdev_stats_rx(>rx, dst);
dst->rx_timeout_errs = __le32_to_cpu(src->pdev_rx_timeout);
dst->rx_ovfl_errs = __le32_to_cpu(src->rx_ovfl_errs);
+   dst->dram_free = __le32_to_cpu(src->mem.dram_free);
+   dst->iram_free = __le32_to_cpu(src->mem.iram_free);
+   dst->sram_free = __le32_to_cpu(src->mem.sram_free);
ath10k_wmi_pull_pdev_stats_extra(>extra, dst);
 
list_add_tail(>list, >pdevs);
@@ -8249,6 +8255,13 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Num Rx Overflow errors", pdev->rx_ovfl_errs);
 
+   len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+"DRAM Free", pdev->dram_free);
+   len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+"IRAM Free", pdev->iram_free);
+   len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+"SRAM Free", pdev->sram_free);
+
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
"ath10k VDEV stats", num_vdevs);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index 93ca8e8..a3ba191 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4419,6 +4419,12 @@ struct wmi_pdev_stats_mem {
__le32 iram_free;
 } __packed;
 
+struct wmi_pdev_stats_mem_10_4 {
+   __le32 iram_free;
+   __le32 dram_free;
+   __le32 sram_free;
+} __packed;
+
 struct wmi_10_2_pdev_stats {
struct wmi_pdev_stats_base base;
struct wmi_pdev_stats_tx tx;
@@ -4436,8 +4442,7 @@ struct wmi_10_4_pdev_stats {
struct wmi_pdev_stats_rx rx;
__le32 pdev_rx_timeout;
__le32 rx_ovfl_errs;
-   struct wmi_pdev_stats_mem mem;
-   __le32 sram_free_size;
+   struct wmi_pdev_stats_mem_10_4 mem;
struct wmi_pdev_stats_extra extra;
 } __packed;
 
-- 
2.4.11



[PATCH] ath10k: Report rx-timeout errors.

2018-01-02 Thread greearb
From: Ben Greear 

The rx pdev related stats do not match the 10.4 firmware stats
struct.  The pdev-rx-timeout field needs to be added.

Stock firmware may not actually ever increment that value,
but this should at least help the other stats be aligned properly.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h | 1 +
 drivers/net/wireless/ath/ath10k/wmi.c  | 3 +++
 drivers/net/wireless/ath/ath10k/wmi.h  | 1 +
 3 files changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index a6b0894..1aacc9b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -288,6 +288,7 @@ struct ath10k_fw_stats_pdev {
s32 phy_err_drop;
s32 mpdu_errs;
s32 rx_ovfl_errs;
+   s32 rx_timeout_errs;
 };
 
 struct ath10k_fw_stats {
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index f3e6c67..cba6dad 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3217,6 +3217,7 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k 
*ar,
ath10k_wmi_pull_pdev_stats_base(>base, dst);
ath10k_wmi_10_4_pull_pdev_stats_tx(>tx, dst);
ath10k_wmi_pull_pdev_stats_rx(>rx, dst);
+   dst->rx_timeout_errs = __le32_to_cpu(src->pdev_rx_timeout);
dst->rx_ovfl_errs = __le32_to_cpu(src->rx_ovfl_errs);
ath10k_wmi_pull_pdev_stats_extra(>extra, dst);
 
@@ -8244,6 +8245,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
 
ath10k_wmi_fw_pdev_rx_stats_fill(pdev, buf, );
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
+   "Num Rx Timeout errors", pdev->rx_timeout_errs);
+   len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"Num Rx Overflow errors", pdev->rx_ovfl_errs);
 
len += scnprintf(buf + len, buf_len - len, "\n");
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index 66b446d..93ca8e8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4434,6 +4434,7 @@ struct wmi_10_4_pdev_stats {
struct wmi_pdev_stats_base base;
struct wmi_10_4_pdev_stats_tx tx;
struct wmi_pdev_stats_rx rx;
+   __le32 pdev_rx_timeout;
__le32 rx_ovfl_errs;
struct wmi_pdev_stats_mem mem;
__le32 sram_free_size;
-- 
2.4.11



[PATCH] ath10k: Fix invalid STS_CAP_OFFSET_MASK.

2017-11-14 Thread greearb
From: Ben Greear 

The 10.4 firmware defines this as a 3-bit field, as does the
mac80211 stack.  The 4th bit is defined as CONF_IMPLICIT_BF
at least in the firmware header I have seen.  This patch
fixes the ath10k wmi header to match the firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index ff15c37..9522f22 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -5195,7 +5195,8 @@ enum wmi_10_4_vdev_param {
 #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
 
 #define WMI_TXBF_STS_CAP_OFFSET_LSB4
-#define WMI_TXBF_STS_CAP_OFFSET_MASK   0xf0
+#define WMI_TXBF_STS_CAP_OFFSET_MASK   0x70
+#define WMI_TXBF_CONF_IMPLICIT_BF   BIT(7)
 #define WMI_BF_SOUND_DIM_OFFSET_LSB8
 #define WMI_BF_SOUND_DIM_OFFSET_MASK   0xf00
 
-- 
2.4.11



[PATCH] ath10k: Fix offchannel tx failure when no ath10k_mac_tx_frm_has_freq

2017-10-17 Thread greearb
From: Ben Greear 

This bug appears to have been added between 4.0 (which works for us),
and 4.4, which does not work.

I think this is because the tx-offchannel logic gets in a loop when
ath10k_mac_tx_frm_has_freq(ar) is false, so pkt is never actually
sent to the firmware for transmit.

This patch fixes the problem on 4.9 for me, and now HS20 clients
can work again with my firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 22 +++---
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index c45ca04..f0a7864 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4101,7 +4101,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
 struct ieee80211_sta *sta,
 enum ath10k_hw_txrx_mode txmode,
 enum ath10k_mac_tx_path txpath,
-struct sk_buff *skb)
+struct sk_buff *skb, bool noque_offchan)
 {
struct ieee80211_hw *hw = ar->hw;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -4134,10 +4134,10 @@ static int ath10k_mac_tx(struct ath10k *ar,
}
}
 
-   if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
+   if ((!noque_offchan) && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
if (!ath10k_mac_tx_frm_has_freq(ar)) {
-   ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb 
%pK\n",
-  skb);
+   ath10k_dbg(ar, ATH10K_DBG_MAC, "no-tx-frm-has-freq: 
queued offchannel skb %pK, len: %d\n",
+  skb, skb->len);
 
skb_queue_tail(>offchan_tx_queue, skb);
ieee80211_queue_work(hw, >offchan_tx_work);
@@ -4198,8 +4198,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 
mutex_lock(>conf_mutex);
 
-   ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n",
-  skb);
+   ath10k_dbg(ar, ATH10K_DBG_MAC, "offchan-tx-work: mac offchannel 
skb %pK len: %d\n",
+  skb, skb->len);
 
hdr = (struct ieee80211_hdr *)skb->data;
peer_addr = ieee80211_get_DA(hdr);
@@ -4245,7 +4245,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
 
-   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
+   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb, true);
if (ret) {
ath10k_warn(ar, "failed to transmit offchannel frame: 
%d\n",
ret);
@@ -4255,8 +4255,8 @@ void ath10k_offchan_tx_work(struct work_struct *work)
time_left =
wait_for_completion_timeout(>offchan_tx_completed, 3 * HZ);
if (time_left == 0)
-   ath10k_warn(ar, "timed out waiting for offchannel skb 
%pK\n",
-   skb);
+   ath10k_warn(ar, "timed out waiting for offchannel skb 
%pK, len: %d\n",
+   skb, skb->len);
 
if (!peer && tmp_peer_created) {
ret = ath10k_peer_delete(ar, vdev_id, peer_addr);
@@ -4513,7 +4513,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
spin_unlock_bh(>htt.tx_lock);
}
 
-   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
+   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb, false);
if (unlikely(ret)) {
ath10k_warn(ar, "failed to push frame: %d\n", ret);
 
@@ -4802,7 +4802,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
spin_unlock_bh(>htt.tx_lock);
}
 
-   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
+   ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb, false);
if (ret) {
ath10k_warn(ar, "failed to transmit frame: %d\n", ret);
if (is_htt) {
-- 
2.4.11



[PATCH v2] ath10k: Retry pci probe on failure.

2017-10-03 Thread greearb
From: Ben Greear 

This works around a problem we see when sometimes the wifi NIC does
not respond the first time.  This seems to happen especially often on
some of the 9984 NICs in mid-range platforms.

Signed-off-by: Ben Greear 
---

v2:  Change to mdelay instead of udelay to fix compile issue on ARM.

 drivers/net/wireless/ath/ath10k/pci.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 77beb13..0861f7f 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3487,8 +3487,8 @@ static const struct ath10k_bus_ops ath10k_pci_bus_ops = {
.get_num_banks  = ath10k_pci_get_num_banks,
 };
 
-static int ath10k_pci_probe(struct pci_dev *pdev,
-   const struct pci_device_id *pci_dev)
+static int __ath10k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_dev)
 {
int ret = 0;
struct ath10k *ar;
@@ -3672,6 +3672,22 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
return ret;
 }
 
+static int ath10k_pci_probe(struct pci_dev *pdev,
+   const struct pci_device_id *pci_dev)
+{
+   int cnt = 0;
+   int rv;
+   do {
+   rv = __ath10k_pci_probe(pdev, pci_dev);
+   if (rv == 0)
+   return rv;
+   pr_err("ath10k: failed to probe PCI : %d, retry-count: %d\n", 
rv, cnt);
+   mdelay(10); /* let the ath10k firmware gerbil take a small 
break */
+   } while (cnt++ < 10);
+   return rv;
+}
+
+
 static void ath10k_pci_remove(struct pci_dev *pdev)
 {
struct ath10k *ar = pci_get_drvdata(pdev);
-- 
2.4.11



[PATCH] ath10k: Store coverage-class in case firmware is not booted.

2017-10-03 Thread greearb
From: Ben Greear 

This way, we can apply the values when the NIC does come up.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/hw.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/hw.c 
b/drivers/net/wireless/ath/ath10k/hw.c
index afb0c01..31c0589 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -454,8 +454,13 @@ static void ath10k_hw_qca988x_set_coverage_class(struct 
ath10k *ar,
 
/* Only modify registers if the core is started. */
if ((ar->state != ATH10K_STATE_ON) &&
-   (ar->state != ATH10K_STATE_RESTARTED))
+   (ar->state != ATH10K_STATE_RESTARTED)) {
+   spin_lock_bh(>data_lock);
+   /* Store config value for when radio boots up */
+   ar->fw_coverage.coverage_class = value;
+   spin_unlock_bh(>data_lock);
goto unlock;
+   }
 
/* Retrieve the current values of the two registers that need to be
 * adjusted.
@@ -487,7 +492,7 @@ static void ath10k_hw_qca988x_set_coverage_class(struct 
ath10k *ar,
ar->fw_coverage.reg_ack_cts_timeout_orig = timeout_reg;
ar->fw_coverage.reg_phyclk = phyclk_reg;
 
-   /* Calculat new value based on the (original) firmware calculation. */
+   /* Calculate new value based on the (original) firmware calculation. */
slottime_reg = ar->fw_coverage.reg_slottime_orig;
timeout_reg = ar->fw_coverage.reg_ack_cts_timeout_orig;
 
-- 
2.4.11



[PATCH] ath10k: Retry pci probe on failure.

2017-09-26 Thread greearb
From: Ben Greear 

This works around a problem we see when sometimes the wifi NIC does
not respond the first time.  This seems to happen especially often on
some of the 9984 NICs in mid-range platforms.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/pci.c | 20 ++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index e0a7b338..8f3c5b1 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3492,8 +3492,8 @@ static const struct ath10k_bus_ops ath10k_pci_bus_ops = {
.get_num_banks  = ath10k_pci_get_num_banks,
 };
 
-static int ath10k_pci_probe(struct pci_dev *pdev,
-   const struct pci_device_id *pci_dev)
+static int __ath10k_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_dev)
 {
int ret = 0;
struct ath10k *ar;
@@ -3668,6 +3668,22 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
return ret;
 }
 
+static int ath10k_pci_probe(struct pci_dev *pdev,
+   const struct pci_device_id *pci_dev)
+{
+   int cnt = 0;
+   int rv;
+   do {
+   rv = __ath10k_pci_probe(pdev, pci_dev);
+   if (rv == 0)
+   return rv;
+   pr_err("ath10k: failed to probe PCI : %d, retry-count: %d\n", 
rv, cnt);
+   udelay(1); /* let the ath10k firmware gerbil take a small 
break */
+   } while (cnt++ < 10);
+   return rv;
+}
+
+
 static void ath10k_pci_remove(struct pci_dev *pdev)
 {
struct ath10k *ar = pci_get_drvdata(pdev);
-- 
2.4.11



[PATCH v3 4/4] mac80211-hwsim: add length checks before allocating skb.

2017-03-23 Thread greearb
From: Ben Greear 

Modify the receive-from-user-space logic to do length
and 'is-down' checks before trying to allocate an skb.

And, if we are going to ignore the pkt due to radio idle,
then do not return an error code to user-space.  User-space
cannot reliably know exactly when a radio is idle or not.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 41 +++
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 84dcddf..6207d4a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3074,6 +3074,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
int frame_data_len;
void *frame_data;
struct sk_buff *skb = NULL;
+   int rv = -EINVAL;
 
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
@@ -3088,25 +3089,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
 
-   /* Allocate new skb here */
-   skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL) {
-   if (hwsim_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
-  frame_data_len);
-   goto out;
-   }
-
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
-   if (hwsim_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
-  frame_data_len, IEEE80211_MAX_DATA_LEN);
-   goto out;
-   }
-
-   /* Copy the data */
-   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
-
data2 = get_hwsim_data_ref_from_addr(dst);
 
if (!data2) {
@@ -3135,9 +3117,30 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (((cnt++ & 0x3FF) == 0x3FF) && hwsim_ratelimit())
printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
   dst, data2->idle, !data2->started, cnt);
+   rv = -ENETDOWN;
goto out;
}
 
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
+
+
+   /* Allocate new skb here */
+   skb = alloc_skb(frame_data_len, GFP_KERNEL);
+   if (skb == NULL) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
+   goto out;
+   }
+
+   /* Copy the data */
+   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
+
/* A frame is received from user space */
memset(_status, 0, sizeof(rx_status));
if (info->attrs[HWSIM_ATTR_FREQ]) {
-- 
2.4.11



[PATCH v3 3/4] mac80211-hwsim: add rate-limited debugging for rx-netlink

2017-03-23 Thread greearb
From: Ben Greear 

This makes it easier to understand why wmediumd (or similar)
is getting errors when sending frames to the kernel.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 55 +++
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 234df8c..84dcddf 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -137,6 +137,12 @@ static int regtest = HWSIM_REGTEST_DISABLED;
 module_param(regtest, int, 0444);
 MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run");
 
+DEFINE_RATELIMIT_STATE(hwsim_ratelimit_state, 5 * HZ, 10);
+int hwsim_ratelimit(void)
+{
+   return __ratelimit(_ratelimit_state);
+}
+
 static const char *hwsim_alpha2s[] = {
"FI",
"AL",
@@ -1649,7 +1655,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
 
if (conf->chandef.chan)
wiphy_debug(hw->wiphy,
-   "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
+   "%s (chandef-chan freq=%d(%d - %d)/%s idle=%d ps=%d 
smps=%s)\n",
__func__,
conf->chandef.chan->center_freq,
conf->chandef.center_freq1,
@@ -1660,7 +1666,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
smps_modes[conf->smps_mode]);
else
wiphy_debug(hw->wiphy,
-   "%s (freq=0 idle=%d ps=%d smps=%s)\n",
+   "%s (no-chandef-chan freq=0 idle=%d ps=%d 
smps=%s)\n",
__func__,
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
@@ -3072,8 +3078,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
-   !info->attrs[HWSIM_ATTR_SIGNAL])
+   !info->attrs[HWSIM_ATTR_SIGNAL]) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Missing required 
attribute\n");
goto out;
+   }
 
dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
@@ -3081,29 +3090,53 @@ static int hwsim_cloned_frame_received_nl(struct 
sk_buff *skb_2,
 
/* Allocate new skb here */
skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL)
-   goto err;
+   if (skb == NULL) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
+   goto out;
+   }
 
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN)
-   goto err;
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
 
/* Copy the data */
memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
 
data2 = get_hwsim_data_ref_from_addr(dst);
-   if (!data2)
+
+   if (!data2) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Cannot find radio 
%pM\n",
+  dst);
goto out;
+   }
 
if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
goto out;
 
-   if (info->snd_portid != data2->wmediumd)
+   if (info->snd_portid != data2->wmediumd) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: portid mismatch, 
snd_portid: %d  portid %d\n",
+  info->snd_portid, data2->wmediumd);
goto out;
+   }
 
/* check if radio is configured properly */
 
-   if (data2->idle || !data2->started)
+   if (data2->idle || !data2->started) {
+   static unsigned int cnt = 0;
+   /* This is fairly common, and usually not a bug.  So, print 
errors
+  rarely. */
+   if (((cnt++ & 0x3FF) == 0x3FF) && hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
+  dst, data2->idle, !data2->started, cnt);
goto out;
+   }
 
/* A frame is received from user space */
memset(_status, 0, sizeof(rx_status));
@@ -3136,8 +3169,6 

[PATCH v3 1/4] mac80211-hwsim: notify user-space about channel change.

2017-03-23 Thread greearb
From: Ben Greear 

The goal is to allow the user-space application to properly
filter packets before sending them down to the kernel.  This
should more closely mimic what a real piece of hardware would
do.

Signed-off-by: Ben Greear 
---

v3:  Rebased against latest wireless-testing, renamed "CH_FREQ" to CENTER_FREQ,
don't send center_freq2 if value is zero.

Compile tested, not run-time tested since original patches were written.

 drivers/net/wireless/mac80211_hwsim.c | 70 +++
 drivers/net/wireless/mac80211_hwsim.h | 16 
 2 files changed, 86 insertions(+)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 67fc91d..f1ad908 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -533,6 +533,10 @@ struct mac80211_hwsim_data {
  ARRAY_SIZE(hwsim_channels_5ghz)];
 
struct ieee80211_channel *channel;
+   enum nl80211_chan_width ch_width;
+   u32 center_freq1;
+   u32 center_freq2;
+
u64 beacon_int  /* beacon interval in us */;
unsigned int rx_filter;
bool started, idle, scanning;
@@ -1004,6 +1008,65 @@ static int hwsim_unicast_netgroup(struct 
mac80211_hwsim_data *data,
return res;
 }
 
+static void mac80211_hwsim_check_nl_notify(struct mac80211_hwsim_data *data)
+{
+   struct sk_buff *skb;
+   u32 center_freq = 0;
+   u32 _portid;
+   void *msg_head;
+
+   /* wmediumd mode check */
+   _portid = READ_ONCE(data->wmediumd);
+
+   if (!_portid)
+   return;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+   if (!skb)
+   goto err_print;
+
+   msg_head = genlmsg_put(skb, 0, 0, _genl_family, 0,
+  HWSIM_CMD_NOTIFY_CH_CHANGE);
+   if (!msg_head) {
+   pr_debug("mac80211_hwsim: problem with msg_head, 
notify-ch-change\n");
+   goto nla_put_failure;
+   }
+
+   if (nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, data->idx))
+   goto nla_put_failure;
+
+   if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+   ETH_ALEN, data->addresses[1].addr))
+   goto nla_put_failure;
+
+   if (data->channel)
+   center_freq = data->channel->center_freq;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_FREQ, center_freq))
+   goto nla_put_failure;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_CENTER_FREQ1, data->center_freq1))
+   goto nla_put_failure;
+
+   if (data->center_freq2)
+   if (nla_put_u32(skb, HWSIM_ATTR_CENTER_FREQ2, 
data->center_freq2))
+   goto nla_put_failure;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_CH_WIDTH, data->ch_width))
+   goto nla_put_failure;
+
+   genlmsg_end(skb, msg_head);
+   if (genlmsg_unicast(_net, skb, _portid))
+   goto err_print;
+
+   return;
+
+nla_put_failure:
+   nlmsg_free(skb);
+err_print:
+   pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
+}
+
 static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
   struct sk_buff *my_skb,
   int dst_portid)
@@ -1631,6 +1694,11 @@ static int mac80211_hwsim_config(struct ieee80211_hw 
*hw, u32 changed)
} else {
data->channel = conf->chandef.chan;
}
+
+   data->ch_width = conf->chandef.width;
+   data->center_freq1 = conf->chandef.center_freq1;
+   data->center_freq2 = conf->chandef.center_freq2;
+
mutex_unlock(>mutex);
 
data->power_level = conf->power_level;
@@ -1646,6 +1714,8 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
  HRTIMER_MODE_REL);
}
 
+   mac80211_hwsim_check_nl_notify(data);
+
return 0;
 }
 
diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index 3f5eda5..523fbc4 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -71,6 +71,15 @@ enum hwsim_tx_control_flags {
  * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
  * %HWSIM_ATTR_RADIO_ID
+ * @HWSIM_CMD_NOTIFY_CH_CHANGE: notify user-space about channel-change.  This 
is
+ * designed to help the user-space app better emulate radio hardware.
+ * This command uses:
+ * %HWSIM_ATTR_FREQ # Notify current operating center frequency.
+ * %HWSIM_ATTR_CH_FREQ1 # Configured center-freq-1.
+ * %HWSIM_ATTR_CH_FREQ2 # Configured center-freq-2.
+ * %HWSIM_ATTR_CH_WIDTH # Configured channel width.
+ * %HWSIM_ATTR_ADDR_TRANSMITTER # ID which radio we are notifying about.
+ * %HWSIM_ATTR_ADDR_ID # Numeric Radio ID.
  * @__HWSIM_CMD_MAX: enum limit
 

[PATCH v3 2/4] mac80211-hwsim: remove dmesg spam about get-survey.

2017-03-23 Thread greearb
From: Ben Greear 

This message just fills up dmesg and/or kernel logs and does
not provide any useful information.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index f1ad908..234df8c 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1893,8 +1893,6 @@ static int mac80211_hwsim_get_survey(struct ieee80211_hw 
*hw, int idx,
 {
struct mac80211_hwsim_data *hwsim = hw->priv;
 
-   wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
-
if (idx < 0 || idx >= ARRAY_SIZE(hwsim->survey_data))
return -ENOENT;
 
-- 
2.4.11



[PATCH v2 2/4] mac80211-hwsim: remove dmesg spam about get-survey.

2017-02-27 Thread greearb
From: Ben Greear 

This message just fills up dmesg and/or kernel logs and does
not provide any useful information.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 12e9333..635ad03 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1860,8 +1860,6 @@ static int mac80211_hwsim_get_survey(
 {
struct ieee80211_conf *conf = >conf;
 
-   wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
-
if (idx != 0)
return -ENOENT;
 
-- 
2.4.11



[PATCH v2 1/4] mac80211-hwsim: notify user-space about channel change.

2017-02-27 Thread greearb
From: Ben Greear 

The goal is to allow the user-space application to properly
filter packets before sending them down to the kernel.  This
should more closely mimic what a real piece of hardware would
do.

Signed-off-by: Ben Greear 
---
v2:  Change IDs, add new ones for width, freq1, freq2.

 drivers/net/wireless/mac80211_hwsim.c | 67 +++
 drivers/net/wireless/mac80211_hwsim.h | 16 +
 2 files changed, 83 insertions(+)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 0150747..12e9333 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -527,6 +527,10 @@ struct mac80211_hwsim_data {
u8 scan_addr[ETH_ALEN];
 
struct ieee80211_channel *channel;
+   enum nl80211_chan_width ch_width;
+   u32 center_freq1;
+   u32 center_freq2;
+
u64 beacon_int  /* beacon interval in us */;
unsigned int rx_filter;
bool started, idle, scanning;
@@ -998,6 +1002,64 @@ static int hwsim_unicast_netgroup(struct 
mac80211_hwsim_data *data,
return res;
 }
 
+static void mac80211_hwsim_check_nl_notify(struct mac80211_hwsim_data *data)
+{
+   struct sk_buff *skb;
+   u32 center_freq = 0;
+   u32 _portid;
+   void *msg_head;
+
+   /* wmediumd mode check */
+   _portid = READ_ONCE(data->wmediumd);
+
+   if (!_portid)
+   return;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+   if (!skb)
+   goto err_print;
+
+   msg_head = genlmsg_put(skb, 0, 0, _genl_family, 0,
+  HWSIM_CMD_NOTIFY_CH_CHANGE);
+   if (!msg_head) {
+   pr_debug("mac80211_hwsim: problem with msg_head, 
notify-ch-change\n");
+   goto nla_put_failure;
+   }
+
+   if (nla_put_u32(skb, HWSIM_ATTR_RADIO_ID, data->idx))
+   goto nla_put_failure;
+
+   if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+   ETH_ALEN, data->addresses[1].addr))
+   goto nla_put_failure;
+
+   if (data->channel)
+   center_freq = data->channel->center_freq;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_FREQ, center_freq))
+   goto nla_put_failure;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_CH_FREQ1, data->center_freq1))
+   goto nla_put_failure;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_CH_FREQ2, data->center_freq2))
+   goto nla_put_failure;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_CH_WIDTH, data->ch_width))
+   goto nla_put_failure;
+
+   genlmsg_end(skb, msg_head);
+   if (genlmsg_unicast(_net, skb, _portid))
+   goto err_print;
+
+   return;
+
+nla_put_failure:
+   nlmsg_free(skb);
+err_print:
+   pr_debug("mac80211_hwsim: error occurred in %s\n", __func__);
+}
+
 static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
   struct sk_buff *my_skb,
   int dst_portid)
@@ -1599,6 +1661,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
data->channel = conf->chandef.chan;
+   data->ch_width = conf->chandef.width;
+   data->center_freq1 = conf->chandef.center_freq1;
+   data->center_freq2 = conf->chandef.center_freq2;
 
WARN_ON(data->channel && data->use_chanctx);
 
@@ -1615,6 +1680,8 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
  HRTIMER_MODE_REL);
}
 
+   mac80211_hwsim_check_nl_notify(data);
+
return 0;
 }
 
diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index 39f2246..1251fdd 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -71,6 +71,15 @@ enum hwsim_tx_control_flags {
  * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
  * %HWSIM_ATTR_RADIO_ID
+ * @HWSIM_CMD_NOTIFY_CH_CHANGE: notify user-space about channel-change.  This 
is
+ * designed to help the user-space app better emulate radio hardware.
+ * This command uses:
+ * %HWSIM_ATTR_FREQ # Notify current operating center frequency.
+ * %HWSIM_ATTR_CH_FREQ1 # Configured center-freq-1.
+ * %HWSIM_ATTR_CH_FREQ2 # Configured center-freq-2.
+ * %HWSIM_ATTR_CH_WIDTH # Configured channel width.
+ * %HWSIM_ATTR_ADDR_TRANSMITTER # ID which radio we are notifying about.
+ * %HWSIM_ATTR_ADDR_ID # Numeric Radio ID.
  * @__HWSIM_CMD_MAX: enum limit
  */
 enum {
@@ -81,6 +90,7 @@ enum {
HWSIM_CMD_NEW_RADIO,
HWSIM_CMD_DEL_RADIO,
HWSIM_CMD_GET_RADIO,
+   HWSIM_CMD_NOTIFY_CH_CHANGE,
__HWSIM_CMD_MAX,
 };
 #define HWSIM_CMD_MAX 

[PATCH v2 4/4] mac80211-hwsim: add length checks before allocating skb.

2017-02-27 Thread greearb
From: Ben Greear 

Modify the receive-from-user-space logic to do length
and 'is-down' checks before trying to allocate an skb.

And, if we are going to ignore the pkt due to radio idle,
then do not return an error code to user-space.  User-space
cannot reliably know exactly when a radio is idle or not.

Signed-off-by: Ben Greear 
---

v2:  Don't return success when radio is idle, but do return unique
 error code (ENETDOWN) in hopes user-space can make a distinction.

 drivers/net/wireless/mac80211_hwsim.c | 41 +++
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index c259b99..73dc627 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3020,6 +3020,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
int frame_data_len;
void *frame_data;
struct sk_buff *skb = NULL;
+   int rv = -EINVAL;
 
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
@@ -3034,25 +3035,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
 
-   /* Allocate new skb here */
-   skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL) {
-   if (hwsim_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
-  frame_data_len);
-   goto out;
-   }
-
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
-   if (hwsim_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
-  frame_data_len, IEEE80211_MAX_DATA_LEN);
-   goto out;
-   }
-
-   /* Copy the data */
-   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
-
data2 = get_hwsim_data_ref_from_addr(dst);
 
if (!data2) {
@@ -3081,9 +3063,30 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (((cnt++ & 0x3FF) == 0x3FF) && hwsim_ratelimit())
printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
   dst, data2->idle, !data2->started, cnt);
+   rv = -ENETDOWN;
goto out;
}
 
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
+
+
+   /* Allocate new skb here */
+   skb = alloc_skb(frame_data_len, GFP_KERNEL);
+   if (skb == NULL) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
+   goto out;
+   }
+
+   /* Copy the data */
+   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
+
/* A frame is received from user space */
memset(_status, 0, sizeof(rx_status));
if (info->attrs[HWSIM_ATTR_FREQ]) {
-- 
2.4.11



[PATCH v2 3/4] mac80211-hwsim: add rate-limited debugging for rx-netlink

2017-02-27 Thread greearb
From: Ben Greear 

This makes it easier to understand why wmediumd (or similar)
is getting errors when sending frames to the kernel.

Signed-off-by: Ben Greear 
---

v2:  Add and use hwsim_ratelimit() instead of net_ratelimit.
 Squash two patches into this one.

 drivers/net/wireless/mac80211_hwsim.c | 55 +++
 1 file changed, 43 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 635ad03..c259b99 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -137,6 +137,12 @@ static int regtest = HWSIM_REGTEST_DISABLED;
 module_param(regtest, int, 0444);
 MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run");
 
+DEFINE_RATELIMIT_STATE(hwsim_ratelimit_state, 5 * HZ, 10);
+int hwsim_ratelimit(void)
+{
+   return __ratelimit(_ratelimit_state);
+}
+
 static const char *hwsim_alpha2s[] = {
"FI",
"AL",
@@ -1641,7 +1647,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
 
if (conf->chandef.chan)
wiphy_debug(hw->wiphy,
-   "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
+   "%s (chandef-chan freq=%d(%d - %d)/%s idle=%d ps=%d 
smps=%s)\n",
__func__,
conf->chandef.chan->center_freq,
conf->chandef.center_freq1,
@@ -1652,7 +1658,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
smps_modes[conf->smps_mode]);
else
wiphy_debug(hw->wiphy,
-   "%s (freq=0 idle=%d ps=%d smps=%s)\n",
+   "%s (no-chandef-chan freq=0 idle=%d ps=%d 
smps=%s)\n",
__func__,
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
@@ -3018,8 +3024,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
-   !info->attrs[HWSIM_ATTR_SIGNAL])
+   !info->attrs[HWSIM_ATTR_SIGNAL]) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Missing required 
attribute\n");
goto out;
+   }
 
dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
@@ -3027,29 +3036,53 @@ static int hwsim_cloned_frame_received_nl(struct 
sk_buff *skb_2,
 
/* Allocate new skb here */
skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL)
-   goto err;
+   if (skb == NULL) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
+   goto out;
+   }
 
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN)
-   goto err;
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
 
/* Copy the data */
memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
 
data2 = get_hwsim_data_ref_from_addr(dst);
-   if (!data2)
+
+   if (!data2) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Cannot find radio 
%pM\n",
+  dst);
goto out;
+   }
 
if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
goto out;
 
-   if (info->snd_portid != data2->wmediumd)
+   if (info->snd_portid != data2->wmediumd) {
+   if (hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: portid mismatch, 
snd_portid: %d  portid %d\n",
+  info->snd_portid, data2->wmediumd);
goto out;
+   }
 
/* check if radio is configured properly */
 
-   if (data2->idle || !data2->started)
+   if (data2->idle || !data2->started) {
+   static unsigned int cnt = 0;
+   /* This is fairly common, and usually not a bug.  So, print 
errors
+  rarely. */
+   if (((cnt++ & 0x3FF) == 0x3FF) && hwsim_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
+  dst, data2->idle, !data2->started, cnt);
goto out;
+   }
 
/* A 

[PATCH 100/306] mac80211-hwsim: remove dmesg spam about get-survey.

2017-02-23 Thread greearb
From: Ben Greear 

This message just fills up dmesg and/or kernel logs and does
not provide any useful information.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index af53317..b8189b9 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1848,7 +1848,7 @@ static int mac80211_hwsim_get_survey(
 {
struct ieee80211_conf *conf = >conf;
 
-   wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx);
+   /* wiphy_debug(hw->wiphy, "%s (idx=%d)\n", __func__, idx); */
 
if (idx != 0)
return -ENOENT;
-- 
2.4.11



[PATCH 162/306] mac80211-hwsim: add length checks before allocating skb.

2017-02-23 Thread greearb
From: Ben Greear 

Modify the receive-from-user-space logic to do length
and 'is-down' checks before trying to allocate an skb.

And, if we are going to ignore the pkt due to radio idle,
then do not return an error code to user-space.  User-space
cannot reliably know exactly when a radio is idle or not.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 43 +++
 1 file changed, 24 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 48ddf5d..3a96933 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3020,25 +3020,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
frame_data = (void *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
 
-   /* Allocate new skb here */
-   skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL) {
-   if (net_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
-  frame_data_len);
-   goto out;
-   }
-
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
-   if (net_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
-  frame_data_len, IEEE80211_MAX_DATA_LEN);
-   goto out;
-   }
-
-   /* Copy the data */
-   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
-
data2 = get_hwsim_data_ref_from_addr(dst);
 
if (!data2) {
@@ -3067,9 +3048,33 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (((cnt++ & 0x3FF) == 0x3FF) && net_ratelimit())
printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
   dst, data2->idle, !data2->started, cnt);
+   /* Fail silently, no need to bug user-space about this, since 
lots of races
+* in up/down interface, and the user-space app cannot keep 
perfectly
+* in sync.
+*/
+   return 0;
+   }
+
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
+
+
+   /* Allocate new skb here */
+   skb = alloc_skb(frame_data_len, GFP_KERNEL);
+   if (skb == NULL) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
goto out;
}
 
+   /* Copy the data */
+   memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
+
/* A frame is received from user space */
memset(_status, 0, sizeof(rx_status));
if (info->attrs[HWSIM_ATTR_FREQ]) {
-- 
2.4.11



[PATCH 101/306] mac80211-hwsim: Pass rate-ctrl flags and tx-power to user-space

2017-02-23 Thread greearb
From: Ben Greear 

The flags field allows user-space to properly decode what the
rate->idx really means.  The tx-power field is useful as well,
in case user-space is interested in doing something clever with
path-loss calculations.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 21 -
 drivers/net/wireless/mac80211_hwsim.h |  8 
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index b8189b9..853c7ae 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -629,6 +629,9 @@ static const struct nla_policy 
hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
[HWSIM_ATTR_RADIO_NAME] = { .type = NLA_STRING },
[HWSIM_ATTR_NO_VIF] = { .type = NLA_FLAG },
[HWSIM_ATTR_FREQ] = { .type = NLA_U32 },
+   [HWSIM_ATTR_TX_INFO2] = { .type = NLA_UNSPEC,
+ .len = IEEE80211_TX_MAX_RATES *
+sizeof(struct hwsim_tx_rate2)},
 };
 
 static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
@@ -1064,6 +1067,7 @@ static void mac80211_hwsim_tx_frame_nl(struct 
ieee80211_hw *hw,
int i;
struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
uintptr_t cookie;
+   struct hwsim_tx_rate2 tx_attempts2[IEEE80211_TX_MAX_RATES];
 
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
@@ -1115,6 +1119,8 @@ static void mac80211_hwsim_tx_frame_nl(struct 
ieee80211_hw *hw,
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
tx_attempts[i].idx = info->status.rates[i].idx;
tx_attempts[i].count = info->status.rates[i].count;
+   tx_attempts2[i].rc_flags = info->status.rates[i].flags;
+   tx_attempts2[i].power_level = data->power_level;
}
 
if (nla_put(skb, HWSIM_ATTR_TX_INFO,
@@ -1122,6 +1128,11 @@ static void mac80211_hwsim_tx_frame_nl(struct 
ieee80211_hw *hw,
tx_attempts))
goto nla_put_failure;
 
+   if (nla_put(skb, HWSIM_ATTR_TX_INFO2,
+   sizeof(struct hwsim_tx_rate2)*IEEE80211_TX_MAX_RATES,
+   tx_attempts2))
+   goto nla_put_failure;
+
/* We create a cookie to identify this skb */
data->pending_cookie++;
cookie = data->pending_cookie;
@@ -2898,6 +2909,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff 
*skb_2,
struct ieee80211_tx_info *txi;
struct hwsim_tx_rate *tx_attempts;
u64 ret_skb_cookie;
+   struct hwsim_tx_rate2 *tx_attempts2;
struct sk_buff *skb, *tmp;
const u8 *src;
unsigned int hwsim_flags;
@@ -2949,6 +2961,12 @@ static int hwsim_tx_info_frame_received_nl(struct 
sk_buff *skb_2,
tx_attempts = (struct hwsim_tx_rate *)nla_data(
   info->attrs[HWSIM_ATTR_TX_INFO]);
 
+   if (info->attrs[HWSIM_ATTR_TX_INFO2])
+   tx_attempts2 = (struct hwsim_tx_rate2 *)nla_data(
+  info->attrs[HWSIM_ATTR_TX_INFO2]);
+   else
+   tx_attempts2 = NULL;
+
/* now send back TX status */
txi = IEEE80211_SKB_CB(skb);
 
@@ -2957,7 +2975,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff 
*skb_2,
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
txi->status.rates[i].idx = tx_attempts[i].idx;
txi->status.rates[i].count = tx_attempts[i].count;
-   /*txi->status.rates[i].flags = 0;*/
+   if (tx_attempts2)
+   txi->status.rates[i].flags = tx_attempts2[i].rc_flags;
}
 
txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index 73646b1..480c0a7 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -129,6 +129,7 @@ enum {
  * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666
  * @HWSIM_ATTR_NO_VIF:  Do not create vif (wlanX) when creating radio.
  * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
+ * @HWSIM_ATTR_TX_INFO2: hwsim_tx_rate2 array
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -155,6 +156,7 @@ enum {
HWSIM_ATTR_NO_VIF,
HWSIM_ATTR_FREQ,
HWSIM_ATTR_PAD,
+   HWSIM_ATTR_TX_INFO2,
__HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
@@ -177,4 +179,10 @@ struct hwsim_tx_rate {
u8 count;
 } __packed;
 
+/* Auxilary info to allow user-space to better understand the rate */
+struct hwsim_tx_rate2 {
+   u16 rc_flags; /* rate-ctrl flags (see mac80211_rate_control_flags) */
+   s16 power_level;
+} __packed;
+
 #endif /* __MAC80211_HWSIM_H */
-- 
2.4.11



[PATCH 161/306] mac80211-hwsim: Improve logging.

2017-02-23 Thread greearb
From: Ben Greear 

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 13 -
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index aaba126..48ddf5d 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1643,7 +1643,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
 
if (conf->chandef.chan)
wiphy_debug(hw->wiphy,
-   "%s (freq=%d(%d - %d)/%s idle=%d ps=%d smps=%s)\n",
+   "%s (chandef-chan freq=%d(%d - %d)/%s idle=%d ps=%d 
smps=%s)\n",
__func__,
conf->chandef.chan->center_freq,
conf->chandef.center_freq1,
@@ -1654,7 +1654,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
smps_modes[conf->smps_mode]);
else
wiphy_debug(hw->wiphy,
-   "%s (freq=0 idle=%d ps=%d smps=%s)\n",
+   "%s (no-chandef-chan freq=0 idle=%d ps=%d 
smps=%s)\n",
__func__,
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS),
@@ -3061,9 +3061,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
/* check if radio is configured properly */
 
if (data2->idle || !data2->started) {
-   if (net_ratelimit())
-   printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d\n",
-  dst, data2->idle, !data2->started);
+   static unsigned int cnt = 0;
+   /* This is fairly common, and usually not a bug.  So, print 
errors
+  rarely. */
+   if (((cnt++ & 0x3FF) == 0x3FF) && net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d cnt: %d\n",
+  dst, data2->idle, !data2->started, cnt);
goto out;
}
 
-- 
2.4.11



[PATCH 099/306] mac80211-hwsim: notify user-space about channel change.

2017-02-23 Thread greearb
From: Ben Greear 

The goal is to allow the user-space application to properly
filter packets before sending them down to the kernel.  This
should more closely mimic what a real piece of hardware would
do.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 48 +++
 drivers/net/wireless/mac80211_hwsim.h |  6 +
 2 files changed, 54 insertions(+)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index d3bad57..af53317 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1005,6 +1005,52 @@ static int hwsim_unicast_netgroup(struct 
mac80211_hwsim_data *data,
return res;
 }
 
+static void mac80211_hwsim_check_nl_notify(struct mac80211_hwsim_data *data)
+{
+   struct sk_buff *skb;
+   u32 center_freq = 0;
+   u32 _portid;
+   void *msg_head;
+
+   /* wmediumd mode check */
+   _portid = ACCESS_ONCE(data->wmediumd);
+
+   if (!_portid)
+   return;
+
+   skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+   if (skb == NULL)
+   goto err_print;
+
+   msg_head = genlmsg_put(skb, 0, 0, _genl_family, 0,
+  HWSIM_CMD_NOTIFY);
+   if (msg_head == NULL) {
+   printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head, 
notify\n");
+   goto nla_put_failure;
+   }
+
+   if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+   ETH_ALEN, data->addresses[1].addr))
+   goto nla_put_failure;
+
+   if (data->channel)
+   center_freq = data->channel->center_freq;
+
+   if (nla_put_u32(skb, HWSIM_ATTR_FREQ, center_freq))
+   goto nla_put_failure;
+
+   genlmsg_end(skb, msg_head);
+   if (genlmsg_unicast(_net, skb, _portid))
+   goto err_print;
+
+   return;
+
+nla_put_failure:
+   nlmsg_free(skb);
+err_print:
+   printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
+}
+
 static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
   struct sk_buff *my_skb,
   int dst_portid)
@@ -1622,6 +1668,8 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, 
u32 changed)
  HRTIMER_MODE_REL);
}
 
+   mac80211_hwsim_check_nl_notify(data);
+
return 0;
 }
 
diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index 39f2246..73646b1 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -71,6 +71,11 @@ enum hwsim_tx_control_flags {
  * @HWSIM_CMD_DEL_RADIO: destroy a radio, reply is multicasted
  * @HWSIM_CMD_GET_RADIO: fetch information about existing radios, uses:
  * %HWSIM_ATTR_RADIO_ID
+ * @HWSIM_CMD_NOTIFY: notify user-space about driver changes.  This is
+ * designed to help the user-space app better emulate radio hardware.
+ * This command uses:
+ *  %HWSIM_ATTR_FREQ # Notify current operating center frequency.
+ *  %HWSIM_ATTR_ADDR_TRANSMITTER # ID which radio we are notifying about.
  * @__HWSIM_CMD_MAX: enum limit
  */
 enum {
@@ -81,6 +86,7 @@ enum {
HWSIM_CMD_NEW_RADIO,
HWSIM_CMD_DEL_RADIO,
HWSIM_CMD_GET_RADIO,
+   HWSIM_CMD_NOTIFY,
__HWSIM_CMD_MAX,
 };
 #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
-- 
2.4.11



[PATCH 102/306] mac80211-hwsim: enable better rx-status when using netlink.

2017-02-23 Thread greearb
From: Ben Greear 

This allows proper rx-status reporting for packets received
from the netlink api.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 10 ++
 drivers/net/wireless/mac80211_hwsim.h | 18 ++
 2 files changed, 28 insertions(+)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 853c7ae..8d494ac 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3068,6 +3068,16 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
 
+   if (info->attrs[HWSIM_ATTR_RX_INFO]) {
+   struct hwsim_rx_info *r;
+   r = (struct hwsim_rx_info *)nla_data(
+   info->attrs[HWSIM_ATTR_RX_INFO]);
+   rx_status.flag = r->rx_flags;
+   rx_status.vht_flag = r->vht_flags;
+   rx_status.vht_nss = r->vht_nss;
+   rx_status.ampdu_reference = r->ampdu_reference;
+   }
+
memcpy(IEEE80211_SKB_RXCB(skb), _status, sizeof(rx_status));
data2->rx_pkts++;
data2->rx_bytes += skb->len;
diff --git a/drivers/net/wireless/mac80211_hwsim.h 
b/drivers/net/wireless/mac80211_hwsim.h
index 480c0a7..d9dd2f8 100644
--- a/drivers/net/wireless/mac80211_hwsim.h
+++ b/drivers/net/wireless/mac80211_hwsim.h
@@ -130,6 +130,7 @@ enum {
  * @HWSIM_ATTR_NO_VIF:  Do not create vif (wlanX) when creating radio.
  * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received.
  * @HWSIM_ATTR_TX_INFO2: hwsim_tx_rate2 array
+ * @HWSIM_ATTR_RX_INFO: hwsim_rx_info
  * @__HWSIM_ATTR_MAX: enum limit
  */
 
@@ -157,6 +158,7 @@ enum {
HWSIM_ATTR_FREQ,
HWSIM_ATTR_PAD,
HWSIM_ATTR_TX_INFO2,
+   HWSIM_ATTR_RX_INFO,
__HWSIM_ATTR_MAX,
 };
 #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
@@ -185,4 +187,20 @@ struct hwsim_tx_rate2 {
s16 power_level;
 } __packed;
 
+/**
+ * This relates to the ieee80211_rx_status struct in mac80211.h
+ * @rx_flags: %RX_FLAG_* (see  mac80211_rx_flags)
+ * @vht_flags: %RX_VHT_FLAG_*
+ * @vht_nss: number of streams (VHT only)
+ * @ampdu_reference: A-MPDU reference number, must be a different value for
+ * each A-MPDU but the same for each subframe within one A-MPDU
+ */
+struct hwsim_rx_info {
+   u32 rx_flags;
+   u8 vht_flags;
+   u8 vht_nss;
+   u16 unused_pad; /* pad to 32-bits, and space for growth */
+   u32 ampdu_reference;
+} __packed;
+
 #endif /* __MAC80211_HWSIM_H */
-- 
2.4.11



[PATCH 160/306] mac80211-hwsim: add rate-limited debugging for rx-netlink

2017-02-23 Thread greearb
From: Ben Greear 

This makes it easier to understand why wmediumd (or similar)
is getting errors when sending frames to the kernel.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/mac80211_hwsim.c | 42 ++-
 1 file changed, 32 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c 
b/drivers/net/wireless/mac80211_hwsim.c
index 8d494ac..aaba126 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -3010,8 +3010,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
!info->attrs[HWSIM_ATTR_FRAME] ||
!info->attrs[HWSIM_ATTR_RX_RATE] ||
-   !info->attrs[HWSIM_ATTR_SIGNAL])
+   !info->attrs[HWSIM_ATTR_SIGNAL]) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Missing required 
attribute\n");
goto out;
+   }
 
dst = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
@@ -3019,29 +3022,50 @@ static int hwsim_cloned_frame_received_nl(struct 
sk_buff *skb_2,
 
/* Allocate new skb here */
skb = alloc_skb(frame_data_len, GFP_KERNEL);
-   if (skb == NULL)
-   goto err;
+   if (skb == NULL) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: skb alloc failed, len: 
%d\n",
+  frame_data_len);
+   goto out;
+   }
 
-   if (frame_data_len > IEEE80211_MAX_DATA_LEN)
-   goto err;
+   if (frame_data_len > IEEE80211_MAX_DATA_LEN) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: data lenth error: %d  
max: %d\n",
+  frame_data_len, IEEE80211_MAX_DATA_LEN);
+   goto out;
+   }
 
/* Copy the data */
memcpy(skb_put(skb, frame_data_len), frame_data, frame_data_len);
 
data2 = get_hwsim_data_ref_from_addr(dst);
-   if (!data2)
+
+   if (!data2) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: Cannot find radio 
%pM\n",
+  dst);
goto out;
+   }
 
if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
goto out;
 
-   if (info->snd_portid != data2->wmediumd)
+   if (info->snd_portid != data2->wmediumd) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: portid mismatch, 
snd_portid: %d  portid %d\n",
+  info->snd_portid, data2->wmediumd);
goto out;
+   }
 
/* check if radio is configured properly */
 
-   if (data2->idle || !data2->started)
+   if (data2->idle || !data2->started) {
+   if (net_ratelimit())
+   printk(KERN_DEBUG " hwsim rx-nl: radio %pM idle: %d or 
not started: %d\n",
+  dst, data2->idle, !data2->started);
goto out;
+   }
 
/* A frame is received from user space */
memset(_status, 0, sizeof(rx_status));
@@ -3084,8 +3108,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff 
*skb_2,
ieee80211_rx_irqsafe(data2->hw, skb);
 
return 0;
-err:
-   printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 out:
dev_kfree_skb(skb);
return -EINVAL;
-- 
2.4.11



[PATCH v2] mac80211: allow overriding station bandwidth.

2017-02-15 Thread greearb
From: Ben Greear 

This allows one to disable VHT160 (or 80+80) on hardware
that might otherwise try to use it.

Signed-off-by: Ben Greear 
---
v2: Change description

 include/linux/ieee80211.h |  1 +
 net/mac80211/main.c   |  1 +
 net/mac80211/vht.c| 23 +++
 3 files changed, 25 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a80516f..e5dc3a8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1542,6 +1542,7 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ   0x0004
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ  0x0008
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x000C
+#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT2
 #define IEEE80211_VHT_CAP_RXLDPC   0x0010
 #define IEEE80211_VHT_CAP_SHORT_GI_80  0x0020
 #define IEEE80211_VHT_CAP_SHORT_GI_160 0x0040
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ec5587d..1447b47 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -464,6 +464,7 @@ static const struct ieee80211_ht_cap 
mac80211_ht_capa_mod_mask = {
 static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
.vht_cap_info =
cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC |
+   IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK |
IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_RXSTBC_1 |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 720c64c..5684e13 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -56,6 +56,29 @@ void ieee80211_apply_vhtcap_overrides(struct 
ieee80211_sub_if_data *sdata,
__check_vhtcap_disable(sdata, vht_cap,
   IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
 
+   /* Allow disabling 160Mhz or 80+80 */
+   if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
+   cpu_to_le32(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
+   u32 cap, n;
+
+   n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
+   IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   n >>= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+   cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   cap >>= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+
+   if (n < cap) {
+   vht_cap->cap &=
+   ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   vht_cap->cap |=
+   n << IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+
+   /* Cannot do short GI 160 if we cannot do 160 or 80+80 
*/
+   if (n == 0)
+   vht_cap->cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
+   }
+   }
+
/* Allow user to decrease AMPDU length exponent */
if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
-- 
2.4.11



[PATCH] mac80211: allow overriding station bandwidth.

2017-02-14 Thread greearb
From: Ben Greear 

This allows one to disable VHT160 (or 80+80) on hardware
that might otherwise try to use it.  One potential reason
to do this is that at least some 160Mhz/80+80 hardware can
only do 2x2 at 160Mhz, but can do 4x4 at 80Mhz.  And, due to
driver and firmware issues, it may effectively be limitted
to 1x1 at 160Mhz for some NICs.

Signed-off-by: Ben Greear 
---
 include/linux/ieee80211.h |  1 +
 net/mac80211/main.c   |  1 +
 net/mac80211/vht.c| 23 +++
 3 files changed, 25 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a80516f..e5dc3a8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1542,6 +1542,7 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ   0x0004
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ  0x0008
 #define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x000C
+#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT2
 #define IEEE80211_VHT_CAP_RXLDPC   0x0010
 #define IEEE80211_VHT_CAP_SHORT_GI_80  0x0020
 #define IEEE80211_VHT_CAP_SHORT_GI_160 0x0040
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index ec5587d..1447b47 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -464,6 +464,7 @@ static const struct ieee80211_ht_cap 
mac80211_ht_capa_mod_mask = {
 static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = {
.vht_cap_info =
cpu_to_le32(IEEE80211_VHT_CAP_RXLDPC |
+   IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK |
IEEE80211_VHT_CAP_SHORT_GI_80 |
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_RXSTBC_1 |
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index 720c64c..5684e13 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -56,6 +56,29 @@ void ieee80211_apply_vhtcap_overrides(struct 
ieee80211_sub_if_data *sdata,
__check_vhtcap_disable(sdata, vht_cap,
   IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN);
 
+   /* Allow disabling 160Mhz or 80+80 */
+   if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
+   cpu_to_le32(IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
+   u32 cap, n;
+
+   n = le32_to_cpu(sdata->u.mgd.vht_capa.vht_cap_info) &
+   IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   n >>= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+   cap = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   cap >>= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+
+   if (n < cap) {
+   vht_cap->cap &=
+   ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+   vht_cap->cap |=
+   n << IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_SHIFT;
+
+   /* Cannot do short GI 160 if we cannot do 160 or 80+80 
*/
+   if (n == 0)
+   vht_cap->cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
+   }
+   }
+
/* Allow user to decrease AMPDU length exponent */
if (sdata->u.mgd.vht_capa_mask.vht_cap_info &
cpu_to_le32(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK)) {
-- 
2.4.11



[PATCH] ath10k: Configure rxnss_override for 10.4 firmware.

2017-02-10 Thread greearb
From: Ben Greear 

QCA9984 hardware can do 4x4 at 80Mhz, but only 2x2 at 160Mhz.

First, report this to user-space by setting the max-tx-speed
and max-rx-speed vht capabilities.

Second, if the peer rx-speed is configured, and if we
are in 160 or 80+80 mode, and the peer rx-speed matches
the max speed for 2x2 or 1x1 at 160Mhz (long guard interval),
then use that info to set the peer_bw_rxnss_override appropriately.

Without this, a 9984 firmware will not use 2x2 ratesets when
transmitting to peer (it will be stuck at 1x1), because
the firmware would not have configured the rxnss_override.

This could use some testing

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 30 +-
 drivers/net/wireless/ath/ath10k/wmi.c |  7 ++-
 drivers/net/wireless/ath/ath10k/wmi.h |  2 ++
 3 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index b9c9105..0bde1db 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2760,6 +2760,18 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
   sta->addr, arg->peer_max_mpdu, arg->peer_flags,
   arg->peer_vht_rates.rx_max_rate, 
arg->peer_vht_rates.rx_mcs_set,
   arg->peer_vht_rates.tx_max_rate, 
arg->peer_vht_rates.tx_mcs_set);
+
+   if ((arg->peer_vht_rates.rx_max_rate) &&
+   (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
+   if (arg->peer_vht_rates.rx_max_rate == 1560) {
+   /* Must be 2x2 at 160Mhz is all it can do. */
+   arg->peer_bw_rxnss_override = 2;
+   }
+   else if (arg->peer_vht_rates.rx_max_rate == 780) {
+   /* Can only do 1x2 at 160Mhz (Long Guard Interval) */
+   arg->peer_bw_rxnss_override = 1;
+   }
+   }
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
@@ -4899,7 +4911,8 @@ static struct ieee80211_sta_vht_cap 
ath10k_create_vht_cap(struct ath10k *ar)
vht_cap.cap |= val;
}
 
-   if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && 
!(ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+   if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) &&
+   ((ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0)) 
{
vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
}
 
@@ -4917,6 +4930,21 @@ static struct ieee80211_sta_vht_cap 
ath10k_create_vht_cap(struct ath10k *ar)
vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
 
+   /* If we are supporting 160Mhz or 80+80, then the NIC may be able to do 
a restricted NSS
+* for 160 or 80+80 vs what it can do for 80Mhz.  Give user-space a 
clue if that is the
+* case.
+*/
+   if (vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+   /* Something more than 80Mhz at least */
+   if (ar->dev_id == QCA9984_1_0_DEVICE_ID) {
+   /* Can do only 2x2 VHT160 or 80+80.
+* 1560Mbps is 4x4 80Mhz or 2x2 160Mhz, 
long-guard-interval
+*/
+   vht_cap.vht_mcs.rx_highest = 1560;
+   vht_cap.vht_mcs.tx_highest = 1560;
+   }
+   }
+
return vht_cap;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index 38db6be..05ca7f5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -7036,7 +7036,12 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void 
*buf,
struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
 
ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
-   cmd->peer_bw_rxnss_override = 0;
+   if (arg->peer_bw_rxnss_override)
+   cmd->peer_bw_rxnss_override =
+   __cpu_to_le32((arg->peer_bw_rxnss_override - 1) |
+ (1<peer_bw_rxnss_override = 0;
 }
 
 static int
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index 5a71bb4..ccbb1bc 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6173,6 +6173,7 @@ struct wmi_10_2_peer_assoc_complete_cmd_ct {
struct wmi_ct_assoc_overrides overrides;
 } __packed;
 
+#define PEER_BW_RXNSS_OVERRIDE_OFFSET  31
 struct wmi_10_4_peer_assoc_complete_cmd {
struct wmi_10_2_peer_assoc_complete_cmd cmd;
__le32 peer_bw_rxnss_override;
@@ -6201,6 +6202,7 @@ struct wmi_peer_assoc_complete_arg {
u32 peer_vht_caps;
enum wmi_phy_mode 

[PATCH] ath10k: Initialize nbytes to 0

2017-01-05 Thread greearb
From: Ben Greear 

ath10k firmware checks nbytes == 0 as part of determining if DMA
has completed successfully.  To help make this work more often,
have the driver initialize nbytes to zero when freeing the descriptor
slot.

Signed-off-by: Ben Greear 
---

I am not yet sure if this actually fixes a real problem or not...curious
if others think this is an improvement.

 drivers/net/wireless/ath/ath10k/ce.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/ce.c 
b/drivers/net/wireless/ath/ath10k/ce.c
index da9998e..15bc7fb 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -595,6 +595,7 @@ int ath10k_ce_completed_send_next_nolock(struct 
ath10k_ce_pipe *ce_state,
unsigned int nentries_mask = src_ring->nentries_mask;
unsigned int sw_index = src_ring->sw_index;
unsigned int read_index;
+   struct ce_desc *desc;
 
if (src_ring->hw_index == sw_index) {
/*
@@ -624,6 +625,9 @@ int ath10k_ce_completed_send_next_nolock(struct 
ath10k_ce_pipe *ce_state,
 
/* sanity */
src_ring->per_transfer_context[sw_index] = NULL;
+   desc = CE_SRC_RING_TO_DESC(src_ring->base_addr_owner_space,
+  sw_index);
+   desc->nbytes = 0;
 
/* Update sw_index */
sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
-- 
2.4.11



[PATCH] mac80211: Fix invalid 'info' access in xmit-fast.

2016-12-30 Thread greearb
From: Ben Greear 

ieee80211_xmit_fast assigns info from the passed-in
skb, but then later it also checks for skb_shared(skb),
and may create a new skb based on that check.

But, the code did not re-assign 'info', so it pointed into
the old shared skb.  This leads to all sorts of problems,
most obviously crashes since the new skb's info->hw_queue is not
properly initialized.

Bug was seen by sending pktgen packets on a bridge that
had an AP network interface in it.  hw-queue was out of
range, which made it crash like this:

BUG: unable to handle kernel NULL pointer dereference at   (null)
IP: [] ieee80211_tx_frags+0x232/0x4c0 [mac80211]
PGD 0
Oops: 0002 [#1] PREEMPT SMP
CPU: 0 PID: 1512 Comm: kpktgend_0 Tainted: G   O4.7.10+ #24
Hardware name: To be filled by O.E.M. To be filled by O.E.M./ChiefRiver, BIOS 
4.6.5 06/07/2013
task: 8802132f3a00 ti: 8800362ac000 task.ti: 8800362ac000
RIP: 0010:[]  [] 
ieee80211_tx_frags+0x232/0x4c0 [mac80211]
RSP: 0018:8800362afa28  EFLAGS: 00010086
RAX: 8802130a22c0 RBX: 8802130a13a0 RCX: 880035ef2200
RDX: 880035ef2200 RSI: 0292 RDI: 
RBP: 8800362afa90 R08:  R09: 
R10: 0088 R11: 0001 R12: 880035ef2200
R13: 880035dabb90 R14: 8800362afb18 R15: 0cc0
FS:  () GS:88021e20() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2:  CR3: 01e06000 CR4: 001406f0
Stack:
 0292 880035daa880 8802130a0b20 8800d4f01808
 00ff8800362afaa0 8800362afb18 8802130a13c0 88021e20db68
 880035daa880 8800362afb18 880035ef2200 88020f6ca300
Call Trace:
 [] __ieee80211_subif_start_xmit+0xc13/0xc30 [mac80211]
 [] ? find_busiest_group+0x35/0x4a0
 [] ieee80211_subif_start_xmit+0xb/0x10 [mac80211]
 [] dev_hard_start_xmit+0x9b/0x220
 [] sch_direct_xmit+0xd6/0x1a0
 [] __dev_queue_xmit+0x3be/0x6c0
 [] ? finish_task_switch+0x73/0x1f0
 [] dev_queue_xmit+0xd/0x10
 [] br_dev_queue_push_xmit+0x75/0x140 [bridge]
 [] br_forward_finish+0x29/0xa0 [bridge]
 [] ? del_timer_sync+0x43/0x50
 [] __br_deliver+0x62/0x130 [bridge]
 [] ? __getnstimeofday64+0x37/0xd0
 [] ? getnstimeofday64+0x9/0x30
 [] br_deliver+0x56/0x60 [bridge]
 [] br_dev_xmit+0x1c2/0x250 [bridge]
 [] pktgen_thread_worker+0x174c/0x2471 [pktgen]
 [] ? __schedule+0x30a/0x7c0
 [] ? wake_atomic_t_function+0x60/0x60
 [] ? pktgen_rem_all_ifs+0x80/0x80 [pktgen]
 [] kthread+0xc4/0xe0
 [] ret_from_fork+0x1f/0x40
 [] ? kthread_worker_fn+0x180/0x180

Fix this by re-assigning info after creating new one.

Signed-off-by: Ben Greear 
---

This patch is against 4.7.10+

 net/mac80211/tx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0573ab9..3da5f94 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3081,6 +3081,7 @@ static bool ieee80211_xmit_fast(struct 
ieee80211_sub_if_data *sdata,
 
if (!skb)
return true;
+   info = IEEE80211_SKB_CB(skb);
}
 
ieee80211_tx_stats(dev, skb->len + extra_head);
-- 
2.4.11



[PATCH v2] mac80211: fix legacy and invalid rx-rate rpt

2016-12-14 Thread greearb
From: Ben Greear 

This fixes obtaining the rate info via sta_set_sinfo
when the rx rate is invalid (for instance, on IBSS
interface that has received no frames from one of its
peers).

This also fixes a more general issue with rinfo->flags
not being properly initialized for legacy rates.

Signed-off-by: Ben Greear 
---

Patch is against 4.7

 net/mac80211/sta_info.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 01868f9..6d27813e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2057,6 +2057,7 @@ static void sta_stats_decode_rate(struct ieee80211_local 
*local, u16 rate,
u16 brate;
unsigned int shift;
 
+   rinfo->flags = 0;
sband = local->hw.wiphy->bands[(rate >> 4) & 0xf];
brate = sband->bitrates[rate & 0xf].bitrate;
if (rinfo->bw == RATE_INFO_BW_5)
@@ -2072,14 +2073,15 @@ static void sta_stats_decode_rate(struct 
ieee80211_local *local, u16 rate,
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
 }
 
-static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
+static int sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
 {
u16 rate = ACCESS_ONCE(sta_get_last_rx_stats(sta)->last_rate);
-
-   if (rate == STA_STATS_RATE_INVALID)
-   rinfo->flags = 0;
-   else
+   if (rate == STA_STATS_RATE_INVALID) {
+   return -EINVAL;
+   } else {
sta_stats_decode_rate(sta->local, rate, rinfo);
+   return 0;
+   }
 }
 
 static void sta_set_tidstats(struct sta_info *sta,
@@ -2284,8 +2286,8 @@ void sta_set_sinfo(struct sta_info *sta, struct 
station_info *sinfo)
}
 
if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) {
-   sta_set_rate_info_rx(sta, >rxrate);
-   sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+   if (sta_set_rate_info_rx(sta, >rxrate) == 0)
+   sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
}
 
sinfo->filled |= BIT(NL80211_STA_INFO_TID_STATS);
-- 
2.4.11



[PATCH] mac80211: fix rx-rate report when rate is invalid.

2016-12-05 Thread greearb
From: Ben Greear 

This fixes obtaining the rate info via sta_set_sinfo
when the rx rate is invalid (for instance, on IBSS
interface that has received no frames from one of its
peers).

Signed-off-by: Ben Greear 
---
 net/mac80211/sta_info.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 01868f9..868dc88 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2076,10 +2076,12 @@ static void sta_set_rate_info_rx(struct sta_info *sta, 
struct rate_info *rinfo)
 {
u16 rate = ACCESS_ONCE(sta_get_last_rx_stats(sta)->last_rate);
 
-   if (rate == STA_STATS_RATE_INVALID)
-   rinfo->flags = 0;
-   else
+   if (rate == STA_STATS_RATE_INVALID) {
+   rinfo->flags = 0; /* means use legacy rates */
+   rinfo->legacy = 0; /* Initialize legacy rates to known value */
+   } else {
sta_stats_decode_rate(sta->local, rate, rinfo);
+   }
 }
 
 static void sta_set_tidstats(struct sta_info *sta,
-- 
2.4.11



[PATCH v2 1/2] mac80211: Return avg sig, rx, tx values in ethtool stats.

2016-12-05 Thread greearb
From: Ben Greear 

For non-station devices.  This gives at least some useful
summary in some cases (especially when we know AP has only one
station attached, for instance).

Signed-off-by: Ben Greear 
---

v2:  Remove commented out pr_err code, remove trailing i++ that had no effect.

 net/mac80211/ethtool.c | 49 +
 1 file changed, 49 insertions(+)

diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 4e937c1..e7df3d3 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -12,6 +12,25 @@
 #include "ieee80211_i.h"
 #include "sta_info.h"
 #include "driver-ops.h"
+#include 
+
+static inline __s64 mac_div(__s64 n, __u32 base)
+{
+   if (n < 0) {
+   __u64 tmp = -n;
+   do_div(tmp, base);
+   /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
+  n, base, tmp); */
+   return -tmp;
+   }
+   else {
+   __u64 tmp = n;
+   do_div(tmp, base);
+   /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
+  n, base, tmp); */
+   return tmp;
+   }
+}
 
 static int ieee80211_set_ringparam(struct net_device *dev,
   struct ethtool_ringparam *rp)
@@ -128,6 +147,12 @@ static void ieee80211_get_stats(struct net_device *dev,
data[i] = (u8)sinfo.signal_avg;
i++;
} else {
+   int amt_tx = 0;
+   int amt_rx = 0;
+   int amt_sig = 0;
+   s64 tx_accum = 0;
+   s64 rx_accum = 0;
+   s64 sig_accum = 0;
list_for_each_entry(sta, >sta_list, list) {
/* Make sure this station belongs to the proper dev */
if (sta->sdata->dev != dev)
@@ -137,6 +162,30 @@ static void ieee80211_get_stats(struct net_device *dev,
sta_set_sinfo(sta, );
i = 0;
ADD_STA_STATS(sta);
+
+   i++; /* skip sta state */
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
+   tx_accum += 10 *
+   
cfg80211_calculate_bitrate();
+   amt_tx++;
+   data[i] = mac_div(tx_accum, amt_tx);
+   }
+   i++;
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
+   rx_accum += 10 *
+   
cfg80211_calculate_bitrate();
+   amt_rx++;
+   data[i] = mac_div(rx_accum, amt_rx);
+   }
+   i++;
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG)) {
+   sig_accum += sinfo.signal_avg;
+   amt_sig++;
+   data[i] = (mac_div(sig_accum, amt_sig) & 0xFF);
+   }
}
}
 
-- 
2.4.11



[PATCH v2 2/2] mac80211: Show pending txqlen in debugfs.

2016-12-05 Thread greearb
From: Ben Greear 

Could be useful for debugging memory consumption issues,
and perhaps power-save as well.

Signed-off-by: Ben Greear 
---

v2:  Use more appropriate length, add comment to explain
  magic numbers.

 net/mac80211/debugfs.c | 27 +++
 1 file changed, 27 insertions(+)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index b251b2f7..b7a0493 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -162,6 +162,31 @@ static ssize_t hwflags_read(struct file *file, char __user 
*user_buf,
return rv;
 }
 
+static ssize_t misc_read(struct file *file, char __user *user_buf,
+size_t count, loff_t *ppos)
+{
+   struct ieee80211_local *local = file->private_data;
+   /* Max len of each line is 16 characters, plus 9 for 'pending:\n' */
+   size_t bufsz = IEEE80211_MAX_QUEUES * 16 + 9;
+   char *buf = kzalloc(bufsz, GFP_KERNEL);
+   char *pos = buf, *end = buf + bufsz - 1;
+   ssize_t rv;
+   int i;
+   int ln;
+
+   pos += scnprintf(pos, end - pos, "pending:\n");
+
+   for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+   ln = skb_queue_len(>pending[i]);
+   pos += scnprintf(pos, end - pos, "[%i] %d\n",
+i, ln);
+   }
+
+   rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+   kfree(buf);
+   return rv;
+}
+
 static ssize_t queues_read(struct file *file, char __user *user_buf,
   size_t count, loff_t *ppos)
 {
@@ -182,6 +207,7 @@ static ssize_t queues_read(struct file *file, char __user 
*user_buf,
 
 DEBUGFS_READONLY_FILE_OPS(hwflags);
 DEBUGFS_READONLY_FILE_OPS(queues);
+DEBUGFS_READONLY_FILE_OPS(misc);
 
 /* statistics stuff */
 
@@ -250,6 +276,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
+   DEBUGFS_ADD(misc);
 #ifdef CONFIG_PM
DEBUGFS_ADD_MODE(reset, 0200);
 #endif
-- 
2.4.11



[PATCH] ath10k: free host-mem with DMA_BIRECTIONAL flag.

2016-12-05 Thread greearb
From: Ben Greear 

Hopefully this fixes the problem reported by Kalle:

Noticed this in my log, but I don't have time to investigate this in
detail right now:

[  413.795346] IPv6: ADDRCONF(NETDEV_UP): wlan0: link is not ready
[  414.158755] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready
[  477.439659] ath10k_pci :02:00.0: could not get mac80211 beacon
[  481.30] [ cut here ]
[  481.69] WARNING: CPU: 0 PID: 1978 at lib/dma-debug.c:1155 
check_unmap+0x320/0x8e0
[  481.88] ath10k_pci :02:00.0: DMA-API: device driver frees DMA memory 
with different direction [device address=0x2d13] [size=63800 bytes] 
[mapped with DMA_BIDIRECTIONAL] [unmapped with DMA_TO_DEVICE]
[  481.666703] Modules linked in: ctr ccm ath10k_pci(E-) ath10k_core(E) ath(E) 
mac80211(E) cfg80211(E) snd_hda_codec_hdmi snd_hda_codec_idt 
snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep 
snd_pcm snd_seq_midi arc4 snd_rawmidi snd_seq_midi_event snd_seq btusb btintel 
snd_seq_device joydev coret
[  481.671468] CPU: 0 PID: 1978 Comm: rmmod Tainted: GE   
4.9.0-rc7-wt+ #54
[  481.671478] Hardware name: Hewlett-Packard HP ProBook 6540b/1722, BIOS 68CDD 
Ver. F.04 01/27/2010
[  481.671489]  ef49dcec c842ee92 c8b5830e ef49dd34 ef49dd20 c80850f5 c8b5a13c 
ef49dd50
[  481.671560]  07ba c8b5830e 0483 c8461830 c8461830 0483 ef49ddcc 
f34e64b8
[  481.671641]  c8b58360 ef49dd3c c80851bb 0009  ef49dd34 c8b5a13c 
ef49dd50
[  481.671716] Call Trace:
[  481.671731]  [] dump_stack+0x76/0xb4
[  481.671745]  [] __warn+0xe5/0x100
[  481.671757]  [] ? check_unmap+0x320/0x8e0
[  481.671769]  [] ? check_unmap+0x320/0x8e0
[  481.671780]  [] warn_slowpath_fmt+0x3b/0x40
[  481.671791]  [] check_unmap+0x320/0x8e0
[  481.671804]  [] debug_dma_unmap_page+0x84/0xa0
[  481.671835]  [] ath10k_wmi_free_host_mem+0x9a/0xe0 [ath10k_core]
[  481.671861]  [] ath10k_core_destroy+0x50/0x60 [ath10k_core]
[  481.671875]  [] ath10k_pci_remove+0x79/0xa0 [ath10k_pci]
[  481.671889]  [] pci_device_remove+0x38/0xb0
[  481.671901]  [] __device_release_driver+0x7b/0x110
[  481.671913]  [] driver_detach+0x97/0xa0
[  481.671923]  [] bus_remove_driver+0x4b/0xb0
[  481.671934]  [] driver_unregister+0x2a/0x60
[  481.671949]  [] pci_unregister_driver+0x18/0x70
[  481.671965]  [] ath10k_pci_exit+0xd/0x25f [ath10k_pci]
[  481.671979]  [] SyS_delete_module+0xf4/0x180
[  481.671995]  [] ? __might_fault+0x8b/0xa0
[  481.672009]  [] do_fast_syscall_32+0xa0/0x1e0
[  481.672025]  [] sysenter_past_esp+0x45/0x74
[  481.672037] ---[ end trace 3fd23759e17e1622 ]---
[  481.672049] Mapped at:
[  481.672060]  [  481.672072] [] debug_dma_map_page.part.25+0x1c/0xf0
[  481.672083]  [  481.672095] [] debug_dma_map_page+0x99/0xc0
[  481.672106]  [  481.672132] [] ath10k_wmi_alloc_chunk+0x12c/0x1f0 
[ath10k_core]
[  481.672142]  [  481.672168] [] 
ath10k_wmi_event_service_ready_work+0x304/0x540 [ath10k_core]
[  481.672178]  [  481.672190] [] process_one_work+0x1c3/0x670
[  482.137134] ath10k_pci :02:00.0: pci irq msi oper_irq_mode 2 irq_mode 0 
reset_mode 0
[  482.313144] ath10k_pci :02:00.0: Direct firmware load for 
ath10k/pre-cal-pci-:02:00.0.bin failed with error -2
[  482.313274] ath10k_pci :02:00.0: Direct firmware load for 
ath10k/cal-pci-:02:00.0.bin failed with error -2
[  482.313768] ath10k_pci :02:00.0: qca988x hw2.0 target 0x4100016c chip_id 
0x043202ff sub :
[  482.313777] ath10k_pci :02:00.0: kconfig debug 1 debugfs 1 tracing 1 dfs 
0 testmode 1
[  482.313974] ath10k_pci :02:00.0: firmware ver 10.2.4.70.59-2 api 5 
features no-p2p,raw-mode,mfp,allows-mesh-bcast crc32 4159f498
[  482.369858] ath10k_pci :02:00.0: Direct firmware load for 
ath10k/QCA988X/hw2.0/board-2.bin failed with error -2
[  482.370011] ath10k_pci :02:00.0: board_file api 1 bmi_id N/A crc32 
bebc7c08
[  483.596770] ath10k_pci :02:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 cal otp 
max-sta 128 raw 0 hwcrypto 1
[  483.701686] ath: EEPROM regdomain: 0x0
[  483.701706] ath: EEPROM indicates default country code should be used
[  483.701713] ath: doing EEPROM country->regdmn map search
[  483.701721] ath: country maps to regdmn code: 0x3a
[  483.701730] ath: Country alpha2 being used: US
[  483.701737] ath: Regpair used: 0x3a

Reported-by: Kalle Valo 
Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index c748923..0be76e4 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -8473,7 +8473,7 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
dma_unmap_single(ar->dev,
 ar->wmi.mem_chunks[i].paddr,
 

[PATCH 2/2] ath10k: work-around for stale txq in ar->txqs

2016-12-01 Thread greearb
From: Ben Greear 

Due to reasons I do not fully understand, when ath10k firmware
crashes when trying to bring up lots of vdevs, the ar->txqs
may still have references to the txq struct when mac80211 re-adds
the network devices.

The device add logic was re-initializing the list members, but
if they were already in the ar->txqs, then that meant the list
was broken and trying to walk the list would end up in an infinite
loop.

So, check for this particular isue, and remove the reference from
ar->txqs before re-initializing the list-head.  There must be
a cleaner way to do this, but I am not sure exactly what that would
be.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 48 ++-
 drivers/net/wireless/ath/ath10k/wmi.c |  9 +++
 2 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 784cf2b..2f50915 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4190,13 +4190,37 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct 
*work)
}
 }
 
-static void ath10k_mac_txq_init(struct ieee80211_txq *txq)
+static void ath10k_mac_txq_init(struct ath10k *ar, struct ieee80211_txq *txq)
 {
struct ath10k_txq *artxq = (void *)txq->drv_priv;
+   struct ath10k_txq *tmp, *walker;
+   struct ieee80211_txq *txq_tmp;
+   int i = 0;
 
if (!txq)
return;
 
+   spin_lock_bh(>txqs_lock);
+
+   /* Remove from ar->txqs in case it still exists there. */
+   list_for_each_entry_safe(walker, tmp, >txqs, list) {
+   txq_tmp = container_of((void *)walker, struct ieee80211_txq,
+  drv_priv);
+   if ((++i % 1) == 0) {
+   ath10k_err(ar, "txq-init: Checking txq_tmp: %p i: 
%d\n", txq_tmp, i);
+   ath10k_err(ar, "txq-init: txqs: %p walker->list: %p 
w->next: %p  w->prev: %p ar->txqs: %p\n",
+  >txqs, &(walker->list), 
walker->list.next, walker->list.prev, >txqs);
+   }
+
+   if (txq_tmp == txq) {
+   WARN_ON_ONCE(1);
+   ath10k_err(ar, "txq-init: Found txq when it should be 
deleted, txq_tmp: %p  txq: %p\n",
+  txq_tmp, txq);
+   list_del(>list);
+   }
+   }
+   spin_unlock_bh(>txqs_lock);
+
INIT_LIST_HEAD(>list);
 }
 
@@ -4208,6 +4232,7 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, 
struct ieee80211_txq *txq)
struct sk_buff *msdu;
struct ieee80211_txq *txq_tmp;
int msdu_id;
+   int i = 0;
 
if (!txq)
return;
@@ -4220,8 +4245,18 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, 
struct ieee80211_txq *txq)
list_for_each_entry_safe(walker, tmp, >txqs, list) {
txq_tmp = container_of((void *)walker, struct ieee80211_txq,
   drv_priv);
-   if (txq_tmp == txq)
+   if ((++i % 1) == 0) {
+   ath10k_err(ar, "Checking txq_tmp: %p i: %d\n", txq_tmp, 
i);
+   ath10k_err(ar, "txqs: %p walker->list: %p w->next: %p  
w->prev: %p ar->txqs: %p\n",
+  >txqs, &(walker->list), 
walker->list.next, walker->list.prev, >txqs);
+   }
+
+   if (txq_tmp == txq) {
+   WARN_ON_ONCE(1);
+   ath10k_err(ar, "Found txq when it should be deleted, 
txq_tmp: %p  txq: %p\n",
+  txq_tmp, txq);
list_del(>list);
+   }
}
spin_unlock_bh(>txqs_lock);
 
@@ -5255,7 +5290,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
mutex_lock(>conf_mutex);
 
memset(arvif, 0, sizeof(*arvif));
-   ath10k_mac_txq_init(vif->txq);
+   ath10k_mac_txq_init(ar, vif->txq);
 
memset(>bcast_rate, WMI_FIXED_RATE_NONE, 
sizeof(arvif->bcast_rate));
memset(>mcast_rate, WMI_FIXED_RATE_NONE, 
sizeof(arvif->mcast_rate));
@@ -5620,8 +5655,9 @@ static void ath10k_remove_interface(struct ieee80211_hw 
*hw,
kfree(arvif->u.ap.noa_data);
}
 
-   ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i delete (remove 
interface)\n",
-  arvif->vdev_id);
+   ath10k_dbg(ar, ATH10K_DBG_MAC,
+  "mac vdev %i delete (remove interface), vif: %p  arvif: 
%p\n",
+  arvif->vdev_id, vif, arvif);
 
ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
if (ret)
@@ -6437,7 +6473,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
INIT_WORK(>update_wk, ath10k_sta_rc_update_wk);
 
for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
-

[PATCH 1/2] mac80211: do not iterate active interfaces when in re-configure

2016-12-01 Thread greearb
From: Ben Greear <gree...@candelatech.com>

This appears to fix a problem where ath10k firmware would crash,
mac80211 would start re-adding interfaces to the driver, but the
iterate-active-interfaces logic would then try to use the half-built
interfaces.  With a bit of extra debug to catch the problem, the
ath10k crash looks like this:

ath10k_pci :05:00.0: Initializing arvif: 8801ce97e320 on vif: 
8801ce97e1d8

[the print that happens after arvif->ar is assigned is not shown, so code did 
not make it that far before
 the tx-beacon-nowait method was called]

tx-beacon-nowait:  arvif: 8801ce97e320  ar:   (null)
arvif->magic: 0x87560001
[ cut here ]
kernel BUG at 
/home/greearb/git/linux-4.7.dev.y/drivers/net/wireless/ath/ath10k/wmi.c:1781!
invalid opcode:  [#1] PREEMPT SMP KASAN
Modules linked in: nf_conntrack_netlink nf_conntrack nfnetlink nf_defrag_ipv4 
bridge carl9170 mac80211_hwsim ath10k_pci ath10k_core ath5k ath9k ath9k_common 
ath9k_hw ath mac80211 cfg80211 8021q garp mrp stp llc bnep bluetooth fuse 
macvlan pktgen rpcsec_gss_krb5 nfsv4 nfs fscache snd_hda_codec_hdmi coretemp 
hwmon intel_rapl x86_pkg_temp_thermal intel_powerclamp snd_hda_codec_realtek 
snd_hda_codec_generic kvm iTCO_wdt irqbypass iTCO_vendor_support joydev 
snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device 
pcspkr snd_pcm snd_timer shpchp snd i2c_i801 lpc_ich soundcore tpm_tis tpm nfsd 
auth_rpcgss nfs_acl lockd grace sunrpc i915 serio_raw i2c_algo_bit 
drm_kms_helper ata_generic e1000e pata_acpi drm ptp pps_core i2c_core fjes 
video ipv6 [last unloaded: nf_conntrack]
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.7.10+ #15
Hardware name: To be filled by O.E.M. To be filled by O.E.M./ChiefRiver, BIOS 
4.6.5 06/07/2013
task: 8801d4f2 ti: 8801d4f28000 task.ti: 8801d4f28000
RIP: 0010:[]  [] 
ath10k_wmi_tx_beacons_iter+0x28b/0x290 [ath10k_core]
RSP: 0018:8801d6447a98  EFLAGS: 00010293
RAX: 0018 RBX: 8801ce97e1d8 RCX: 
RDX: 0018 RSI: 0003 RDI: ed003ac88f49
RBP: 8801d6447af0 R08: 0003 R09: 
R10: 0001 R11: 0001 R12: 
R13: 8801ce97e320 R14: 8801ce97e378 R15: 8801ce97ca40
FS:  () GS:8801d644() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: 7eff191ef1ab CR3: 0260a000 CR4: 001406e0
Stack:
 11003ac88f59 41b58ab3 a0f4d52a 8801d4f2
 0246 0002 8801ce97e1d8 8801bd5d39b8
 0002 0001 8801ce97ca40 8801d6447b48
Call Trace:
 
 [] __iterate_interfaces+0xfc/0x1d0 [mac80211]
 [] ? ath10k_wmi_cmd_send_nowait+0x260/0x260 [ath10k_core]
 [] ? ath10k_wmi_cmd_send_nowait+0x260/0x260 [ath10k_core]
 [] ieee80211_iterate_active_interfaces_atomic+0x67/0x100 
[mac80211]
 [] ? ieee80211_handle_reconfig_failure+0x140/0x140 [mac80211]
 [] ? ath10k_tpc_config_disp_tables+0x620/0x620 [ath10k_core]
 [] ath10k_wmi_op_ep_tx_credits+0x2b/0x50 [ath10k_core]
 [] ath10k_htc_rx_completion_handler+0x422/0x5c0 [ath10k_core]
 [] ath10k_pci_process_rx_cb+0x37e/0x430 [ath10k_pci]
 [] ? ath10k_htc_build_tx_ctrl_skb+0xc0/0xc0 [ath10k_core]
 [] ? ath10k_pci_rx_post_pipe+0x550/0x550 [ath10k_pci]
 [] ? debug_lockdep_rcu_enabled+0x35/0x40
 [] ? mark_held_locks+0x23/0xc0
 [] ? __local_bh_enable_ip+0x6a/0xd0
 [] ? trace_hardirqs_on_caller+0x18b/0x290
 [] ? trace_hardirqs_on+0xd/0x10
 [] ? __local_bh_enable_ip+0x6a/0xd0
 [] ? _raw_spin_unlock_bh+0x30/0x40
 [] ? ath10k_ce_per_engine_service+0xee/0x100 [ath10k_pci]
 [] ath10k_pci_htt_htc_rx_cb+0x29/0x30 [ath10k_pci]
 [] ath10k_ce_per_engine_service+0xa6/0x100 [ath10k_pci]
 [] ath10k_ce_per_engine_service_any+0xd6/0xf0 [ath10k_pci]
 [] ? ath10k_pci_enable_legacy_irq+0xe0/0xe0 [ath10k_pci]
 [] ath10k_pci_tasklet+0x5f/0xb0 [ath10k_pci]
 [] tasklet_action+0x245/0x2b0
 [] __do_softirq+0x181/0x595
 [] irq_exit+0xbc/0xc0
 [] do_IRQ+0x7c/0x150
 [] common_interrupt+0x8c/0x8c
 
 [] ? trace_hardirqs_on_caller+0x18b/0x290
 [] ? cpuidle_enter_state+0x1ae/0x4b0
 [] ? cpuidle_enter_state+0x1a7/0x4b0
 [] cpuidle_enter+0x12/0x20
 [] call_cpuidle+0x4e/0x90
 [] cpu_startup_entry+0x3f7/0x540
 [] ? default_idle_call+0x50/0x50
 [] ? clockevents_config_and_register+0x5f/0x70
 [] ? setup_APIC_timer+0xfa/0x110
 [] start_secondary+0x253/0x2b0
 [] ? set_cpu_sibling_map+0x920/0x920
Code: 4d 49 e0 8b b3 48 01 00 00 48 c7 c7 a0 ee f3 a0 e8 d9 c2 3f e0 49 81 fd 
3f 1f 00 00 76 0f 49 81 fc 3f 1f 00 00 0f 87 c0 fd ff ff <0f> 0b 0f 0b 90 55 48 
89 e5 41 57 41 56 48 8d 85 58 ff ff ff 41
RIP  [] ath10k_wmi_tx_beacons_iter+0x28b/0x290 [ath10k_core]
 RSP 
---[ end trace 6588464714e5163a ]---

Signed-off-by: Ben Greear <gree...@candelatech.com>
---
 net/mac80211/util.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/util

[PATCH] mac80211: Return avg sig, rx, tx values in ethtool stats.

2016-11-29 Thread greearb
From: Ben Greear 

For non-station devices.  This gives at least some useful
summary in some cases (especially when we know AP has only one
station attached, for instance).

Signed-off-by: Ben Greear 
---

This is against 4.7.10+, applied to 4.4 and 4.9 for me as well.

 net/mac80211/ethtool.c | 56 ++
 1 file changed, 56 insertions(+)

diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 4e937c1..dc6f76f 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -12,6 +12,25 @@
 #include "ieee80211_i.h"
 #include "sta_info.h"
 #include "driver-ops.h"
+#include 
+
+static inline __s64 mac_div(__s64 n, __u32 base)
+{
+   if (n < 0) {
+   __u64 tmp = -n;
+   do_div(tmp, base);
+   /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
+  n, base, tmp); */
+   return -tmp;
+   }
+   else {
+   __u64 tmp = n;
+   do_div(tmp, base);
+   /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
+  n, base, tmp); */
+   return tmp;
+   }
+}
 
 static int ieee80211_set_ringparam(struct net_device *dev,
   struct ethtool_ringparam *rp)
@@ -128,6 +147,12 @@ static void ieee80211_get_stats(struct net_device *dev,
data[i] = (u8)sinfo.signal_avg;
i++;
} else {
+   int amt_tx = 0;
+   int amt_rx = 0;
+   int amt_sig = 0;
+   s64 tx_accum = 0;
+   s64 rx_accum = 0;
+   s64 sig_accum = 0;
list_for_each_entry(sta, >sta_list, list) {
/* Make sure this station belongs to the proper dev */
if (sta->sdata->dev != dev)
@@ -137,6 +162,37 @@ static void ieee80211_get_stats(struct net_device *dev,
sta_set_sinfo(sta, );
i = 0;
ADD_STA_STATS(sta);
+
+   i++; /* skip sta state */
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
+   tx_accum += 10 *
+   
cfg80211_calculate_bitrate();
+   amt_tx++;
+   data[i] = mac_div(tx_accum, amt_tx);
+   }
+   i++;
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
+   rx_accum += 10 *
+   
cfg80211_calculate_bitrate();
+   amt_rx++;
+   data[i] = mac_div(rx_accum, amt_rx);
+   }
+   i++;
+
+   if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG)) {
+   sig_accum += sinfo.signal_avg;
+   amt_sig++;
+   data[i] = (mac_div(sig_accum, amt_sig) & 0xFF);
+   }
+   i++;
+
+   /*pr_err("sta: %p (%s) sig_accum: %ld  amt-sig: %d 
filled: 0x%x:%08x rpt-sig-avg: %d  i: %d  div: %d sinfo.signal_avg: %d\n",
+  sta, sta->sdata->name, (long)(sig_accum), 
amt_sig, (u32)(sinfo.filled >> 32),
+  (u32)(sinfo.filled), (u32)(data[i-1]), i-1, 
(u32)(mac_div(sig_accum, amt_sig)),
+  sinfo.signal_avg);*/
+
}
}
 
-- 
2.4.11



[PATCH 1/2] mac80211: Show pending txqlen in debugfs.

2016-11-29 Thread greearb
From: Ben Greear 

Could be useful for debugging memory consumption issues,
and perhaps power-save as well.

Signed-off-by: Ben Greear 
---

This is against 4.7.10+

 net/mac80211/debugfs.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index b251b2f7..0b49b43 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -162,6 +162,30 @@ static ssize_t hwflags_read(struct file *file, char __user 
*user_buf,
return rv;
 }
 
+static ssize_t misc_read(struct file *file, char __user *user_buf,
+size_t count, loff_t *ppos)
+{
+   struct ieee80211_local *local = file->private_data;
+   size_t bufsz = 1000;
+   char *buf = kzalloc(bufsz, GFP_KERNEL);
+   char *pos = buf, *end = buf + bufsz - 1;
+   ssize_t rv;
+   int i;
+   int ln;
+
+   pos += scnprintf(pos, end - pos, "pending:\n");
+
+   for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+   ln = skb_queue_len(>pending[i]);
+   pos += scnprintf(pos, end - pos, "[%i] %d\n",
+i, ln);
+   }
+
+   rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+   kfree(buf);
+   return rv;
+}
+
 static ssize_t queues_read(struct file *file, char __user *user_buf,
   size_t count, loff_t *ppos)
 {
@@ -182,6 +206,7 @@ static ssize_t queues_read(struct file *file, char __user 
*user_buf,
 
 DEBUGFS_READONLY_FILE_OPS(hwflags);
 DEBUGFS_READONLY_FILE_OPS(queues);
+DEBUGFS_READONLY_FILE_OPS(misc);
 
 /* statistics stuff */
 
@@ -250,6 +275,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(queues);
+   DEBUGFS_ADD(misc);
 #ifdef CONFIG_PM
DEBUGFS_ADD_MODE(reset, 0200);
 #endif
-- 
2.4.11



[PATCH 2/2] mac80211: put upper bound on txqi queue length.

2016-11-29 Thread greearb
From: Ben Greear 

This fixes OOM when using pktgen to drive a wifi station at more than
the station can transmit.  pktgen uses ndo_start_xmit instead of going
through the queue layer, so it will not back off when the queues are
stopped, and would thus cause packets to be added to the txqi->queue
until the system goes OOM and crashes.

Signed-off-by: Ben Greear 
---

This is against 4.7.10+, not sure if it is actually needed in latest kernel.

 net/mac80211/tx.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index fbcb5fc..0573ab9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1293,6 +1293,16 @@ static void ieee80211_drv_tx(struct ieee80211_local 
*local,
goto tx_normal;
 
ac = txq->ac;
+
+   if (atomic_read(>txqs_len[ac]) >=
+   (local->hw.txq_ac_max_pending * 2)) {
+   /* Must be that something is not paying attention to
+* max-pending, like pktgen, so just drop this frame.
+*/
+   ieee80211_free_txskb(>hw, skb);
+   return;
+   }
+
txqi = to_txq_info(txq);
atomic_inc(>txqs_len[ac]);
if (atomic_read(>txqs_len[ac]) >= local->hw.txq_ac_max_pending)
-- 
2.4.11



[PATCH 1/3] ath10k: Ensure there are no stale ar->txqs entries.

2016-08-18 Thread greearb
From: Ben Greear 

I was seeing kernel crashes due to accessing freed memory
while debugging a 9984 firmware that was crashing often.

This patch fixes the crashes.  I am not certain if there
is a better way or not.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 5659ef1..916119c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4172,8 +4172,10 @@ static void ath10k_mac_txq_init(struct ieee80211_txq 
*txq)
 static void ath10k_mac_txq_unref(struct ath10k *ar, struct ieee80211_txq *txq)
 {
struct ath10k_txq *artxq = (void *)txq->drv_priv;
+   struct ath10k_txq *tmp, *walker;
struct ath10k_skb_cb *cb;
struct sk_buff *msdu;
+   struct ieee80211_txq *txq_tmp;
int msdu_id;
 
if (!txq)
@@ -4182,6 +4184,14 @@ static void ath10k_mac_txq_unref(struct ath10k *ar, 
struct ieee80211_txq *txq)
spin_lock_bh(>txqs_lock);
if (!list_empty(>list))
list_del_init(>list);
+
+   /* Remove from ar->txqs in case it still exists there. */
+   list_for_each_entry_safe(walker, tmp, >txqs, list) {
+   txq_tmp = container_of((void *)walker, struct ieee80211_txq,
+  drv_priv);
+   if (txq_tmp == txq)
+   list_del(>list);
+   }
spin_unlock_bh(>txqs_lock);
 
spin_lock_bh(>htt.tx_lock);
-- 
2.4.11



[PATCH 3/3] ath10k: Improve logging message.

2016-08-18 Thread greearb
From: Ben Greear 

Helps to know the sta pointer.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index d96c06e..82bc0da 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -6491,8 +6491,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
 * Existing station deletion.
 */
ath10k_dbg(ar, ATH10K_DBG_MAC,
-  "mac vdev %d peer delete %pM (sta gone)\n",
-  arvif->vdev_id, sta->addr);
+  "mac vdev %d peer delete %pM (sta gone) sta: %p\n",
+  arvif->vdev_id, sta->addr, sta);
 
ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
if (ret)
-- 
2.4.11



[PATCH 2/3] ath10k: Grab rcu_read_lock before the txqs spinlock.

2016-08-18 Thread greearb
From: Ben Greear 

I was seeing some spin-lock hangs in this area of the code,
and it seems more proper to do the rcu-read-lock outside of
the spin lock.  I am not sure how much this matters, however.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 916119c..d96c06e 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4307,8 +4307,8 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar)
int max;
int loop_max = 2000;
 
-   spin_lock_bh(>txqs_lock);
rcu_read_lock();
+   spin_lock_bh(>txqs_lock);
 
last = list_last_entry(>txqs, struct ath10k_txq, list);
while (!list_empty(>txqs)) {
@@ -4342,8 +4342,8 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar)
break;
}
 
-   rcu_read_unlock();
spin_unlock_bh(>txqs_lock);
+   rcu_read_unlock();
 }
 
 //
-- 
2.4.11



[PATCH] mac80211: ensure info->control.vif is set for queued pkts.

2016-06-15 Thread greearb
From: Ben Greear <gree...@candelatech.com>

When driving ath10k with a modified pktgen, we see excessive amounts
of these warnings:

Jun  6 13:47:53 localhost kernel: WARNING: CPU: 1 PID: 1186 at 
/home/greearb/git/linux-4.4.dev.y/net/mac80211/tx.c:3
125 ieee80211_tx_pending+0x9d/0x19e [mac80211]()
Jun  6 13:47:53 localhost kernel: Modules linked in: nf_conntrack_netlink 
nfnetlink nf_conntrack_ipv4 iptable_raw xt
_CT nf_conntrack nf_defrag_ipv4 8021q garp mrp stp llc bnep bluetooth fuse 
macvlan wanlink(O) pktgen ip6table_filter
 ip6_tables ebtable_nat ebtables snd_hda_codec_hdmi snd_hda_codec_realtek 
snd_hda_codec_generic ath10k_pci ath10k_co
re snd_hda_intel snd_hda_codec coretemp hwmon intel_rapl iosf_mbi 
x86_pkg_temp_thermal intel_powerclamp kvm_intel sn
d_hda_core ath iTCO_wdt iTCO_vendor_support mac80211 kvm cfg80211 snd_hwdep 
e1000e snd_seq cdc_acm snd_seq_device sn
d_pcm irqbypass serio_raw pcspkr ptp i2c_i801 pps_core snd_timer snd soundcore 
8250_fintek shpchp fjes lpc_ich tpm_t
is tpm uinput ipv6 i915 i2c_algo_bit drm_kms_helper drm i2c_core video [last 
unloaded: nfnetlink]
Jun  6 13:47:53 localhost kernel: CPU: 1 PID: 1186 Comm: kpktgend_1 Tainted: G  
  W  O4.4.11+ #50
Jun  6 13:47:53 localhost kernel: Hardware name: To be filled by O.E.M. To be 
filled by O.E.M./ChiefRiver, BIOS 4.6.
5 06/07/2013
Jun  6 13:47:53 localhost kernel:  88021e243e68 
81340d35 
Jun  6 13:47:53 localhost kernel: 0009 88021e243ea0 810e
a46e a0b1cb0e
Jun  6 13:47:53 localhost kernel: 880213a41600 880213a406e0 
8800c8ac1700 88021e243ed8
Jun  6 13:47:53 localhost kernel: Call Trace:
Jun  6 13:47:53 localhost kernel:  [] 
dump_stack+0x63/0x7f
Jun  6 13:47:53 localhost kernel: [] 
warn_slowpath_common+0x94/0xad
Jun  6 13:47:53 localhost kernel: [] ? 
ieee80211_tx_pending+0x9d/0x19e [mac80211]
Jun  6 13:47:53 localhost kernel: [] 
warn_slowpath_null+0x15/0x17
Jun  6 13:47:53 localhost kernel: [] 
ieee80211_tx_pending+0x9d/0x19e [mac80211]
Jun  6 13:47:53 localhost kernel: [] tasklet_action+0xae/0xbf
Jun  6 13:47:53 localhost kernel: [] __do_softirq+0x109/0x26d
Jun  6 13:47:53 localhost kernel: [] ? rcu_irq_exit+0x3d/0x40
Jun  6 13:47:53 localhost kernel: [] 
do_softirq_own_stack+0x1c/0x30
Jun  6 13:47:53 localhost kernel:  [] 
do_softirq+0x30/0x3b
Jun  6 13:47:53 localhost kernel: [] 
__local_bh_enable_ip+0x69/0x83
Jun  6 13:47:53 localhost kernel: [] 
pktgen_thread_worker+0x1399/0x1f26 [pktgen]
Jun  6 13:47:53 localhost kernel: [] ? __schedule+0x3c1/0x585
Jun  6 13:47:53 localhost kernel: [] ? finish_wait+0x5d/0x5d
Jun  6 13:47:53 localhost kernel: [] ? 
pktgen_rem_all_ifs+0x6a/0x6a [pktgen]
Jun  6 13:47:53 localhost kernel: [] kthread+0xa0/0xa8
Jun  6 13:47:53 localhost kernel: [] ? 
kthread_parkme+0x1f/0x1f
Jun  6 13:47:53 localhost kernel: [] ret_from_fork+0x3f/0x70
Jun  6 13:47:53 localhost kernel: [] ? 
kthread_parkme+0x1f/0x1f
Jun  6 13:47:53 localhost kernel: ---[ end trace a5fa4429cf1b918b ]---
Jun  6 13:47:53 localhost kernel: [ cut here ]

I think the problem is that the logic that inserts the packet into the pending
queue is not setting the vif in the skb info struct.  This patch appears to
fix the problem.

Signed-off-by: Ben Greear <gree...@candelatech.com>
---

Please review this well, looks like this code has been this way for a long time,
and this was reproduced and tested on a kernel with a lot of wifi, pktgen, and 
ath10k
patches.

 net/mac80211/tx.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4309aff..f4231ab 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1368,6 +1368,8 @@ static bool ieee80211_tx_frags(struct ieee80211_local 
*local,
}
 #endif
 
+   info->control.vif = vif;
+
spin_lock_irqsave(>queue_stop_reason_lock, flags);
if (local->queue_stop_reasons[q] ||
(!txpending && !skb_queue_empty(>pending[q]))) {
@@ -1432,8 +1434,6 @@ static bool ieee80211_tx_frags(struct ieee80211_local 
*local,
}
spin_unlock_irqrestore(>queue_stop_reason_lock, flags);
 
-   info->control.vif = vif;
-
__skb_unlink(skb, skbs);
ieee80211_drv_tx(local, vif, sta, skb);
}
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2] mac80211: add vht cap decode to debugfs.

2016-05-13 Thread greearb
From: Ben Greear 

This makes it a lot easier to understand the capabilities used
by the station:

VHT supported
cap: 0x300819b2
MAX-MPDU-11454
80Mhz
RXLDPC
SHORT-GI-80
TXSTBC
RXSTBC_1
SU-BEAMFORMER-CAPABLE
SU-BEAMFORMEE-CAPABLE
BEAMFORMEE-STS: 0x0
SOUNDING-DIMENSIONS: 0x0
MU-BEAMFORMER-CAPABLE
MPDU-LENGTH-EXPONENT: 0x0
LINK-ADAPTATION-VHT-MRQ-MFB: 0x0
RX-ANTENNA-PATTERN
TX-ANTENNA-PATTERN
RX MCS: fffe
TX MCS: fffe

Signed-off-by: Ben Greear 
---
v2:  Fix usage of the bitfields.
 Update comments to match new format.
 net/mac80211/debugfs_sta.c | 78 --
 1 file changed, 76 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 5d3d2ab..0b7a635 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -292,14 +292,88 @@ STA_OPS(ht_capa);
 static ssize_t sta_vht_capa_read(struct file *file, char __user *userbuf,
 size_t count, loff_t *ppos)
 {
-   char buf[128], *p = buf;
+   char buf[512], *p = buf;
struct sta_info *sta = file->private_data;
struct ieee80211_sta_vht_cap *vhtc = >sta.vht_cap;
 
p += scnprintf(p, sizeof(buf) + buf - p, "VHT %ssupported\n",
vhtc->vht_supported ? "" : "not ");
if (vhtc->vht_supported) {
-   p += scnprintf(p, sizeof(buf)+buf-p, "cap: %#.8x\n", vhtc->cap);
+   p += scnprintf(p, sizeof(buf) + buf - p, "cap: %#.8x\n",
+  vhtc->cap);
+#define PFLAG(a, b)\
+   do {\
+   if (vhtc->cap & IEEE80211_VHT_CAP_ ## a)\
+   p += scnprintf(p, sizeof(buf) + buf - p, \
+  "\t\t%s\n", b);  \
+   } while (0)
+
+   switch (vhtc->cap & 0x3) {
+   case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tMAX-MPDU-3895\n");
+   break;
+   case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tMAX-MPDU-7991\n");
+   break;
+   case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tMAX-MPDU-11454\n");
+   break;
+   default:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tMAX-MPDU-UNKNOWN\n");
+   };
+   switch (vhtc->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+   case 0:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\t80Mhz\n");
+   break;
+   case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\t160Mhz\n");
+   break;
+   case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\t80+80Mhz\n");
+   break;
+   default:
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tUNKNOWN-MHZ: 0x%x\n",
+  (vhtc->cap >> 2) & 0x3);
+   };
+   PFLAG(RXLDPC, "RXLDPC");
+   PFLAG(SHORT_GI_80, "SHORT-GI-80");
+   PFLAG(SHORT_GI_160, "SHORT-GI-160");
+   PFLAG(TXSTBC, "TXSTBC");
+   p += scnprintf(p, sizeof(buf) + buf - p,
+  "\t\tRXSTBC_%d\n", (vhtc->cap >> 8) & 0x7);
+   PFLAG(SU_BEAMFORMER_CAPABLE, "SU-BEAMFORMER-CAPABLE");
+   PFLAG(SU_BEAMFORMEE_CAPABLE, "SU-BEAMFORMEE-CAPABLE");
+   p += scnprintf(p, sizeof(buf) + buf - p,
+   "\t\tBEAMFORMEE-STS: 0x%x\n",
+   (vhtc->cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK) >>
+   IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
+   p += scnprintf(p, sizeof(buf) + buf - p,
+   "\t\tSOUNDING-DIMENSIONS: 0x%x\n",
+   (vhtc->cap & IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK)
+   >> 

[PATCH] ath9k: Support 4.9Ghz channels on AR9580 adapter.

2016-05-12 Thread greearb
From: Ben Greear 

NOTE:  These channels must not be used in most regulatory
domains unless you have a license from the FCC or similar!

A proper regulatory database is also required to actually use
these channels.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath9k/ath9k.h   |  2 +-
 drivers/net/wireless/ath/ath9k/common-init.c | 42 ++--
 drivers/net/wireless/ath/ath9k/hw.h  |  4 +--
 3 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h 
b/drivers/net/wireless/ath/ath9k/ath9k.h
index d78bb10..0429bd5 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -958,7 +958,7 @@ struct ath_softc {
struct device *dev;
 
struct survey_info *cur_survey;
-   struct survey_info survey[ATH9K_NUM_CHANNELS];
+   struct survey_info survey[ATH9K_MAX_NUM_CHANNELS];
 
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c 
b/drivers/net/wireless/ath/ath9k/common-init.c
index a006c14..2bff831 100644
--- a/drivers/net/wireless/ath/ath9k/common-init.c
+++ b/drivers/net/wireless/ath/ath9k/common-init.c
@@ -86,6 +86,20 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] 
= {
CHAN5G(5785, 35), /* Channel 157 */
CHAN5G(5805, 36), /* Channel 161 */
CHAN5G(5825, 37), /* Channel 165 */
+
+   /* 4.9Ghz channels, public safety channels, license is required in US
+* and most other regulatory domains!
+*/
+   CHAN5G(4915, 38), /* Channel 183 */
+   CHAN5G(4920, 39), /* Channel 184 */
+   CHAN5G(4925, 40), /* Channel 185 */
+   CHAN5G(4935, 41), /* Channel 187 */
+   CHAN5G(4940, 42), /* Channel 188 */
+   CHAN5G(4945, 43), /* Channel 189 */
+   CHAN5G(4960, 44), /* Channel 192 */
+   CHAN5G(4970, 45), /* Channel 194 */
+   CHAN5G(4980, 46), /* Channel 196 */
+#define ATH9K_NUM_49GHZ_CHANNELS 9
 };
 
 /* Atheros hardware rate code addition for short premble */
@@ -122,14 +136,28 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
 IEEE80211_RATE_SUPPORTS_10MHZ)),
 };
 
+static bool ath9k_49ghz_capable(struct ath_hw* ah)
+{
+   /* Seems AR9580 supports 4.9ghz, at least. */
+   switch (ah->hw_version.devid) {
+   case AR9300_DEVID_AR9580:
+   return true;
+   }
+   return false;
+}
+
+
 int ath9k_cmn_init_channels_rates(struct ath_common *common)
 {
struct ath_hw *ah = (struct ath_hw *)common->ah;
void *channels;
+   int num_5ghz_chan = ARRAY_SIZE(ath9k_5ghz_chantable);
+   if (!ath9k_49ghz_capable(ah))
+   num_5ghz_chan -= ATH9K_NUM_49GHZ_CHANNELS;
 
BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
-ARRAY_SIZE(ath9k_5ghz_chantable) !=
-ATH9K_NUM_CHANNELS);
+ARRAY_SIZE(ath9k_5ghz_chantable) >
+ATH9K_MAX_NUM_CHANNELS);
 
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
channels = devm_kzalloc(ah->dev,
@@ -149,17 +177,15 @@ int ath9k_cmn_init_channels_rates(struct ath_common 
*common)
}
 
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
-   channels = devm_kzalloc(ah->dev,
-   sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
+   int ch_sz = num_5ghz_chan * sizeof(ath9k_5ghz_chantable[0]);
+   channels = devm_kzalloc(ah->dev, ch_sz, GFP_KERNEL);
if (!channels)
return -ENOMEM;
 
-   memcpy(channels, ath9k_5ghz_chantable,
-  sizeof(ath9k_5ghz_chantable));
+   memcpy(channels, ath9k_5ghz_chantable, ch_sz);
common->sbands[IEEE80211_BAND_5GHZ].channels = channels;
common->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
-   common->sbands[IEEE80211_BAND_5GHZ].n_channels =
-   ARRAY_SIZE(ath9k_5ghz_chantable);
+   common->sbands[IEEE80211_BAND_5GHZ].n_channels = num_5ghz_chan;
common->sbands[IEEE80211_BAND_5GHZ].bitrates =
ath9k_legacy_rates + 4;
common->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
diff --git a/drivers/net/wireless/ath/ath9k/hw.h 
b/drivers/net/wireless/ath/ath9k/hw.h
index 831a544..eaf8d2d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -73,7 +73,7 @@
 
 #define ATH9K_RSSI_BAD -128
 
-#define ATH9K_NUM_CHANNELS 38
+#define ATH9K_MAX_NUM_CHANNELS 47
 
 /* Register read/write primitives */
 #define REG_WRITE(_ah, _reg, _val) \
@@ -776,7 +776,7 @@ struct ath_hw {
struct ath9k_hw_version hw_version;
struct ath9k_ops_config config;
struct ath9k_hw_capabilities caps;
-   struct 

[PATCH v2 08/21] ath10k: make firmware text debug messages more verbose.

2016-05-11 Thread greearb
From: Ben Greear 

There are not many of these messages producted by the
firmware, but they are generally fairly useful, so print
them at info level.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index 1758b4a..d9e4b77 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4050,7 +4050,7 @@ void ath10k_wmi_event_debug_print(struct ath10k *ar, 
struct sk_buff *skb)
/* the last byte is always reserved for the null character */
buf[i] = '\0';
 
-   ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
+   ath10k_info(ar, "wmi print '%s'\n", buf);
 }
 
 void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 10/21] ath10k: support logging ath10k_info as KERN_DEBUG

2016-05-11 Thread greearb
From: Ben Greear 

Helps keep messages off of (serial) console when
that is desired.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 5 -
 drivers/net/wireless/ath/ath10k/debug.h | 6 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 97de9f37..76b5163 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -139,7 +139,10 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
 
va_start(args, fmt);
vaf.va = 
-   dev_info(ar->dev, "%pV", );
+   if (ath10k_debug_mask & ATH10K_DBG_INFO_AS_DBG)
+   dev_printk(KERN_DEBUG, ar->dev, "%pV", );
+   else
+   dev_info(ar->dev, "%pV", );
trace_ath10k_log_info(ar, );
va_end(args);
 }
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 641fce1..070f1c6 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -21,6 +21,10 @@
 #include 
 #include "trace.h"
 
+/**
+ * ATH10K_DBG_INFO_AS_DBG: use dev_dbg instead of dev_info
+ *   for ath10k_info messages
+ */
 enum ath10k_debug_mask {
ATH10K_DBG_PCI  = 0x0001,
ATH10K_DBG_WMI  = 0x0002,
@@ -38,6 +42,8 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT= 0x2000,
ATH10K_DBG_PCI_PS   = 0x4000,
ATH10K_DBG_AHB  = 0x8000,
+
+   ATH10K_DBG_INFO_AS_DBG  = 0x4000,
ATH10K_DBG_FW   = 0x8000,
ATH10K_DBG_ANY  = 0x,
 };
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 20/21] ath10k: read firmware crash over ioread32 if CE fails.

2016-05-11 Thread greearb
From: Ben Greear 

This might work around problem where sometimes host cannot
access firmware crash over normal CE transport.

Requires CT firmware with matching logic in it's assert
handler (-13 and higher releases).

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/hw.h  |  5 
 drivers/net/wireless/ath/ath10k/pci.c | 56 ++-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index d3f37d5..5ff1fac 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -603,6 +603,7 @@ enum ath10k_hw_4addr_pad {
 #define PCIE_INTR_ENABLE_ADDRESS   0x0008
 #define PCIE_INTR_CAUSE_ADDRESS0x000c
 #define PCIE_INTR_CLR_ADDRESS  ar->regs->pcie_intr_clr_address
+#define SCRATCH_2_ADDRESS   0x002c
 #define SCRATCH_3_ADDRESS  ar->regs->scratch_3_address
 #define CPU_INTR_ADDRESS   0x0010
 
@@ -614,6 +615,10 @@ enum ath10k_hw_4addr_pad {
 #define FW_IND_INITIALIZED 2
 #define FW_IND_HOST_READY  0x8000
 
+/* CT firmware only */
+#define FW_IND_SCRATCH2_WR  (1<<14) /* scratch2 has data written to it */
+#define FW_IND_SCRATCH2_RD  (1<<15) /* scratch2 has been read (by host) */
+
 /* HOST_REG interrupt from firmware */
 #define PCIE_INTR_FIRMWARE_MASK
ar->regs->pcie_intr_fw_mask
 #define PCIE_INTR_CE_MASK_ALL  ar->regs->pcie_intr_ce_mask_all
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 2adc459..330c150 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1507,6 +1507,54 @@ static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
 hi_err_stack);
 }
 
+/* Only CT firmware can do this.  Attempt to read crash dump over pci
+ * registers since normal CE transport is not working.
+ */
+static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
+ __le32 *reg_dump_values,
+ int len)
+{
+   u32 val;
+   int i;
+   int q;
+#define MAX_SPIN_TRIES 100
+
+   if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ ar->running_fw->fw_file.fw_features)) {
+   return -EINVAL;
+   }
+
+   for (i = 0; i

[PATCH v2 17/21] ath10k: Enable detecting failure to install key in firmware (CT).

2016-05-11 Thread greearb
From: Ben Greear 

CT firmware has been modified so that it will always return
a response message when user requests to add a key, even if
the key could not actually be added.  Upstream firmware may
assert or just not respond in a failure case.

This change should be compatible with non CT firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h   |  1 +
 drivers/net/wireless/ath/ath10k/htt.h|  7 +--
 drivers/net/wireless/ath/ath10k/htt_rx.c | 20 +---
 drivers/net/wireless/ath/ath10k/mac.c|  3 ++-
 4 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index f9e3b20..fda66bf 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -848,6 +848,7 @@ struct ath10k {
unsigned int filter_flags;
unsigned long dev_flags;
bool dfs_block_radar_events;
+   int install_key_rv; /* Store error code from key-install */
 
/* protected by conf_mutex */
bool radar_enabled;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h 
b/drivers/net/wireless/ath/ath10k/htt.h
index 911c535..c50b343 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -702,8 +702,9 @@ enum htt_security_types {
 };
 
 enum htt_security_flags {
-#define HTT_SECURITY_TYPE_MASK 0x7F
+#define HTT_SECURITY_TYPE_MASK 0x3F
 #define HTT_SECURITY_TYPE_LSB  0
+   HTT_SECURITY_IS_FAILURE = 1 << 6, /* CT firmware only */
HTT_SECURITY_IS_UNICAST = 1 << 7
 };
 
@@ -712,7 +713,9 @@ struct htt_security_indication {
/* dont use bitfields; undefined behaviour */
u8 flags; /* %htt_security_flags */
struct {
-   u8 security_type:7, /* %htt_security_types */
+   u8 security_type:6, /* %htt_security_types */
+  is_failure:1, /* does this response indicate failure
+   (CT Firmware) */
   is_unicast:1;
} __packed;
} __packed;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 47da904..02b5417 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -2307,9 +2307,23 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, 
struct sk_buff *skb)
 
ath10k_dbg(ar, ATH10K_DBG_HTT,
   "sec ind peer_id %d unicast %d type %d\n",
- __le16_to_cpu(ev->peer_id),
- !!(ev->flags & HTT_SECURITY_IS_UNICAST),
- MS(ev->flags, HTT_SECURITY_TYPE));
+  __le16_to_cpu(ev->peer_id),
+  !!(ev->flags & HTT_SECURITY_IS_UNICAST),
+  MS(ev->flags, HTT_SECURITY_TYPE));
+
+   /* CT firmware adds way to determine failure of key set, without
+* just timing things out.  Indication of failure is determined
+* by the 6th bit of the security-type being set.
+*/
+   if (ev->flags & HTT_SECURITY_IS_FAILURE) {
+   ath10k_warn(ar, "Firmware failed to set security key, 
peer_id: %d unicast %d type %d\n",
+   __le16_to_cpu(ev->peer_id),
+   !!(ev->flags & HTT_SECURITY_IS_UNICAST),
+   MS(ev->flags, HTT_SECURITY_TYPE));
+   ar->install_key_rv = -EINVAL;
+   } else {
+   ar->install_key_rv = 0;
+   }
complete(>install_key_done);
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 2169337..373f2ee 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -255,7 +255,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
if (time_left == 0)
return -ETIMEDOUT;
 
-   return 0;
+   ret = ar->install_key_rv;
+   return ret;
 }
 
 static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 03/21] ath10k: Allow changing ath10k debug mask at runtime.

2016-05-11 Thread greearb
From: Ben Greear 

Using debugfs.  More convenient than module options
in some cases.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 62 +
 1 file changed, 62 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index e251155..d552a4a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -870,6 +870,65 @@ static const struct file_operations fops_reg_addr = {
.llseek = default_llseek,
 };
 
+static ssize_t ath10k_read_debug_level(struct file *file,
+  char __user *user_buf,
+  size_t count, loff_t *ppos)
+{
+   int sz;
+   const char buf[] =
+   "To change debug level, set value adding up desired flags:\n"
+   "PCI:0x1\n"
+   "WMI:0x2\n"
+   "HTC:0x4\n"
+   "HTT:0x8\n"
+   "MAC:   0x10\n"
+   "BOOT:  0x20\n"
+   "PCI-DUMP:  0x40\n"
+   "HTT-DUMP:  0x80\n"
+   "MGMT: 0x100\n"
+   "DATA: 0x200\n"
+   "BMI:  0x400\n"
+   "REGULATORY:   0x800\n"
+   "TESTMODE:0x1000\n"
+   "INFO-AS-DBG: 0x4000\n"
+   "FW:  0x8000\n"
+   "ALL: 0x\n";
+   char wbuf[sizeof(buf) + 60];
+   sz = snprintf(wbuf, sizeof(wbuf), "Current debug level: 0x%x\n\n%s",
+ ath10k_debug_mask, buf);
+   wbuf[sizeof(wbuf) - 1] = 0;
+
+   return simple_read_from_buffer(user_buf, count, ppos, wbuf, sz);
+}
+
+/* Set logging level.
+ */
+static ssize_t ath10k_write_debug_level(struct file *file,
+   const char __user *user_buf,
+   size_t count, loff_t *ppos)
+{
+   struct ath10k *ar = file->private_data;
+   int ret;
+   unsigned long mask;
+
+   ret = kstrtoul_from_user(user_buf, count, 0, );
+   if (ret)
+   return ret;
+
+   ath10k_warn(ar, "Setting debug-mask to: 0x%lx  old: 0x%x\n",
+   mask, ath10k_debug_mask);
+   ath10k_debug_mask = mask;
+   return count;
+}
+
+static const struct file_operations fops_debug_level = {
+   .read = ath10k_read_debug_level,
+   .write = ath10k_write_debug_level,
+   .open = simple_open,
+   .owner = THIS_MODULE,
+   .llseek = default_llseek,
+};
+
 static ssize_t ath10k_reg_value_read(struct file *file,
 char __user *user_buf,
 size_t count, loff_t *ppos)
@@ -2375,6 +2434,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("mem_value", S_IRUSR | S_IWUSR,
ar->debug.debugfs_phy, ar, _mem_value);
 
+   debugfs_create_file("debug_level", S_IRUSR, ar->debug.debugfs_phy,
+   ar, _debug_level);
+
debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
ar, _chip_id);
 
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 01/21] ath10k: Fix crash related to printing features.

2016-05-11 Thread greearb
From: Ben Greear 

This looks like a regression from
c4cdf753 (move fw_features to struct ath10k_fw_file)

Signed-off-by:  Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index e94cb87..b7318b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1078,7 +1078,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
}
 
ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
-   ar->running_fw->fw_file.fw_features,
+   fw_file->fw_features,
sizeof(fw_file->fw_features));
break;
case ATH10K_FW_IE_FW_IMAGE:
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 18/21] ath10k: Note limitation on beaconing vdevs.

2016-05-11 Thread greearb
From: Ben Greear 

This only pertains to CT firmware, as standard firmware
can't do anywhere near this many vdevs anyway.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 373f2ee..f1bfb3a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1343,6 +1343,22 @@ static int ath10k_vdev_start_restart(struct ath10k_vif 
*arvif,
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
 
+   /* CT Firmware can support 32+ VDEVS, but can only support
+* beacon-ing devs with dev ids 0 - 31 due to firmware limitations.
+* Create VAPs first and all should be well...likely most people
+* won't ever hit this anyway, but some day the vdev ID allocation
+* could be made smarter to make it more likely to work no matter the
+* order the vdevs are created. --Ben
+*/
+   if ((arvif->vdev_type == WMI_VDEV_TYPE_AP) ||
+   (arvif->vdev_type == WMI_VDEV_TYPE_IBSS)) {
+   if (arg.vdev_id > 31) {
+   ath10k_warn(ar, "failed to start vdev %i  Beaconing 
VIFS must have IDs <= 31 to work-around firmware limitations.\n",
+   arg.vdev_id);
+   return -EINVAL;
+   }
+   }
+
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
arg.ssid_len = arvif->u.ap.ssid_len;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 16/21] ath10k: Support 32+ stations.

2016-05-11 Thread greearb
From: Ben Greear 

Support up to 32 stations when using CT firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 14 +++
 drivers/net/wireless/ath/ath10k/hw.h   |  6 +
 drivers/net/wireless/ath/ath10k/mac.c  | 43 ++
 drivers/net/wireless/ath/ath10k/wmi.c  | 16 ++---
 4 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 49c85c3..3869edd 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1567,6 +1567,20 @@ static int ath10k_core_init_firmware_features(struct 
ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+fw_file->fw_features)) {
+   ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
+   ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+   ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
+   } else {
+   ar->max_num_peers = TARGET_10X_NUM_PEERS;
+   ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+   ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
+   }
+   ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+   ar->fw_stats_req_mask = WMI_STAT_PEER;
+   ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
+   break;
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
if (ath10k_peer_stats_enabled(ar)) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index 7b80e29..d3f37d5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -370,6 +370,12 @@ enum ath10k_hw_4addr_pad {
 (TARGET_10X_NUM_VDEVS))
 #define TARGET_10X_TX_STATS_NUM_PEERS  
((TARGET_10X_TX_STATS_NUM_STATIONS) + \
 (TARGET_10X_NUM_VDEVS))
+
+/* Over-rides for Candela Technologies firmware */
+#define TARGET_10X_NUM_VDEVS_CT32
+#define TARGET_10X_NUM_PEERS_CT(32 + 
(TARGET_10X_NUM_VDEVS_CT))
+#define TARGET_10X_AST_SKID_LIMIT_CT   (TARGET_10X_NUM_PEERS_CT * 
TARGET_10X_NUM_PEER_AST)
+
 #define TARGET_10X_NUM_OFFLOAD_PEERS   0
 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS0
 #define TARGET_10X_NUM_PEER_KEYS   2
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 42cac32..2169337 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7451,6 +7451,22 @@ static const struct ieee80211_iface_limit 
ath10k_10x_if_limits[] = {
},
 };
 
+static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+   {
+   .max= TARGET_10X_NUM_VDEVS_CT,
+   .types  = BIT(NL80211_IFTYPE_STATION)
+   | BIT(NL80211_IFTYPE_P2P_CLIENT)
+   },
+   {
+   .max= 3,
+   .types  = BIT(NL80211_IFTYPE_P2P_GO)
+   },
+   {
+   .max= 7,
+   .types  = BIT(NL80211_IFTYPE_AP)
+   },
+};
+
 static const struct ieee80211_iface_combination ath10k_if_comb[] = {
{
.limits = ath10k_if_limits,
@@ -7531,6 +7547,22 @@ static const struct ieee80211_iface_limit 
ath10k_tlv_if_limit_ibss[] = {
},
 };
 
+static const struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
+   {
+   .limits = ath10k_10x_ct_if_limits,
+   .n_limits = ARRAY_SIZE(ath10k_10x_ct_if_limits),
+   .max_interfaces = TARGET_10X_NUM_VDEVS_CT,
+   .num_different_channels = 1,
+   .beacon_int_infra_match = true,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+   .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+   BIT(NL80211_CHAN_WIDTH_20) |
+   BIT(NL80211_CHAN_WIDTH_40) |
+   BIT(NL80211_CHAN_WIDTH_80),
+#endif
+   },
+};
+
 /* FIXME: This is not thouroughly tested. These combinations may over- or
  * underestimate hw/fw capabilities.
  */
@@ -7808,6 +7840,17 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ar->normal_mode_fw.fw_file.fw_features)) {
+   ar->hw->wiphy->iface_combinations = 
ath10k_10x_ct_if_comb;
+   

[PATCH v2 07/21] ath10k: save firmware RAM and ROM BSS sections on crash

2016-05-11 Thread greearb
From: Ben Greear 

This can be used to get a useful back trace out of a firmware
crash that involves an interrupt handler.  For instance, a
null-pointer-exception would be this kind of trace.  A user-space
tool can read the debugfs file and decode things as wished.

This requires a packaged firmware with a new IE to describe the
BSS section starts and length.

Signed-off-by: Ben Greear 
Signed-off-by: Kalle Valo 
---
 drivers/net/wireless/ath/ath10k/core.c  | 48 +
 drivers/net/wireless/ath/ath10k/core.h  | 14 +
 drivers/net/wireless/ath/ath10k/debug.c | 40 +++-
 drivers/net/wireless/ath/ath10k/hw.h|  2 ++
 drivers/net/wireless/ath/ath10k/pci.c   | 54 +
 5 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index b7318b8..3f1786c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -922,6 +922,13 @@ err:
return ret;
 }
 
+struct ath10k_bss_rom_ie {
+   __le32 ram_addr;
+   __le32 ram_len;
+   __le32 rom_addr;
+   __le32 rom_len;
+} __packed;
+
 static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
 size_t name_len)
 {
@@ -983,6 +990,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
struct ath10k_fw_ie *hdr;
const u8 *data;
__le32 *timestamp, *version;
+   struct ath10k_bss_rom_ie *bss;
 
/* first fetch the firmware file (firmware-*.bin) */
fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
@@ -1100,6 +1108,12 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
 
break;
case ATH10K_FW_IE_WMI_OP_VERSION:
+   /* Upstream stole the ID CT firmware was using, so add
+* hack-around to deal with backwards-compat. --Ben
+*/
+   if (ie_len >= sizeof(*bss))
+   goto fw_ie_bss_info_ct;
+
if (ie_len != sizeof(u32))
break;
 
@@ -1128,6 +1142,40 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
fw_file->codeswap_data = data;
fw_file->codeswap_len = ie_len;
break;
+   case ATH10K_FW_IE_BSS_INFO_CT:
+fw_ie_bss_info_ct:
+   if (ie_len < sizeof(*bss)) {
+   ath10k_warn(ar, "invalid ie len for bss-info 
(%zd)\n",
+   ie_len);
+   break;
+   }
+   bss = (struct ath10k_bss_rom_ie *)(data);
+
+   fw_file->ram_bss_addr = le32_to_cpu(bss->ram_addr);
+   fw_file->ram_bss_len = le32_to_cpu(bss->ram_len);
+   ath10k_dbg(ar, ATH10K_DBG_BOOT,
+  "found RAM BSS addr 0x%x length %d\n",
+  fw_file->ram_bss_addr, fw_file->ram_bss_len);
+
+   if (fw_file->ram_bss_len > ATH10K_RAM_BSS_BUF_LEN) {
+   ath10k_warn(ar, "too long firmware RAM BSS 
length: %d\n",
+   fw_file->ram_bss_len);
+   fw_file->ram_bss_len = 0;
+   }
+
+   fw_file->rom_bss_addr = le32_to_cpu(bss->rom_addr);
+   fw_file->rom_bss_len = le32_to_cpu(bss->rom_len);
+   ath10k_dbg(ar, ATH10K_DBG_BOOT,
+  "found ROM BSS addr 0x%x length %d\n",
+  fw_file->rom_bss_addr, fw_file->rom_bss_len);
+
+   if (fw_file->rom_bss_len > ATH10K_ROM_BSS_BUF_LEN) {
+   ath10k_warn(ar, "too long firmware ROM BSS 
length: %d\n",
+   fw_file->rom_bss_len);
+   fw_file->rom_bss_len = 0;
+   }
+
+   break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 644d077..6aa7a14 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -420,6 +420,10 @@ struct ath10k_dbglog_entry_storage {
 #define DBGLOG_NUM_ARGS_MASK 0xFC00 /* Bit 26-31 */
 #define DBGLOG_NUM_ARGS_MAX  5 /* firmware tool chain limit */
 
+/* estimated values, hopefully these are 

[PATCH v2 19/21] ath10k: Enable adhoc mode for CT firmware.

2016-05-11 Thread greearb
From: Ben Greear 

CT firmware can support IBSS mode, so allow users to configure this.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index f1bfb3a..3fc9006 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7482,6 +7482,10 @@ static const struct ieee80211_iface_limit 
ath10k_10x_ct_if_limits[] = {
.max= 7,
.types  = BIT(NL80211_IFTYPE_AP)
},
+   {
+   .max= 1,
+   .types  = BIT(NL80211_IFTYPE_ADHOC)
+   },
 };
 
 static const struct ieee80211_iface_combination ath10k_if_comb[] = {
@@ -7862,6 +7866,7 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->iface_combinations = 
ath10k_10x_ct_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_10x_ct_if_comb);
+   ar->hw->wiphy->interface_modes |= 
BIT(NL80211_IFTYPE_ADHOC);
} else {
ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
ar->hw->wiphy->n_iface_combinations =
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 05/21] ath10k: save firmware debug log messages.

2016-05-11 Thread greearb
From: Ben Greear 

They may be dumped through the firmware dump debugfs
file.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h  | 18 ++
 drivers/net/wireless/ath/ath10k/debug.c | 97 +++-
 drivers/net/wireless/ath/ath10k/debug.h |  6 ++
 drivers/net/wireless/ath/ath10k/hw.h| 21 +++
 drivers/net/wireless/ath/ath10k/pci.c   | 99 +
 drivers/net/wireless/ath/ath10k/wmi.c   | 13 +
 drivers/net/wireless/ath/ath10k/wmi.h   |  6 ++
 7 files changed, 258 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 1379054..7f9f460 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -404,6 +404,22 @@ struct ath10k_vif_iter {
struct ath10k_vif *arvif;
 };
 
+/* This will store at least the last 128 entries.  Each dbglog message
+ * is a max of 7 32-bit integers in length, but the length can be less
+ * than that as well.
+ */
+#define ATH10K_DBGLOG_DATA_LEN (128 * 7)
+struct ath10k_dbglog_entry_storage {
+   u32 head_idx; /* Where to write next chunk of data */
+   u32 tail_idx; /* Index of first msg */
+   __le32 data[ATH10K_DBGLOG_DATA_LEN];
+};
+
+/* Just enough info to decode firmware debug-log argument length */
+#define DBGLOG_NUM_ARGS_OFFSET   26
+#define DBGLOG_NUM_ARGS_MASK 0xFC00 /* Bit 26-31 */
+#define DBGLOG_NUM_ARGS_MAX  5 /* firmware tool chain limit */
+
 /* used for crash-dump storage, protected by data-lock */
 struct ath10k_fw_crash_data {
bool crashed_since_read;
@@ -437,6 +453,8 @@ struct ath10k_debug {
u32 reg_addr;
u32 nf_cal_period;
 
+   struct ath10k_dbglog_entry_storage dbglog_entry_data;
+
struct ath10k_fw_crash_data *fw_crash_data;
 };
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index d552a4a..1739687 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -35,10 +35,11 @@
 /**
  * enum ath10k_fw_crash_dump_type - types of data in the dump file
  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
  */
 enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
-
+   ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
ATH10K_FW_CRASH_DUMP_MAX,
 };
 
@@ -109,6 +110,12 @@ struct ath10k_dump_file_data {
u8 data[0];
 } __packed;
 
+struct ath10k_dbglog_entry_storage_user {
+   __le32 head_idx; /* Where to write next chunk of data */
+   __le32 tail_idx; /* Index of first msg */
+   __le32 data[ATH10K_DBGLOG_DATA_LEN];
+} __packed;
+
 void ath10k_info(struct ath10k *ar, const char *fmt, ...)
 {
struct va_format vaf = {
@@ -697,7 +704,6 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 
lockdep_assert_held(>data_lock);
 
-   crash_data->crashed_since_read = true;
uuid_le_gen(_data->uuid);
getnstimeofday(_data->timestamp);
 
@@ -705,17 +711,87 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 }
 EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
 
+static void ath10k_dbg_drop_dbg_buffer(struct ath10k *ar)
+{
+   /* Find next message boundary */
+   u32 lg_hdr;
+   int acnt;
+   int tail_idx = ar->debug.dbglog_entry_data.tail_idx;
+   int h_idx = (tail_idx + 1) % ATH10K_DBGLOG_DATA_LEN;
+
+   lockdep_assert_held(>data_lock);
+
+   /* Log header is second 32-bit word */
+   lg_hdr = le32_to_cpu(ar->debug.dbglog_entry_data.data[h_idx]);
+
+   acnt = (lg_hdr & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET;
+
+   if (acnt > DBGLOG_NUM_ARGS_MAX) {
+   /* Some sort of corruption it seems, recover as best we can. */
+   ath10k_err(ar, "invalid dbglog arg-count: %i %i %i\n",
+  acnt, ar->debug.dbglog_entry_data.tail_idx,
+  ar->debug.dbglog_entry_data.head_idx);
+   ar->debug.dbglog_entry_data.tail_idx =
+   ar->debug.dbglog_entry_data.head_idx;
+   return;
+   }
+
+   /* Move forward over the args and the two header fields */
+   ar->debug.dbglog_entry_data.tail_idx =
+   (tail_idx + acnt + 2) % ATH10K_DBGLOG_DATA_LEN;
+}
+
+void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len)
+{
+   int i;
+   int z;
+
+   lockdep_assert_held(>data_lock);
+
+   z = ar->debug.dbglog_entry_data.head_idx;
+
+   /* Don't save any new logs until user-space reads this. */
+   if (ar->debug.fw_crash_data &&
+   ar->debug.fw_crash_data->crashed_since_read) {
+   ath10k_warn(ar, "dropping dbg buffer due to crash since 
read\n");
+   return;
+   }
+

[PATCH v2 21/21] ath10k: Read dbglog buffers over register ping-pong.

2016-05-11 Thread greearb
From: Ben Greear 

This gives much better debugging capability when debugging
crashes in the firmware that cause CE transport loss.

(Such as AXI errors).

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/pci.c | 46 ++-
 1 file changed, 45 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 330c150..286b12d 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1532,7 +1532,7 @@ static int ath10k_ct_fw_crash_regs_harder(struct ath10k 
*ar,
return -EBUSY;
 
 pingpong:
-   ath10k_warn(ar, "Trying to read crash dump over pingpong registers.\n");
+   ath10k_warn(ar, "Trying to read crash dump over pingpong registers, len 
%d\n", len);
/* Firmware is trying to send us info it seems. */
for (q = 0; q 1500) {
+   ath10k_err(ar, "dbuf length is greater than 1500: 
%d\n", len);
+   len = 1500;
+   }
+   if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+   goto free_and_cont;
+
+   ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+   ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+   /* See if the second one is available */
+   if (ath10k_ct_fw_crash_regs_harder(ar, (__le32 *)(), 
sizeof(dbuf)/4))
+   goto free_and_cont;
+
+   len = le32_to_cpu(dbuf.length);
+   if (len > 1500) {
+   ath10k_err(ar, "dbuf[2] length is greater than 1500: 
%d\n", len);
+   len = 1500;
+   }
+
+   if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+   goto free_and_cont;
+
+   ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+   ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+   free_and_cont:
+   kfree(buffer);
}
 
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 09/21] ath10k: print fw debug messages in hex.

2016-05-11 Thread greearb
From: Ben Greear 

This allows user-space tools to decode debug-log
messages by parsing dmesg or /var/log/messages.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 72 +
 drivers/net/wireless/ath/ath10k/debug.h |  5 +++
 drivers/net/wireless/ath/ath10k/pci.c   |  3 ++
 drivers/net/wireless/ath/ath10k/wmi.c   | 12 ++
 4 files changed, 92 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index c7bff1e..97de9f37 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2717,3 +2717,75 @@ void ath10k_dbg_dump(struct ath10k *ar,
 EXPORT_SYMBOL(ath10k_dbg_dump);
 
 #endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
+   const char* lvl)
+{
+   /* Print out raw hex, external tools can decode if
+* they care.
+* TODO:  Add ar identifier to messages.
+*/
+   int q = 0;
+
+   dev_printk(lvl, ar->dev, "ath10k_pci ATH10K_DBG_BUFFER:\n");
+   while (q < len) {
+   if (q + 8 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X 
%08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5], ibuf[q+6], ibuf[q+7]);
+   q += 8;
+   }
+   else if (q + 7 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X 
%08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5], ibuf[q+6]);
+   q += 7;
+   }
+   else if (q + 6 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X 
%08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5]);
+   q += 6;
+   }
+   else if (q + 5 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4]);
+   q += 5;
+   }
+   else if (q + 4 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3]);
+   q += 4;
+   }
+   else if (q + 3 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2]);
+   q += 3;
+   }
+   else if (q + 2 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1]);
+   q += 2;
+   }
+   else if (q + 1 <= len) {
+   printk("%sath10k: [%04d]: %08X\n",
+  lvl, q,
+  ibuf[q]);
+   q += 1;
+   }
+   else {
+   break;
+   }
+   }/* while */
+
+   dev_printk(lvl, ar->dev, "ATH10K_END\n");
+}
+EXPORT_SYMBOL(ath10k_dbg_print_fw_dbg_buffer);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 3062948..641fce1 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -38,6 +38,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT= 0x2000,
ATH10K_DBG_PCI_PS   = 0x4000,
ATH10K_DBG_AHB  = 0x8000,
+   ATH10K_DBG_FW   = 0x8000,
ATH10K_DBG_ANY  = 0x,
 };
 
@@ -192,4 +193,8 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
 {
 }
 #endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer,
+   int len, const char* lvl);
+
 #endif /* _DEBUG_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index e6315ec..dbf0db8 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1623,6 +1623,9 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
WARN_ON(len & 0x3);
 
ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
+ 

[PATCH v2 11/21] ath10k: add fw-powerup-fail to ethtool stats.

2016-05-11 Thread greearb
From: Ben Greear 

This gives user-space a normal-ish way to detect that
firmware has failed to start and that a reboot is
probably required.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h  | 1 +
 drivers/net/wireless/ath/ath10k/debug.c | 2 ++
 drivers/net/wireless/ath/ath10k/pci.c   | 2 ++
 3 files changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 6aa7a14..e7c228a 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -698,6 +698,7 @@ struct ath10k {
 
enum ath10k_hw_rev hw_rev;
u16 dev_id;
+   bool fw_powerup_failed; /* If true, might take reboot to recover. */
u32 chip_id;
u32 target_version;
u8 fw_version_major;
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 76b5163..05b5ea4 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1541,6 +1541,7 @@ static const char 
ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"d_fw_crash_count",
"d_fw_warm_reset_count",
"d_fw_cold_reset_count",
+   "d_fw_powerup_failed", /* boolean */
 };
 
 #define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
@@ -1640,6 +1641,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
data[i++] = ar->stats.fw_crash_counter;
data[i++] = ar->stats.fw_warm_reset_counter;
data[i++] = ar->stats.fw_cold_reset_counter;
+   data[i++] = ar->fw_powerup_failed;
 
spin_unlock_bh(>data_lock);
 
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index dbf0db8..2adc459 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2709,10 +2709,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
goto err_ce;
}
 
+   ar->fw_powerup_failed = false;
return 0;
 
 err_ce:
ath10k_pci_ce_deinit(ar);
+   ar->fw_powerup_failed = true;
 
 err_sleep:
return ret;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 13/21] ath10k: Document cycle count related counters.

2016-05-11 Thread greearb
From: Ben Greear 

They are not necessarily named in an intuitive manner,
so at least add some comments to help the next person.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h | 8 
 drivers/net/wireless/ath/ath10k/wmi.h  | 8 
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index e7c228a..91b1f95 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -189,10 +189,10 @@ struct ath10k_fw_stats_pdev {
 
/* PDEV stats */
s32 ch_noise_floor;
-   u32 tx_frame_count;
-   u32 rx_frame_count;
-   u32 rx_clear_count;
-   u32 cycle_count;
+   u32 tx_frame_count; /* Cycles spent transmitting frames */
+   u32 rx_frame_count; /* Cycles spent receiving frames */
+   u32 rx_clear_count; /* Total channel busy time, evidently */
+   u32 cycle_count; /* Total on-channel time */
u32 phy_err_count;
u32 chan_tx_power;
u32 ack_rx_bad;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h 
b/drivers/net/wireless/ath/ath10k/wmi.h
index 8d9b5b3..91c7df5 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -4208,10 +4208,10 @@ struct wmi_10_2_stats_event {
  */
 struct wmi_pdev_stats_base {
__le32 chan_nf;
-   __le32 tx_frame_count;
-   __le32 rx_frame_count;
-   __le32 rx_clear_count;
-   __le32 cycle_count;
+   __le32 tx_frame_count; /* Cycles spent transmitting frames */
+   __le32 rx_frame_count; /* Cycles spent receiving frames */
+   __le32 rx_clear_count; /* Total channel busy time, evidently */
+   __le32 cycle_count; /* Total on-channel time */
__le32 phy_err_count;
__le32 chan_tx_pwr;
 } __packed;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 14/21] ath10k: Add tx/rx bytes, cycle counters to ethtool stats.

2016-05-11 Thread greearb
From: Ben Greear 

The firmware does not offer tx/rx bytes counters, so just keep track of
it in the driver.

For the cycle counters:

Note these counters are since the chip reset, though the counters
wrap often.  When cycle-counters counter overflows on
certain hardware, it will right shift all 4 of the
related registers to the right by one bit (basically,
divide by two).  Since you have no idea what the others
were at when cycle-counter wrapped, you must simply
ignore any sample where cycle-counter wraps, and set
new baseline values to calculate diffs against next
time.

Hardware with this funny wrap logic will cause the
d_flags 'counter' to have bit 0x1 set, so that is how
user-space can know how to deal with this.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h   |  3 +++
 drivers/net/wireless/ath/ath10k/debug.c  | 22 +-
 drivers/net/wireless/ath/ath10k/htt_rx.c |  3 +++
 drivers/net/wireless/ath/ath10k/htt_tx.c | 22 +-
 4 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 91b1f95..cb6aa8c 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -466,6 +466,9 @@ struct ath10k_debug {
struct ath10k_dbglog_entry_storage dbglog_entry_data;
 
struct ath10k_fw_crash_data *fw_crash_data;
+
+   u64 tx_bytes; /* counter, firmware does not offer this stat */
+   u64 rx_bytes; /* counter, firmware does not offer this stat */
 };
 
 enum ath10k_state {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 05b5ea4..a3da6ab 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -1496,11 +1496,15 @@ exit:
 /* This generally cooresponds to the debugfs fw_stats file */
 static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_pkts_nic",
-   "tx_bytes_nic",
+   "tx_bytes_nic", /* from driver, firmware does not keep this stat. */
"rx_pkts_nic",
-   "rx_bytes_nic",
+   "rx_bytes_nic", /* from driver, firmware does not keep this stat. */
"d_noise_floor",
-   "d_cycle_count",
+   "d_cycle_count", /* this is duty cycle counter, basically channel-time. 
88MHz clock */
+   "d_tx_cycle_count", /* tx cycle count */
+   "d_rx_cycle_count", /* rx cycle count */
+   "d_busy_count", /* Total channel busy time cycles (called 'clear' by 
firmware) */
+   "d_flags", /* 0x1:  hw has shifted cycle-count wrap, see 
ath10k_hw_fill_survey_time */
"d_phy_error",
"d_rts_bad",
"d_rts_good",
@@ -1572,6 +1576,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
static const struct ath10k_fw_stats_pdev zero_stats = {};
const struct ath10k_fw_stats_pdev *pdev_stats;
int i = 0, ret;
+   u64 d_flags = 0;
 
mutex_lock(>conf_mutex);
 
@@ -1595,12 +1600,19 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
 
spin_lock_bh(>data_lock);
 
+   if (ar->hw_params.has_shifted_cc_wraparound)
+   d_flags |= 0x1;
+
data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
-   data[i++] = 0; /* tx bytes */
+   data[i++] = ar->debug.tx_bytes;
data[i++] = pdev_stats->htt_mpdus;
-   data[i++] = 0; /* rx bytes */
+   data[i++] = ar->debug.rx_bytes;
data[i++] = pdev_stats->ch_noise_floor;
data[i++] = pdev_stats->cycle_count;
+   data[i++] = pdev_stats->tx_frame_count;
+   data[i++] = pdev_stats->rx_frame_count;
+   data[i++] = pdev_stats->rx_clear_count; /* yes, this appears to 
actually be 'busy' count */
+   data[i++] = d_flags; /* give user-space a chance to decode cycle 
counters */
data[i++] = pdev_stats->phy_err_count;
data[i++] = pdev_stats->rts_bad;
data[i++] = pdev_stats->rts_good;
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c 
b/drivers/net/wireless/ath/ath10k/htt_rx.c
index cc979a4..47da904 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -1379,6 +1379,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
 }
 
skb_queue_walk(amsdu, msdu) {
+#ifdef CONFIG_ATH10K_DEBUGFS
+   ar->debug.rx_bytes += msdu->len;
+#endif
ath10k_htt_rx_h_csum_offload(msdu);
ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
is_decrypted);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c 
b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 6269c61..06ec995 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -769,6 +769,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct 
sk_buff *msdu)
int len = 0;
int msdu_id = -1;
 

[PATCH v2 06/21] ath10k: save firmware stacks upon firmware crash

2016-05-11 Thread greearb
From: Ben Greear 

Should help debug firmware crashes, and give users a way
to provide some useful debug reports to firmware developers.

Signed-off-by: Ben Greear 
Signed-off-by: Kalle Valo 
---
 drivers/net/wireless/ath/ath10k/core.h  |  4 +++
 drivers/net/wireless/ath/ath10k/debug.c | 29 +-
 drivers/net/wireless/ath/ath10k/hw.h|  2 ++
 drivers/net/wireless/ath/ath10k/pci.c   | 52 +
 4 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 7f9f460..644d077 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -427,6 +427,10 @@ struct ath10k_fw_crash_data {
uuid_le uuid;
struct timespec timestamp;
__le32 registers[REG_DUMP_COUNT_QCA988X];
+   __le32 stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+   __le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+   __le32 stack_addr;
+   __le32 exc_stack_addr;
 };
 
 struct ath10k_debug {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 1739687..ec6db04 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -36,10 +36,15 @@
  * enum ath10k_fw_crash_dump_type - types of data in the dump file
  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
  * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
+ * @ATH10K_FW_CRASH_DUMP_STACK:   Stack memory contents.
+ * @ATH10K_FW_CRASH_DUMP_EXC_STACK:   Exception stack memory contents.
  */
 enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
+   ATH10K_FW_CRASH_DUMP_STACK = 2,
+   ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
+
ATH10K_FW_CRASH_DUMP_MAX,
 };
 
@@ -103,8 +108,11 @@ struct ath10k_dump_file_data {
/* VERMAGIC_STRING */
char kernel_ver[64];
 
+   __le32 stack_addr;
+   __le32 exc_stack_addr;
+
/* room for growth w/out changing binary format */
-   u8 unused[128];
+   u8 unused[120];
 
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
@@ -792,6 +800,8 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
+   len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
+   len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
 
sofar += hdr_len;
 
@@ -831,6 +841,8 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+   dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
+   dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
 
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
@@ -863,7 +875,22 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
dbglog_storage->tail_idx =
cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
+   sofar += sizeof(*dump_tlv) + tmp;
 
+   /* Gather firmware stack dump */
+   tmp = sizeof(crash_data->stack_buf);
+   dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+   dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_STACK);
+   dump_tlv->tlv_len = cpu_to_le32(tmp);
+   memcpy(dump_tlv->tlv_data, crash_data->stack_buf, tmp);
+   sofar += sizeof(*dump_tlv) + tmp;
+
+   /* Gather firmware exception stack dump */
+   tmp = sizeof(crash_data->exc_stack_buf);
+   dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+   dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_EXC_STACK);
+   dump_tlv->tlv_len = cpu_to_le32(tmp);
+   memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
sofar += sizeof(*dump_tlv) + tmp;
 
ar->debug.fw_crash_data->crashed_since_read = false;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index 5bbef4b..e86ebf0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -122,6 +122,8 @@ enum qca9377_chip_id_rev {
 
 #define REG_DUMP_COUNT_QCA988X 60
 
+#define ATH10K_FW_STACK_SIZE 4096
+
 struct ath10k_fw_ie {
__le32 id;
__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 16e32d0..62dd167 100644
--- 

[PATCH v2 15/21] ath10k: support CT firmware flag.

2016-05-11 Thread greearb
From: Ben Greear 

Add placeholder so CT firmware can more easily co-exist with upstream
kernel.  CT firmware should be backwards compatible with existing kernels,
but it also has many new features.  Subsequent patches, if acceptable for
upstream, can enable and further describe those features.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 1 +
 drivers/net/wireless/ath/ath10k/core.h | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index fa71d57..49c85c3 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -235,6 +235,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
[ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
+   [ATH10K_FW_FEATURE_WMI_10X_CT] = "wmi-10.x-CT",
 };
 
 static unsigned int ath10k_core_get_fw_feature_str(char *buf,
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index cb6aa8c..f9e3b20 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -566,6 +566,9 @@ enum ath10k_fw_features {
 */
ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
 
+   /* Firmware from Candela Technologies, enables more VIFs, etc */
+   ATH10K_FW_FEATURE_WMI_10X_CT = 31,
+
/* keep last */
ATH10K_FW_FEATURE_COUNT,
 };
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 02/21] ath10k: fix typo in logging message

2016-05-11 Thread greearb
From: Ben Greear 

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 0e24f9e..cd3016d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2747,7 +2747,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret)
-   ath10k_warn(ar, "faield to down vdev %i: %d\n",
+   ath10k_warn(ar, "failed to down vdev %i: %d\n",
arvif->vdev_id, ret);
 
arvif->def_wep_key_idx = -1;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 04/21] ath10k: rate-limit packet tx errors

2016-05-11 Thread greearb
From: Ben Greear 

When firmware crashes, stack can continue to send packets
for a bit, and existing code was spamming logs.

So, rate-limit the error message for tx failures.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index cd3016d..42cac32 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3432,8 +3432,9 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
}
 
if (ret) {
-   ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
-   ret);
+   if (net_ratelimit())
+   ath10k_warn(ar, "failed to transmit packet, dropping: 
%d\n",
+   ret);
ieee80211_free_txskb(ar->hw, skb);
}
 
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH v2 12/21] ath10k: Support up to 64 vdevs.

2016-05-11 Thread greearb
From: Ben Greear 

The (1 << x) - 1 trick won't work when you
are trying to fill up all 64 bits, so add special
case for that.

And, move the limits to the per-nic structure instead
of per-driver to allow better dynamic use of the limits.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 3f1786c..fa71d57 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1819,7 +1819,10 @@ int ath10k_core_start(struct ath10k *ar, enum 
ath10k_firmware_mode mode,
if (status)
goto err_hif_stop;
 
-   ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
+   if (ar->max_num_vdevs >= 64)
+   ar->free_vdev_map = 0xLL;
+   else
+   ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
 
INIT_LIST_HEAD(>arvifs);
 
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] mac80211: Get ethtool-stats frequency more often.

2016-05-09 Thread greearb
From: Ben Greear 

Some NICs (ath9k_htc) don't use chanctx_conf, it
seems, so look at local->hw.conf.channel->center_freq
in that case.

Signed-off-by: Ben Greear 
---
 net/mac80211/ethtool.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 9cc986d..4e937c1 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -165,10 +165,14 @@ do_survey:
} while (channel != survey.channel);
}
 
-   if (survey.filled)
-   data[i++] = survey.channel->center_freq;
-   else
-   data[i++] = 0;
+   if (channel) {
+   data[i++] = channel->center_freq;
+   } else {
+   if (local->_oper_chandef.chan)
+   data[i++] = local->_oper_chandef.chan->center_freq;
+   else
+   data[i++] = 0;
+   }
if (survey.filled & SURVEY_INFO_NOISE_DBM)
data[i++] = (u8)survey.noise;
else
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/21] ath10k: print fw debug messages in hex.

2016-05-09 Thread greearb
From: Ben Greear 

This allows user-space tools to decode debug-log
messages by parsing dmesg or /var/log/messages.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 72 +
 drivers/net/wireless/ath/ath10k/debug.h |  5 +++
 drivers/net/wireless/ath/ath10k/pci.c   |  3 ++
 drivers/net/wireless/ath/ath10k/wmi.c   | 12 ++
 4 files changed, 92 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 28e0c05..c38862b 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -2660,3 +2660,75 @@ void ath10k_dbg_dump(struct ath10k *ar,
 EXPORT_SYMBOL(ath10k_dbg_dump);
 
 #endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
+   const char* lvl)
+{
+   /* Print out raw hex, external tools can decode if
+* they care.
+* TODO:  Add ar identifier to messages.
+*/
+   int q = 0;
+
+   dev_printk(lvl, ar->dev, "ath10k_pci ATH10K_DBG_BUFFER:\n");
+   while (q < len) {
+   if (q + 8 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X 
%08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5], ibuf[q+6], ibuf[q+7]);
+   q += 8;
+   }
+   else if (q + 7 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X 
%08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5], ibuf[q+6]);
+   q += 7;
+   }
+   else if (q + 6 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X 
%08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4], ibuf[q+5]);
+   q += 6;
+   }
+   else if (q + 5 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
+  ibuf[q+4]);
+   q += 5;
+   }
+   else if (q + 4 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3]);
+   q += 4;
+   }
+   else if (q + 3 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1], ibuf[q+2]);
+   q += 3;
+   }
+   else if (q + 2 <= len) {
+   printk("%sath10k: [%04d]: %08X %08X\n",
+  lvl, q,
+  ibuf[q], ibuf[q+1]);
+   q += 2;
+   }
+   else if (q + 1 <= len) {
+   printk("%sath10k: [%04d]: %08X\n",
+  lvl, q,
+  ibuf[q]);
+   q += 1;
+   }
+   else {
+   break;
+   }
+   }/* while */
+
+   dev_printk(lvl, ar->dev, "ATH10K_END\n");
+}
+EXPORT_SYMBOL(ath10k_dbg_print_fw_dbg_buffer);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 613ad7e..6356dce 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -38,6 +38,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT= 0x2000,
ATH10K_DBG_PCI_PS   = 0x4000,
ATH10K_DBG_AHB  = 0x8000,
+   ATH10K_DBG_FW   = 0x8000,
ATH10K_DBG_ANY  = 0x,
 };
 
@@ -193,4 +194,8 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
 {
 }
 #endif /* CONFIG_ATH10K_DEBUG */
+
+void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer,
+   int len, const char* lvl);
+
 #endif /* _DEBUG_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index e6315ec..dbf0db8 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1623,6 +1623,9 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
WARN_ON(len & 0x3);
 
ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
+  

[PATCH 07/21] ath10k: save firmware RAM and ROM BSS sections on crash

2016-05-09 Thread greearb
From: Ben Greear 

This can be used to get a useful back trace out of a firmware
crash that involves an interrupt handler.  For instance, a
null-pointer-exception would be this kind of trace.  A user-space
tool can read the debugfs file and decode things as wished.

This requires a packaged firmware with a new IE to describe the
BSS section starts and length.

Signed-off-by: Ben Greear 
Signed-off-by: Kalle Valo 
---
 drivers/net/wireless/ath/ath10k/core.c  | 48 +
 drivers/net/wireless/ath/ath10k/core.h  | 14 +
 drivers/net/wireless/ath/ath10k/debug.c | 40 +++-
 drivers/net/wireless/ath/ath10k/hw.h|  2 ++
 drivers/net/wireless/ath/ath10k/pci.c   | 54 +
 5 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index b7318b8..3f1786c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -922,6 +922,13 @@ err:
return ret;
 }
 
+struct ath10k_bss_rom_ie {
+   __le32 ram_addr;
+   __le32 ram_len;
+   __le32 rom_addr;
+   __le32 rom_len;
+} __packed;
+
 static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
 size_t name_len)
 {
@@ -983,6 +990,7 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
struct ath10k_fw_ie *hdr;
const u8 *data;
__le32 *timestamp, *version;
+   struct ath10k_bss_rom_ie *bss;
 
/* first fetch the firmware file (firmware-*.bin) */
fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
@@ -1100,6 +1108,12 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
 
break;
case ATH10K_FW_IE_WMI_OP_VERSION:
+   /* Upstream stole the ID CT firmware was using, so add
+* hack-around to deal with backwards-compat. --Ben
+*/
+   if (ie_len >= sizeof(*bss))
+   goto fw_ie_bss_info_ct;
+
if (ie_len != sizeof(u32))
break;
 
@@ -1128,6 +1142,40 @@ int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, 
const char *name,
fw_file->codeswap_data = data;
fw_file->codeswap_len = ie_len;
break;
+   case ATH10K_FW_IE_BSS_INFO_CT:
+fw_ie_bss_info_ct:
+   if (ie_len < sizeof(*bss)) {
+   ath10k_warn(ar, "invalid ie len for bss-info 
(%zd)\n",
+   ie_len);
+   break;
+   }
+   bss = (struct ath10k_bss_rom_ie *)(data);
+
+   fw_file->ram_bss_addr = le32_to_cpu(bss->ram_addr);
+   fw_file->ram_bss_len = le32_to_cpu(bss->ram_len);
+   ath10k_dbg(ar, ATH10K_DBG_BOOT,
+  "found RAM BSS addr 0x%x length %d\n",
+  fw_file->ram_bss_addr, fw_file->ram_bss_len);
+
+   if (fw_file->ram_bss_len > ATH10K_RAM_BSS_BUF_LEN) {
+   ath10k_warn(ar, "too long firmware RAM BSS 
length: %d\n",
+   fw_file->ram_bss_len);
+   fw_file->ram_bss_len = 0;
+   }
+
+   fw_file->rom_bss_addr = le32_to_cpu(bss->rom_addr);
+   fw_file->rom_bss_len = le32_to_cpu(bss->rom_len);
+   ath10k_dbg(ar, ATH10K_DBG_BOOT,
+  "found ROM BSS addr 0x%x length %d\n",
+  fw_file->rom_bss_addr, fw_file->rom_bss_len);
+
+   if (fw_file->rom_bss_len > ATH10K_ROM_BSS_BUF_LEN) {
+   ath10k_warn(ar, "too long firmware ROM BSS 
length: %d\n",
+   fw_file->rom_bss_len);
+   fw_file->rom_bss_len = 0;
+   }
+
+   break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 644d077..6aa7a14 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -420,6 +420,10 @@ struct ath10k_dbglog_entry_storage {
 #define DBGLOG_NUM_ARGS_MASK 0xFC00 /* Bit 26-31 */
 #define DBGLOG_NUM_ARGS_MAX  5 /* firmware tool chain limit */
 
+/* estimated values, hopefully these are 

[PATCH 08/21] ath10k: make firmware text debug messages more verbose.

2016-05-09 Thread greearb
From: Ben Greear 

There are not many of these messages producted by the
firmware, but they are generally fairly useful, so print
them at info level.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/wmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/wmi.c 
b/drivers/net/wireless/ath/ath10k/wmi.c
index 1758b4a..d9e4b77 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -4050,7 +4050,7 @@ void ath10k_wmi_event_debug_print(struct ath10k *ar, 
struct sk_buff *skb)
/* the last byte is always reserved for the null character */
buf[i] = '\0';
 
-   ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
+   ath10k_info(ar, "wmi print '%s'\n", buf);
 }
 
 void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 04/21] ath10k: rate-limit packet tx errors

2016-05-09 Thread greearb
From: Ben Greear 

When firmware crashes, stack can continue to send packets
for a bit, and existing code was spamming logs.

So, rate-limit the error message for tx failures.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index cd3016d..42cac32 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3432,8 +3432,9 @@ static int ath10k_mac_tx_submit(struct ath10k *ar,
}
 
if (ret) {
-   ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
-   ret);
+   if (net_ratelimit())
+   ath10k_warn(ar, "failed to transmit packet, dropping: 
%d\n",
+   ret);
ieee80211_free_txskb(ar->hw, skb);
}
 
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 10/21] ath10k: support logging ath10k_info as KERN_DEBUG

2016-05-09 Thread greearb
From: Ben Greear 

Helps keep messages off of (serial) console when
that is desired.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/debug.c | 5 -
 drivers/net/wireless/ath/ath10k/debug.h | 6 ++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index c38862b..7d9ad99 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -139,7 +139,10 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
 
va_start(args, fmt);
vaf.va = 
-   dev_info(ar->dev, "%pV", );
+   if (ath10k_debug_mask & ATH10K_DBG_INFO_AS_DBG)
+   dev_printk(KERN_DEBUG, ar->dev, "%pV", );
+   else
+   dev_info(ar->dev, "%pV", );
trace_ath10k_log_info(ar, );
va_end(args);
 }
diff --git a/drivers/net/wireless/ath/ath10k/debug.h 
b/drivers/net/wireless/ath/ath10k/debug.h
index 6356dce..4f10685 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -21,6 +21,10 @@
 #include 
 #include "trace.h"
 
+/**
+ * ATH10K_DBG_INFO_AS_DBG: use dev_dbg instead of dev_info
+ *   for ath10k_info messages
+ */
 enum ath10k_debug_mask {
ATH10K_DBG_PCI  = 0x0001,
ATH10K_DBG_WMI  = 0x0002,
@@ -38,6 +42,8 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT= 0x2000,
ATH10K_DBG_PCI_PS   = 0x4000,
ATH10K_DBG_AHB  = 0x8000,
+
+   ATH10K_DBG_INFO_AS_DBG  = 0x4000,
ATH10K_DBG_FW   = 0x8000,
ATH10K_DBG_ANY  = 0x,
 };
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 18/21] ath10k: Note limitation on beaconing vdevs.

2016-05-09 Thread greearb
From: Ben Greear 

This only pertains to CT firmware, as standard firmware
can't do anywhere near this many vdevs anyway.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 373f2ee..f1bfb3a 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1343,6 +1343,22 @@ static int ath10k_vdev_start_restart(struct ath10k_vif 
*arvif,
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
 
+   /* CT Firmware can support 32+ VDEVS, but can only support
+* beacon-ing devs with dev ids 0 - 31 due to firmware limitations.
+* Create VAPs first and all should be well...likely most people
+* won't ever hit this anyway, but some day the vdev ID allocation
+* could be made smarter to make it more likely to work no matter the
+* order the vdevs are created. --Ben
+*/
+   if ((arvif->vdev_type == WMI_VDEV_TYPE_AP) ||
+   (arvif->vdev_type == WMI_VDEV_TYPE_IBSS)) {
+   if (arg.vdev_id > 31) {
+   ath10k_warn(ar, "failed to start vdev %i  Beaconing 
VIFS must have IDs <= 31 to work-around firmware limitations.\n",
+   arg.vdev_id);
+   return -EINVAL;
+   }
+   }
+
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
arg.ssid_len = arvif->u.ap.ssid_len;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 05/21] ath10k: save firmware debug log messages.

2016-05-09 Thread greearb
From: Ben Greear 

They may be dumped through the firmware dump debugfs
file.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.h  | 18 ++
 drivers/net/wireless/ath/ath10k/debug.c | 97 +++-
 drivers/net/wireless/ath/ath10k/debug.h |  6 ++
 drivers/net/wireless/ath/ath10k/hw.h| 21 +++
 drivers/net/wireless/ath/ath10k/pci.c   | 99 +
 drivers/net/wireless/ath/ath10k/wmi.c   | 13 +
 drivers/net/wireless/ath/ath10k/wmi.h   |  6 ++
 7 files changed, 258 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 1379054..7f9f460 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -404,6 +404,22 @@ struct ath10k_vif_iter {
struct ath10k_vif *arvif;
 };
 
+/* This will store at least the last 128 entries.  Each dbglog message
+ * is a max of 7 32-bit integers in length, but the length can be less
+ * than that as well.
+ */
+#define ATH10K_DBGLOG_DATA_LEN (128 * 7)
+struct ath10k_dbglog_entry_storage {
+   u32 head_idx; /* Where to write next chunk of data */
+   u32 tail_idx; /* Index of first msg */
+   __le32 data[ATH10K_DBGLOG_DATA_LEN];
+};
+
+/* Just enough info to decode firmware debug-log argument length */
+#define DBGLOG_NUM_ARGS_OFFSET   26
+#define DBGLOG_NUM_ARGS_MASK 0xFC00 /* Bit 26-31 */
+#define DBGLOG_NUM_ARGS_MAX  5 /* firmware tool chain limit */
+
 /* used for crash-dump storage, protected by data-lock */
 struct ath10k_fw_crash_data {
bool crashed_since_read;
@@ -437,6 +453,8 @@ struct ath10k_debug {
u32 reg_addr;
u32 nf_cal_period;
 
+   struct ath10k_dbglog_entry_storage dbglog_entry_data;
+
struct ath10k_fw_crash_data *fw_crash_data;
 };
 
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index a689bf1..38b3541 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -35,10 +35,11 @@
 /**
  * enum ath10k_fw_crash_dump_type - types of data in the dump file
  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+ * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
  */
 enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
-
+   ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
ATH10K_FW_CRASH_DUMP_MAX,
 };
 
@@ -109,6 +110,12 @@ struct ath10k_dump_file_data {
u8 data[0];
 } __packed;
 
+struct ath10k_dbglog_entry_storage_user {
+   __le32 head_idx; /* Where to write next chunk of data */
+   __le32 tail_idx; /* Index of first msg */
+   __le32 data[ATH10K_DBGLOG_DATA_LEN];
+} __packed;
+
 void ath10k_info(struct ath10k *ar, const char *fmt, ...)
 {
struct va_format vaf = {
@@ -702,7 +709,6 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 
lockdep_assert_held(>data_lock);
 
-   crash_data->crashed_since_read = true;
uuid_le_gen(_data->uuid);
getnstimeofday(_data->timestamp);
 
@@ -710,17 +716,87 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
 }
 EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
 
+static void ath10k_dbg_drop_dbg_buffer(struct ath10k *ar)
+{
+   /* Find next message boundary */
+   u32 lg_hdr;
+   int acnt;
+   int tail_idx = ar->debug.dbglog_entry_data.tail_idx;
+   int h_idx = (tail_idx + 1) % ATH10K_DBGLOG_DATA_LEN;
+
+   lockdep_assert_held(>data_lock);
+
+   /* Log header is second 32-bit word */
+   lg_hdr = le32_to_cpu(ar->debug.dbglog_entry_data.data[h_idx]);
+
+   acnt = (lg_hdr & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET;
+
+   if (acnt > DBGLOG_NUM_ARGS_MAX) {
+   /* Some sort of corruption it seems, recover as best we can. */
+   ath10k_err(ar, "invalid dbglog arg-count: %i %i %i\n",
+  acnt, ar->debug.dbglog_entry_data.tail_idx,
+  ar->debug.dbglog_entry_data.head_idx);
+   ar->debug.dbglog_entry_data.tail_idx =
+   ar->debug.dbglog_entry_data.head_idx;
+   return;
+   }
+
+   /* Move forward over the args and the two header fields */
+   ar->debug.dbglog_entry_data.tail_idx =
+   (tail_idx + acnt + 2) % ATH10K_DBGLOG_DATA_LEN;
+}
+
+void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len)
+{
+   int i;
+   int z;
+
+   lockdep_assert_held(>data_lock);
+
+   z = ar->debug.dbglog_entry_data.head_idx;
+
+   /* Don't save any new logs until user-space reads this. */
+   if (ar->debug.fw_crash_data &&
+   ar->debug.fw_crash_data->crashed_since_read) {
+   ath10k_warn(ar, "dropping dbg buffer due to crash since 
read\n");
+   return;
+   }
+

[PATCH 06/21] ath10k: save firmware stacks upon firmware crash

2016-05-09 Thread greearb
From: Ben Greear 

Should help debug firmware crashes, and give users a way
to provide some useful debug reports to firmware developers.

Signed-off-by: Ben Greear 
Signed-off-by: Kalle Valo 
---
 drivers/net/wireless/ath/ath10k/core.h  |  4 +++
 drivers/net/wireless/ath/ath10k/debug.c | 29 +-
 drivers/net/wireless/ath/ath10k/hw.h|  2 ++
 drivers/net/wireless/ath/ath10k/pci.c   | 52 +
 4 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.h 
b/drivers/net/wireless/ath/ath10k/core.h
index 7f9f460..644d077 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -427,6 +427,10 @@ struct ath10k_fw_crash_data {
uuid_le uuid;
struct timespec timestamp;
__le32 registers[REG_DUMP_COUNT_QCA988X];
+   __le32 stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+   __le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+   __le32 stack_addr;
+   __le32 exc_stack_addr;
 };
 
 struct ath10k_debug {
diff --git a/drivers/net/wireless/ath/ath10k/debug.c 
b/drivers/net/wireless/ath/ath10k/debug.c
index 38b3541..7bc3053 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -36,10 +36,15 @@
  * enum ath10k_fw_crash_dump_type - types of data in the dump file
  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
  * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
+ * @ATH10K_FW_CRASH_DUMP_STACK:   Stack memory contents.
+ * @ATH10K_FW_CRASH_DUMP_EXC_STACK:   Exception stack memory contents.
  */
 enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
+   ATH10K_FW_CRASH_DUMP_STACK = 2,
+   ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
+
ATH10K_FW_CRASH_DUMP_MAX,
 };
 
@@ -103,8 +108,11 @@ struct ath10k_dump_file_data {
/* VERMAGIC_STRING */
char kernel_ver[64];
 
+   __le32 stack_addr;
+   __le32 exc_stack_addr;
+
/* room for growth w/out changing binary format */
-   u8 unused[128];
+   u8 unused[120];
 
/* struct ath10k_tlv_dump_data + more */
u8 data[0];
@@ -797,6 +805,8 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
+   len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
+   len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
 
sofar += hdr_len;
 
@@ -836,6 +846,8 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+   dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
+   dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
 
strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
sizeof(dump_data->fw_ver));
@@ -868,7 +880,22 @@ static struct ath10k_dump_file_data 
*ath10k_build_dump_file(struct ath10k *ar)
cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
dbglog_storage->tail_idx =
cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
+   sofar += sizeof(*dump_tlv) + tmp;
 
+   /* Gather firmware stack dump */
+   tmp = sizeof(crash_data->stack_buf);
+   dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+   dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_STACK);
+   dump_tlv->tlv_len = cpu_to_le32(tmp);
+   memcpy(dump_tlv->tlv_data, crash_data->stack_buf, tmp);
+   sofar += sizeof(*dump_tlv) + tmp;
+
+   /* Gather firmware exception stack dump */
+   tmp = sizeof(crash_data->exc_stack_buf);
+   dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+   dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_EXC_STACK);
+   dump_tlv->tlv_len = cpu_to_le32(tmp);
+   memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
sofar += sizeof(*dump_tlv) + tmp;
 
ar->debug.fw_crash_data->crashed_since_read = false;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index 5bbef4b..e86ebf0 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -122,6 +122,8 @@ enum qca9377_chip_id_rev {
 
 #define REG_DUMP_COUNT_QCA988X 60
 
+#define ATH10K_FW_STACK_SIZE 4096
+
 struct ath10k_fw_ie {
__le32 id;
__le32 len;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 16e32d0..62dd167 100644
--- 

[PATCH 02/21] ath10k: fix typo in logging message

2016-05-09 Thread greearb
From: Ben Greear 

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 0e24f9e..cd3016d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2747,7 +2747,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
 
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
if (ret)
-   ath10k_warn(ar, "faield to down vdev %i: %d\n",
+   ath10k_warn(ar, "failed to down vdev %i: %d\n",
arvif->vdev_id, ret);
 
arvif->def_wep_key_idx = -1;
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 21/21] ath10k: Read dbglog buffers over register ping-pong.

2016-05-09 Thread greearb
From: Ben Greear 

This gives much better debugging capability when debugging
crashes in the firmware that cause CE transport loss.

(Such as AXI errors).

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/pci.c | 47 ++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 330c150..4069e72 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1532,7 +1532,7 @@ static int ath10k_ct_fw_crash_regs_harder(struct ath10k 
*ar,
return -EBUSY;
 
 pingpong:
-   ath10k_warn(ar, "Trying to read crash dump over pingpong registers.\n");
+   ath10k_warn(ar, "Trying to read crash dump over pingpong registers, len 
%d\n", len);
/* Firmware is trying to send us info it seems. */
for (q = 0; q 1500) {
+   ath10k_err(ar, "dbuf length is greater than 1500: 
%d\n", len);
+   len = 1500;
+   }
+   if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+   goto free_and_cont;
+
+   ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+   ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+   /* See if the second one is available */
+   if (ath10k_ct_fw_crash_regs_harder(ar, (__le32 *)(), 
sizeof(dbuf)/4))
+   goto free_and_cont;
+
+   len = le32_to_cpu(dbuf.length);
+   if (len > 1500) {
+   ath10k_err(ar, "dbuf[2] length is greater than 1500: 
%d\n", len);
+   len = 1500;
+   }
+
+   if (ath10k_ct_fw_crash_regs_harder(ar, buffer, len/4))
+   goto free_and_cont;
+
+   ath10k_dbg_save_fw_dbg_buffer(ar, buffer, len/4);
+   ath10k_dbg_print_fw_dbg_buffer(ar, buffer, len/4, KERN_ERR);
+
+   free_and_cont:
+   kfree(buffer);
}
 
BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
@@ -1723,6 +1767,7 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
 
spin_unlock_bh(>data_lock);
 
+   /* ath10k_set_debug_mask(0);  // stop more log spam */
queue_work(ar->workqueue, >restart_work);
 }
 
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 20/21] ath10k: read firmware crash over ioread32 if CE fails.

2016-05-09 Thread greearb
From: Ben Greear 

This might work around problem where sometimes host cannot
access firmware crash over normal CE transport.

Requires CT firmware with matching logic in it's assert
handler (-13 and higher releases).

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/hw.h  |  5 
 drivers/net/wireless/ath/ath10k/pci.c | 56 ++-
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index d3f37d5..5ff1fac 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -603,6 +603,7 @@ enum ath10k_hw_4addr_pad {
 #define PCIE_INTR_ENABLE_ADDRESS   0x0008
 #define PCIE_INTR_CAUSE_ADDRESS0x000c
 #define PCIE_INTR_CLR_ADDRESS  ar->regs->pcie_intr_clr_address
+#define SCRATCH_2_ADDRESS   0x002c
 #define SCRATCH_3_ADDRESS  ar->regs->scratch_3_address
 #define CPU_INTR_ADDRESS   0x0010
 
@@ -614,6 +615,10 @@ enum ath10k_hw_4addr_pad {
 #define FW_IND_INITIALIZED 2
 #define FW_IND_HOST_READY  0x8000
 
+/* CT firmware only */
+#define FW_IND_SCRATCH2_WR  (1<<14) /* scratch2 has data written to it */
+#define FW_IND_SCRATCH2_RD  (1<<15) /* scratch2 has been read (by host) */
+
 /* HOST_REG interrupt from firmware */
 #define PCIE_INTR_FIRMWARE_MASK
ar->regs->pcie_intr_fw_mask
 #define PCIE_INTR_CE_MASK_ALL  ar->regs->pcie_intr_ce_mask_all
diff --git a/drivers/net/wireless/ath/ath10k/pci.c 
b/drivers/net/wireless/ath/ath10k/pci.c
index 2adc459..330c150 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1507,6 +1507,54 @@ static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
 hi_err_stack);
 }
 
+/* Only CT firmware can do this.  Attempt to read crash dump over pci
+ * registers since normal CE transport is not working.
+ */
+static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
+ __le32 *reg_dump_values,
+ int len)
+{
+   u32 val;
+   int i;
+   int q;
+#define MAX_SPIN_TRIES 100
+
+   if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ ar->running_fw->fw_file.fw_features)) {
+   return -EINVAL;
+   }
+
+   for (i = 0; i

[PATCH 16/21] ath10k: Support 32+ stations.

2016-05-09 Thread greearb
From: Ben Greear 

Support up to 32 stations when using CT firmware.

Signed-off-by: Ben Greear 
---
 drivers/net/wireless/ath/ath10k/core.c | 14 +++
 drivers/net/wireless/ath/ath10k/hw.h   |  6 +
 drivers/net/wireless/ath/ath10k/mac.c  | 43 ++
 drivers/net/wireless/ath/ath10k/wmi.c  | 16 ++---
 4 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c 
b/drivers/net/wireless/ath/ath10k/core.c
index 49c85c3..3869edd 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1567,6 +1567,20 @@ static int ath10k_core_init_firmware_features(struct 
ath10k *ar)
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+fw_file->fw_features)) {
+   ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
+   ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+   ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
+   } else {
+   ar->max_num_peers = TARGET_10X_NUM_PEERS;
+   ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+   ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
+   }
+   ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+   ar->fw_stats_req_mask = WMI_STAT_PEER;
+   ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
+   break;
case ATH10K_FW_WMI_OP_VERSION_10_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
if (ath10k_peer_stats_enabled(ar)) {
diff --git a/drivers/net/wireless/ath/ath10k/hw.h 
b/drivers/net/wireless/ath/ath10k/hw.h
index 7b80e29..d3f37d5 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -370,6 +370,12 @@ enum ath10k_hw_4addr_pad {
 (TARGET_10X_NUM_VDEVS))
 #define TARGET_10X_TX_STATS_NUM_PEERS  
((TARGET_10X_TX_STATS_NUM_STATIONS) + \
 (TARGET_10X_NUM_VDEVS))
+
+/* Over-rides for Candela Technologies firmware */
+#define TARGET_10X_NUM_VDEVS_CT32
+#define TARGET_10X_NUM_PEERS_CT(32 + 
(TARGET_10X_NUM_VDEVS_CT))
+#define TARGET_10X_AST_SKID_LIMIT_CT   (TARGET_10X_NUM_PEERS_CT * 
TARGET_10X_NUM_PEER_AST)
+
 #define TARGET_10X_NUM_OFFLOAD_PEERS   0
 #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS0
 #define TARGET_10X_NUM_PEER_KEYS   2
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 42cac32..2169337 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7451,6 +7451,22 @@ static const struct ieee80211_iface_limit 
ath10k_10x_if_limits[] = {
},
 };
 
+static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+   {
+   .max= TARGET_10X_NUM_VDEVS_CT,
+   .types  = BIT(NL80211_IFTYPE_STATION)
+   | BIT(NL80211_IFTYPE_P2P_CLIENT)
+   },
+   {
+   .max= 3,
+   .types  = BIT(NL80211_IFTYPE_P2P_GO)
+   },
+   {
+   .max= 7,
+   .types  = BIT(NL80211_IFTYPE_AP)
+   },
+};
+
 static const struct ieee80211_iface_combination ath10k_if_comb[] = {
{
.limits = ath10k_if_limits,
@@ -7531,6 +7547,22 @@ static const struct ieee80211_iface_limit 
ath10k_tlv_if_limit_ibss[] = {
},
 };
 
+static const struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
+   {
+   .limits = ath10k_10x_ct_if_limits,
+   .n_limits = ARRAY_SIZE(ath10k_10x_ct_if_limits),
+   .max_interfaces = TARGET_10X_NUM_VDEVS_CT,
+   .num_different_channels = 1,
+   .beacon_int_infra_match = true,
+#ifdef CONFIG_ATH10K_DFS_CERTIFIED
+   .radar_detect_widths =  BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+   BIT(NL80211_CHAN_WIDTH_20) |
+   BIT(NL80211_CHAN_WIDTH_40) |
+   BIT(NL80211_CHAN_WIDTH_80),
+#endif
+   },
+};
+
 /* FIXME: This is not thouroughly tested. These combinations may over- or
  * underestimate hw/fw capabilities.
  */
@@ -7808,6 +7840,17 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
break;
case ATH10K_FW_WMI_OP_VERSION_10_1:
+   if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
+ar->normal_mode_fw.fw_file.fw_features)) {
+   ar->hw->wiphy->iface_combinations = 
ath10k_10x_ct_if_comb;
+   

  1   2   3   >