Skip to content

Commit

Permalink
ath10k: Support tx at very specific ratecode, beacon debugging, etc.
Browse files Browse the repository at this point in the history
See the new debugfs ieee80211/wiphy1/ath10k/set_rate_override for ability
to set data frames to specific txpower, mcs, nss, bandwidth, and retry count.

Should be useful for testing.

Adds ability to display more useful radar info in debugfs as well.

Signed-off-by: Ben Greear <greearb@candelatech.com>
  • Loading branch information
greearb committed Dec 10, 2018
1 parent 6c3a626 commit 9650f5b
Show file tree
Hide file tree
Showing 18 changed files with 579 additions and 51 deletions.
13 changes: 13 additions & 0 deletions ath10k-4.16/core.h
Expand Up @@ -479,6 +479,18 @@ struct ath10k_vif {
bool nohwcrypt; /* actual setting, based on firmware abilities, etc. */
int num_legacy_stations;
int txpower;

/* TX Rate overrides, CT FW only at this time, and only wave-2 has full support */
bool txo_active;
u8 txo_tpc;
u8 txo_mcs;
u8 txo_nss;
u8 txo_pream;
u8 txo_retries;
u8 txo_dynbw;
u8 txo_bw;
u8 txo_rix; /* wave-1 only */

/* Firmware allows configuring rate of each of these traffic types.
* 0xFF will mean value has not been set by user, and in that case,
* we will auto-adjust the rates based on the legacy rate mask.
Expand Down Expand Up @@ -594,6 +606,7 @@ struct ath10k_debug {
u64 tx_noack_bytes;
u64 tx_discard_bytes;
u64 tx_bytes; /* counter, total sent to firmware */
char dfs_last_msg[120];
};

enum ath10k_state {
Expand Down
167 changes: 166 additions & 1 deletion ath10k-4.16/debug.c
Expand Up @@ -1439,6 +1439,165 @@ static const struct file_operations fops_set_rates = {
.llseek = default_llseek,
};


static ssize_t ath10k_read_set_rate_override(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
char* buf2;
int size=8000;
struct ath10k_vif *arvif;
struct ieee80211_vif *vif;
struct wireless_dev *wdev;
int sofar;
int rv;
const char buf[] =
"This allows specify specif tx rate parameters for all DATA frames on a vdev\n"
"Only wave-2 CT firmware has full support. Wave-1 CT firmware has at least\n"
"some support (rix mostly). Wave-2 does not use rix.\n"
"To set a value, you specify the dev-name and key-value pairs:\n"
"tpc=10 mcs=x nss=x pream=x retries=x dynbw=0|1 bw=x rix=x enable=0|1\n"
"pream: 0=ofdm, 1=cck, 2=HT, 3=VHT\n"
"tpc is in 1db increments, 255 means use defaults, bw is 0-3 for 20-160\n"
" For example, wlan0: echo \"wlan0 tpc=255 mcs=0 nss=1 pream=3 retries=1 dynbw=0 bw=0 active=1\" > ...ath10k/set_rate_override\n";

buf2 = kzalloc(size, GFP_KERNEL);
if (buf2 == NULL)
return -ENOMEM;
strcpy(buf2, buf);
sofar = strlen(buf2);

list_for_each_entry(arvif, &ar->arvifs, list) {
vif = arvif->vif;
wdev = ieee80211_vif_to_wdev(vif);

if (!wdev)
continue;

sofar += scnprintf(buf2 + sofar, size - sofar,
"vdev %i(%s) active=%d tpc=%d mcs=%d nss=%d pream=%d retries=%d dynbw=%d bw=%d rix=%d\n",
arvif->vdev_id, wdev->netdev->name,
arvif->txo_active, arvif->txo_tpc, arvif->txo_mcs,
arvif->txo_nss, arvif->txo_pream, arvif->txo_retries, arvif->txo_dynbw,
arvif->txo_bw, arvif->txo_rix);
if (sofar >= size)
break;
}

rv = simple_read_from_buffer(user_buf, count, ppos, buf2, sofar);
kfree(buf2);
return rv;
}

/* Set the rates for specific types of traffic.
*/
static ssize_t ath10k_write_set_rate_override(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
char buf[180];
char tmp[20];
char* tok;
int ret;
struct ath10k_vif *arvif;
struct ieee80211_vif *vif;
unsigned int vdev_id = 0xFFFF;
char* bufptr = buf;
long rc;
char dev_name_match[IFNAMSIZ + 2];
struct wireless_dev *wdev;

memset(buf, 0, sizeof(buf));

simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);

/* make sure that buf is null terminated */
buf[sizeof(buf) - 1] = 0;

/* drop the possible '\n' from the end */
if (buf[count - 1] == '\n')
buf[count - 1] = 0;

mutex_lock(&ar->conf_mutex);

/* Ignore empty lines, 'echo' appends them sometimes at least. */
if (buf[0] == 0) {
ret = count;
goto exit;
}

/* String starts with vdev name, ie 'wlan0' Find the proper vif that
* matches the name.
*/
list_for_each_entry(arvif, &ar->arvifs, list) {
vif = arvif->vif;
wdev = ieee80211_vif_to_wdev(vif);

if (!wdev)
continue;
snprintf(dev_name_match, sizeof(dev_name_match) - 1, "%s ", wdev->netdev->name);
if (strncmp(dev_name_match, buf, strlen(dev_name_match)) == 0) {
vdev_id = arvif->vdev_id;
bufptr = buf + strlen(dev_name_match) - 1;
break;
}
}

if (vdev_id == 0xFFFF) {
ath10k_warn(ar, "set-rate-override, unknown netdev name: %s\n", buf);
ret = -EINVAL;
goto exit;
}

#define ATH10K_PARSE_LTOK(a) \
if ((tok = strstr(bufptr, " " #a "="))) { \
char* tspace; \
tok += 1; /* move past initial space */ \
strncpy(tmp, tok + strlen(#a "="), sizeof(tmp) - 1); \
tmp[sizeof(tmp) - 1] = 0; \
tspace = strstr(tmp, " "); \
if (tspace) { *tspace = 0; } \
if (kstrtol(tmp, 0, &rc) != 0) { \
ath10k_warn(ar, "set-rate-override: " #a "= could not be parsed, tmp: %s\n", tmp); \
} \
else { \
arvif->txo_##a = rc; \
} \
}

ATH10K_PARSE_LTOK(tpc);
ATH10K_PARSE_LTOK(mcs);
ATH10K_PARSE_LTOK(nss);
ATH10K_PARSE_LTOK(pream);
ATH10K_PARSE_LTOK(retries);
ATH10K_PARSE_LTOK(dynbw);
ATH10K_PARSE_LTOK(bw);
ATH10K_PARSE_LTOK(rix);
ATH10K_PARSE_LTOK(active);

ath10k_warn(ar, "set-rate-overrides, vdev %i(%s) active=%d tpc=%d mcs=%d nss=%d pream=%d retries=%d dynbw=%d bw=%d rix=%d\n",
arvif->vdev_id, dev_name_match,
arvif->txo_active, arvif->txo_tpc, arvif->txo_mcs,
arvif->txo_nss, arvif->txo_pream, arvif->txo_retries, arvif->txo_dynbw,
arvif->txo_bw, arvif->txo_rix);

ret = count;

exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}

static const struct file_operations fops_set_rate_override = {
.read = ath10k_read_set_rate_override,
.write = ath10k_write_set_rate_override,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};

static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
Expand Down Expand Up @@ -2790,6 +2949,9 @@ static ssize_t ath10k_read_dfs_stats(struct file *file, char __user *user_buf,
ATH10K_DFS_POOL_STAT("Seqs. alloc error", pseq_alloc_error);
ATH10K_DFS_POOL_STAT("Seqs. in use", pseq_used);

len += scnprintf(buf + len, size - len, "Last-DFS-Msg: %s\n",
ar->debug.dfs_last_msg);

exit:
if (len > size)
len = size;
Expand Down Expand Up @@ -3485,6 +3647,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("set_rates", 0600, ar->debug.debugfs_phy,
ar, &fops_set_rates);

debugfs_create_file("set_rate_override", 0600, ar->debug.debugfs_phy,
ar, &fops_set_rate_override);

debugfs_create_file("firmware_info", 0400, ar->debug.debugfs_phy, ar,
&fops_fwinfo_services);

Expand Down Expand Up @@ -3531,7 +3696,7 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("dfs_simulate_radar", 0200, ar->debug.debugfs_phy,
ar, &fops_simulate_radar);

debugfs_create_bool("dfs_block_radar_events", 0200,
debugfs_create_bool("dfs_block_radar_events", 0644,
ar->debug.debugfs_phy,
&ar->dfs_block_radar_events);

Expand Down
6 changes: 4 additions & 2 deletions ath10k-4.16/htt.h
Expand Up @@ -826,7 +826,8 @@ struct htt_data_tx_completion {
} __packed;
u8 num_msdus;
u8 flag_ack_rssi_filled:1, /* For 10.4 firmware */
flag_reserved:5,
flag_reserved:4,
flag_tx_retries_filled:1, /* CT firmware only currently */
flag_tx_rate_filled:1, /* CT firmware only currently */
flag_reserved2:1;
__le16 msdus[0]; /* variable length based on %num_msdus */
Expand Down Expand Up @@ -1913,7 +1914,8 @@ struct ath10k_htt_tx_ops {
int (*htt_send_frag_desc_bank_cfg)(struct ath10k_htt *htt);
int (*htt_alloc_frag_desc)(struct ath10k_htt *htt);
void (*htt_free_frag_desc)(struct ath10k_htt *htt);
int (*htt_tx)(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
int (*htt_tx)(struct ath10k_htt *htt, struct ieee80211_vif *vif,
enum ath10k_hw_txrx_mode txmode,
struct sk_buff *msdu);
int (*htt_alloc_txbuff)(struct ath10k_htt *htt);
void (*htt_free_txbuff)(struct ath10k_htt *htt);
Expand Down
38 changes: 35 additions & 3 deletions ath10k-4.16/htt_rx.c
Expand Up @@ -1898,10 +1898,11 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
}

ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx completion num_msdus %d status: %d discard: %d no-ack: %d\n",
"htt tx completion num_msdus %d status: %d discard: %d no-ack: %d wmi-op-ver: %d\n",
resp->data_tx_completion.num_msdus, status,
tx_done.status == HTT_TX_COMPL_STATE_DISCARD,
tx_done.status == HTT_TX_COMPL_STATE_NOACK);
tx_done.status == HTT_TX_COMPL_STATE_NOACK,
ar->running_fw->fw_file.wmi_op_version);

if (test_bit(ATH10K_FW_FEATURE_TXRATE_CT,
ar->running_fw->fw_file.fw_features) &&
Expand All @@ -1928,7 +1929,7 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
* of the ath10k-ct wave-1 tx-rate logic.
*/

/*ath10k_warn(ar,
/* ath10k_warn(ar,
"htt tx completion, msdu_id: %d tx-rate-code: 0x%x tx-rate-flags: 0x%x tried: %d failed: %d\n",
tx_done.msdu_id,
tx_done.tx_rate_code,
Expand Down Expand Up @@ -1956,6 +1957,7 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
int storage_idx = (resp->data_tx_completion_ct.num_msdus + 1) & ~1;
__le16 ack_rssi;
__le16 rate_info;
__le16 retries_info;
/* 10.4 firmware may report the ack rssi. If so, it is
* a series of uint16 appended on the end of the report.
* And, 10.4 CT firmware may also report tx-rate, which
Expand All @@ -1974,8 +1976,17 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
goto do_generic;
}

if (resp->data_tx_completion.flag_tx_retries_filled &&
WARN_ON_ONCE(skb->len < ((storage_idx * 4) + sizeof(struct htt_data_tx_completion)))) {
ath10k_err(ar, "Invalid length for tx-retries report, skb->len: %d storage_idx: %d msdu: %d\n",
skb->len, storage_idx, resp->data_tx_completion_ct.num_msdus);
goto do_generic;
}

tx_done.tx_rate_code = 0;
tx_done.tx_rate_flags = 0;
tx_done.mpdus_tried = 0;
tx_done.mpdus_failed = 0;
for (i = 0; i < resp->data_tx_completion_ct.num_msdus; i++) {
msdu_id = resp->data_tx_completion.msdus[i];
tx_done.msdu_id = __le16_to_cpu(msdu_id);
Expand All @@ -1986,7 +1997,28 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
rate_info = __le16_to_cpu(rate_info);
tx_done.tx_rate_code = rate_info >> 8;
tx_done.tx_rate_flags = rate_info & 0xFF;
if (resp->data_tx_completion.flag_tx_retries_filled) {
/* NOTE: It seems that if 'probe' frames in the firmware
* fail, then they will be retried at a lower rate, and because
* the tx rate is different, it is not counted as 'mpdus_failed'
* when finally reporting the tx status here. So, this will
* undercount, at least when using rate-ctrl. I think that using
* a single fixed rate might not see this issue, but that needs
* testing. --Ben
*/
retries_info = resp->data_tx_completion.msdus[storage_idx * 3 + i];
retries_info = __le16_to_cpu(retries_info);
tx_done.mpdus_tried = retries_info & 0xFF;
tx_done.mpdus_failed = retries_info >> 8;
}
}
/* ath10k_warn(ar,
"htt tx completion-w2, msdu_id: %d tx-rate-code: 0x%x tx-rate-flags: 0x%x tried: %d failed: %d\n",
tx_done.msdu_id,
tx_done.tx_rate_code,
tx_done.tx_rate_flags,
tx_done.mpdus_tried,
tx_done.mpdus_failed);*/
ath10k_txrx_tx_unref(htt, &tx_done);
}
} else {
Expand Down

0 comments on commit 9650f5b

Please sign in to comment.