wil6210: add support for link statistics
Driver can request FW to report link statistics using WMI_LINK_STATS_CMDID. FW will report statistics with WMI_LINK_STATS_EVENTID. Two categories of statistics defined: basic and global. New "link_stats" debugfs is used for requesting basic statistics report (write) and for reading the basic statistics (read). "link_stats_global" debugfs is used for requesting and reading the global statistics. Signed-off-by: Dedy Lansky <dlansky@codeaurora.org> Signed-off-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
这个提交包含在:
@@ -1922,6 +1922,223 @@ static const struct file_operations fops_tx_latency = {
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static void wil_link_stats_print_basic(struct wil6210_vif *vif,
|
||||
struct seq_file *s,
|
||||
struct wmi_link_stats_basic *basic)
|
||||
{
|
||||
char per[5] = "?";
|
||||
|
||||
if (basic->per_average != 0xff)
|
||||
snprintf(per, sizeof(per), "%d%%", basic->per_average);
|
||||
|
||||
seq_printf(s, "CID %d {\n"
|
||||
"\tTxMCS %d TxTpt %d\n"
|
||||
"\tGoodput(rx:tx) %d:%d\n"
|
||||
"\tRxBcastFrames %d\n"
|
||||
"\tRSSI %d SQI %d SNR %d PER %s\n"
|
||||
"\tRx RFC %d Ant num %d\n"
|
||||
"\tSectors(rx:tx) my %d:%d peer %d:%d\n"
|
||||
"}\n",
|
||||
basic->cid,
|
||||
basic->bf_mcs, le32_to_cpu(basic->tx_tpt),
|
||||
le32_to_cpu(basic->rx_goodput),
|
||||
le32_to_cpu(basic->tx_goodput),
|
||||
le32_to_cpu(basic->rx_bcast_frames),
|
||||
basic->rssi, basic->sqi, basic->snr, per,
|
||||
basic->selected_rfc, basic->rx_effective_ant_num,
|
||||
basic->my_rx_sector, basic->my_tx_sector,
|
||||
basic->other_rx_sector, basic->other_tx_sector);
|
||||
}
|
||||
|
||||
static void wil_link_stats_print_global(struct wil6210_priv *wil,
|
||||
struct seq_file *s,
|
||||
struct wmi_link_stats_global *global)
|
||||
{
|
||||
seq_printf(s, "Frames(rx:tx) %d:%d\n"
|
||||
"BA Frames(rx:tx) %d:%d\n"
|
||||
"Beacons %d\n"
|
||||
"Rx Errors (MIC:CRC) %d:%d\n"
|
||||
"Tx Errors (no ack) %d\n",
|
||||
le32_to_cpu(global->rx_frames),
|
||||
le32_to_cpu(global->tx_frames),
|
||||
le32_to_cpu(global->rx_ba_frames),
|
||||
le32_to_cpu(global->tx_ba_frames),
|
||||
le32_to_cpu(global->tx_beacons),
|
||||
le32_to_cpu(global->rx_mic_errors),
|
||||
le32_to_cpu(global->rx_crc_errors),
|
||||
le32_to_cpu(global->tx_fail_no_ack));
|
||||
}
|
||||
|
||||
static void wil_link_stats_debugfs_show_vif(struct wil6210_vif *vif,
|
||||
struct seq_file *s)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wmi_link_stats_basic *stats;
|
||||
int i;
|
||||
|
||||
if (!vif->fw_stats_ready) {
|
||||
seq_puts(s, "no statistics\n");
|
||||
return;
|
||||
}
|
||||
|
||||
seq_printf(s, "TSF %lld\n", vif->fw_stats_tsf);
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if (wil->sta[i].status == wil_sta_unused)
|
||||
continue;
|
||||
if (wil->sta[i].mid != vif->mid)
|
||||
continue;
|
||||
|
||||
stats = &wil->sta[i].fw_stats_basic;
|
||||
wil_link_stats_print_basic(vif, s, stats);
|
||||
}
|
||||
}
|
||||
|
||||
static int wil_link_stats_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wil6210_vif *vif;
|
||||
int i, rc;
|
||||
|
||||
rc = mutex_lock_interruptible(&wil->vif_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* iterate over all MIDs and show per-cid statistics. Then show the
|
||||
* global statistics
|
||||
*/
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
|
||||
seq_printf(s, "MID %d ", i);
|
||||
if (!vif) {
|
||||
seq_puts(s, "unused\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
wil_link_stats_debugfs_show_vif(vif, s);
|
||||
}
|
||||
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_link_stats_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_link_stats_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t wil_link_stats_write(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct wil6210_priv *wil = s->private;
|
||||
int cid, interval, rc, i;
|
||||
struct wil6210_vif *vif;
|
||||
char *kbuf = kmalloc(len + 1, GFP_KERNEL);
|
||||
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
|
||||
if (rc != len) {
|
||||
kfree(kbuf);
|
||||
return rc >= 0 ? -EIO : rc;
|
||||
}
|
||||
|
||||
kbuf[len] = '\0';
|
||||
/* specify cid (use -1 for all cids) and snapshot interval in ms */
|
||||
rc = sscanf(kbuf, "%d %d", &cid, &interval);
|
||||
kfree(kbuf);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc < 2 || interval < 0)
|
||||
return -EINVAL;
|
||||
|
||||
wil_info(wil, "request link statistics, cid %d interval %d\n",
|
||||
cid, interval);
|
||||
|
||||
rc = mutex_lock_interruptible(&wil->vif_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (!vif)
|
||||
continue;
|
||||
|
||||
rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_BASIC,
|
||||
(cid == -1 ? 0xff : cid), interval);
|
||||
if (rc)
|
||||
wil_err(wil, "link statistics failed for mid %d\n", i);
|
||||
}
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_link_stats = {
|
||||
.open = wil_link_stats_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.write = wil_link_stats_write,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int
|
||||
wil_link_stats_global_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
|
||||
if (!wil->fw_stats_global.ready)
|
||||
return 0;
|
||||
|
||||
seq_printf(s, "TSF %lld\n", wil->fw_stats_global.tsf);
|
||||
wil_link_stats_print_global(wil, s, &wil->fw_stats_global.stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wil_link_stats_global_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_link_stats_global_debugfs_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
wil_link_stats_global_write(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct wil6210_priv *wil = s->private;
|
||||
int interval, rc;
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
|
||||
/* specify snapshot interval in ms */
|
||||
rc = kstrtoint_from_user(buf, len, 0, &interval);
|
||||
if (rc || interval < 0) {
|
||||
wil_err(wil, "Invalid argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wil_info(wil, "request global link stats, interval %d\n", interval);
|
||||
|
||||
rc = wmi_link_stats_cfg(vif, WMI_LINK_STATS_TYPE_GLOBAL, 0, interval);
|
||||
if (rc)
|
||||
wil_err(wil, "global link stats failed %d\n", rc);
|
||||
|
||||
return rc ? rc : len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_link_stats_global = {
|
||||
.open = wil_link_stats_global_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.write = wil_link_stats_global_write,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -2256,6 +2473,8 @@ static const struct {
|
||||
{"status_msg", 0444, &fops_status_msg},
|
||||
{"rx_buff_mgmt", 0444, &fops_rx_buff_mgmt},
|
||||
{"tx_latency", 0644, &fops_tx_latency},
|
||||
{"link_stats", 0644, &fops_link_stats},
|
||||
{"link_stats_global", 0644, &fops_link_stats_global},
|
||||
};
|
||||
|
||||
static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
|
||||
|
@@ -728,6 +728,7 @@ struct wil_sta_info {
|
||||
* tx_latency_res is configured from "tx_latency" debug-fs.
|
||||
*/
|
||||
u64 *tx_latency_bins;
|
||||
struct wmi_link_stats_basic fw_stats_basic;
|
||||
/* Rx BACK */
|
||||
struct wil_tid_ampdu_rx *tid_rx[WIL_STA_TID_NUM];
|
||||
spinlock_t tid_rx_lock; /* guarding tid_rx array */
|
||||
@@ -842,6 +843,8 @@ struct wil6210_vif {
|
||||
struct mutex probe_client_mutex; /* protect @probe_client_pending */
|
||||
struct work_struct probe_client_worker;
|
||||
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
|
||||
bool fw_stats_ready; /* per-cid statistics are ready inside sta_info */
|
||||
u64 fw_stats_tsf; /* measurement timestamp */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -869,6 +872,12 @@ struct wil_rx_buff_mgmt {
|
||||
unsigned long free_list_empty_cnt; /* statistics */
|
||||
};
|
||||
|
||||
struct wil_fw_stats_global {
|
||||
bool ready;
|
||||
u64 tsf; /* measurement timestamp */
|
||||
struct wmi_link_stats_global stats;
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
u32 bar_size;
|
||||
@@ -1002,6 +1011,8 @@ struct wil6210_priv {
|
||||
bool use_rx_hw_reordering;
|
||||
bool secured_boot;
|
||||
u8 boot_config;
|
||||
|
||||
struct wil_fw_stats_global fw_stats_global;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wiphy)
|
||||
@@ -1201,6 +1212,7 @@ int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid);
|
||||
int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
|
||||
const u8 *mac, enum nl80211_iftype iftype);
|
||||
int wmi_port_delete(struct wil6210_priv *wil, u8 mid);
|
||||
int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval);
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
|
||||
u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl);
|
||||
|
@@ -464,6 +464,8 @@ static const char *cmdid2name(u16 cmdid)
|
||||
return "WMI_BCAST_DESC_RING_ADD_CMD";
|
||||
case WMI_CFG_DEF_RX_OFFLOAD_CMDID:
|
||||
return "WMI_CFG_DEF_RX_OFFLOAD_CMD";
|
||||
case WMI_LINK_STATS_CMDID:
|
||||
return "WMI_LINK_STATS_CMD";
|
||||
default:
|
||||
return "Untracked CMD";
|
||||
}
|
||||
@@ -598,6 +600,10 @@ static const char *eventid2name(u16 eventid)
|
||||
return "WMI_RX_DESC_RING_CFG_DONE_EVENT";
|
||||
case WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENTID:
|
||||
return "WMI_CFG_DEF_RX_OFFLOAD_DONE_EVENT";
|
||||
case WMI_LINK_STATS_CONFIG_DONE_EVENTID:
|
||||
return "WMI_LINK_STATS_CONFIG_DONE_EVENT";
|
||||
case WMI_LINK_STATS_EVENTID:
|
||||
return "WMI_LINK_STATS_EVENT";
|
||||
default:
|
||||
return "Untracked EVENT";
|
||||
}
|
||||
@@ -1329,6 +1335,130 @@ wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
cfg80211_sched_scan_results(wiphy, 0);
|
||||
}
|
||||
|
||||
static void wil_link_stats_store_basic(struct wil6210_vif *vif,
|
||||
struct wmi_link_stats_basic *basic)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
u8 cid = basic->cid;
|
||||
struct wil_sta_info *sta;
|
||||
|
||||
if (cid < 0 || cid >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "invalid cid %d\n", cid);
|
||||
return;
|
||||
}
|
||||
|
||||
sta = &wil->sta[cid];
|
||||
sta->fw_stats_basic = *basic;
|
||||
}
|
||||
|
||||
static void wil_link_stats_store_global(struct wil6210_vif *vif,
|
||||
struct wmi_link_stats_global *global)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
|
||||
wil->fw_stats_global.stats = *global;
|
||||
}
|
||||
|
||||
static void wmi_link_stats_parse(struct wil6210_vif *vif, u64 tsf,
|
||||
bool has_next, void *payload,
|
||||
size_t payload_size)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
size_t hdr_size = sizeof(struct wmi_link_stats_record);
|
||||
size_t stats_size, record_size, expected_size;
|
||||
struct wmi_link_stats_record *hdr;
|
||||
|
||||
if (payload_size < hdr_size) {
|
||||
wil_err(wil, "link stats wrong event size %zu\n", payload_size);
|
||||
return;
|
||||
}
|
||||
|
||||
while (payload_size >= hdr_size) {
|
||||
hdr = payload;
|
||||
stats_size = le16_to_cpu(hdr->record_size);
|
||||
record_size = hdr_size + stats_size;
|
||||
|
||||
if (payload_size < record_size) {
|
||||
wil_err(wil, "link stats payload ended unexpectedly, size %zu < %zu\n",
|
||||
payload_size, record_size);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (hdr->record_type_id) {
|
||||
case WMI_LINK_STATS_TYPE_BASIC:
|
||||
expected_size = sizeof(struct wmi_link_stats_basic);
|
||||
if (stats_size < expected_size) {
|
||||
wil_err(wil, "link stats invalid basic record size %zu < %zu\n",
|
||||
stats_size, expected_size);
|
||||
return;
|
||||
}
|
||||
if (vif->fw_stats_ready) {
|
||||
/* clean old statistics */
|
||||
vif->fw_stats_tsf = 0;
|
||||
vif->fw_stats_ready = 0;
|
||||
}
|
||||
|
||||
wil_link_stats_store_basic(vif, payload + hdr_size);
|
||||
|
||||
if (!has_next) {
|
||||
vif->fw_stats_tsf = tsf;
|
||||
vif->fw_stats_ready = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
case WMI_LINK_STATS_TYPE_GLOBAL:
|
||||
expected_size = sizeof(struct wmi_link_stats_global);
|
||||
if (stats_size < sizeof(struct wmi_link_stats_global)) {
|
||||
wil_err(wil, "link stats invalid global record size %zu < %zu\n",
|
||||
stats_size, expected_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wil->fw_stats_global.ready) {
|
||||
/* clean old statistics */
|
||||
wil->fw_stats_global.tsf = 0;
|
||||
wil->fw_stats_global.ready = 0;
|
||||
}
|
||||
|
||||
wil_link_stats_store_global(vif, payload + hdr_size);
|
||||
|
||||
if (!has_next) {
|
||||
wil->fw_stats_global.tsf = tsf;
|
||||
wil->fw_stats_global.ready = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* skip to next record */
|
||||
payload += record_size;
|
||||
payload_size -= record_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wmi_link_stats_event *evt = d;
|
||||
size_t payload_size;
|
||||
|
||||
if (len < offsetof(struct wmi_link_stats_event, payload)) {
|
||||
wil_err(wil, "stats event way too short %d\n", len);
|
||||
return;
|
||||
}
|
||||
payload_size = le16_to_cpu(evt->payload_size);
|
||||
if (len < sizeof(struct wmi_link_stats_event) + payload_size) {
|
||||
wil_err(wil, "stats event too short %d\n", len);
|
||||
return;
|
||||
}
|
||||
|
||||
wmi_link_stats_parse(vif, le64_to_cpu(evt->tsf), evt->has_next,
|
||||
evt->payload, payload_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some events are ignored for purpose; and need not be interpreted as
|
||||
* "unhandled events"
|
||||
@@ -1359,6 +1489,7 @@ static const struct {
|
||||
{WMI_RING_EN_EVENTID, wmi_evt_ring_en},
|
||||
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_ignore},
|
||||
{WMI_SCHED_SCAN_RESULT_EVENTID, wmi_evt_sched_scan_result},
|
||||
{WMI_LINK_STATS_EVENTID, wmi_evt_link_stats},
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -3242,3 +3373,37 @@ int wil_wmi_bcast_desc_ring_add(struct wil6210_vif *vif, int ring_id)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wmi_link_stats_cmd cmd = {
|
||||
.record_type_mask = cpu_to_le32(type),
|
||||
.cid = cid,
|
||||
.action = WMI_LINK_STATS_SNAPSHOT,
|
||||
.interval_msec = cpu_to_le32(interval),
|
||||
};
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_link_stats_config_done_event evt;
|
||||
} __packed reply = {
|
||||
.evt = {.status = WMI_FW_STATUS_FAILURE},
|
||||
};
|
||||
int rc;
|
||||
|
||||
rc = wmi_call(wil, WMI_LINK_STATS_CMDID, vif->mid, &cmd, sizeof(cmd),
|
||||
WMI_LINK_STATS_CONFIG_DONE_EVENTID, &reply,
|
||||
sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS);
|
||||
if (rc) {
|
||||
wil_err(wil, "WMI_LINK_STATS_CMDID failed, rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (reply.evt.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "Link statistics config failed, status %d\n",
|
||||
reply.evt.status);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1715,9 +1715,7 @@ enum wmi_link_stats_action {
|
||||
/* WMI_LINK_STATS_EVENT record identifiers */
|
||||
enum wmi_link_stats_record_type {
|
||||
WMI_LINK_STATS_TYPE_BASIC = 0x01,
|
||||
WMI_LINK_STATS_TYPE_MAC = 0x02,
|
||||
WMI_LINK_STATS_TYPE_PHY = 0x04,
|
||||
WMI_LINK_STATS_TYPE_OTA = 0x08,
|
||||
WMI_LINK_STATS_TYPE_GLOBAL = 0x02,
|
||||
};
|
||||
|
||||
/* WMI_LINK_STATS_CMDID */
|
||||
@@ -1731,7 +1729,7 @@ struct wmi_link_stats_cmd {
|
||||
/* wmi_link_stats_action_e */
|
||||
u8 action;
|
||||
u8 reserved[6];
|
||||
/* for WMI_LINK_STATS_PERIODIC */
|
||||
/* range = 100 - 10000 */
|
||||
__le32 interval_msec;
|
||||
} __packed;
|
||||
|
||||
@@ -3779,32 +3777,59 @@ struct wmi_link_stats_config_done_event {
|
||||
|
||||
/* WMI_LINK_STATS_EVENTID */
|
||||
struct wmi_link_stats_event {
|
||||
__le64 tsf;
|
||||
__le16 payload_size;
|
||||
u8 has_next;
|
||||
u8 reserved[5];
|
||||
/* a stream of records, e.g. wmi_link_stats_basic_s */
|
||||
/* a stream of wmi_link_stats_record_s */
|
||||
u8 payload[0];
|
||||
} __packed;
|
||||
|
||||
/* WMI_LINK_STATS_EVENT record struct */
|
||||
struct wmi_link_stats_basic {
|
||||
/* WMI_LINK_STATS_TYPE_BASIC */
|
||||
/* WMI_LINK_STATS_EVENT */
|
||||
struct wmi_link_stats_record {
|
||||
/* wmi_link_stats_record_type_e */
|
||||
u8 record_type_id;
|
||||
u8 reserved;
|
||||
__le16 record_size;
|
||||
u8 record[0];
|
||||
} __packed;
|
||||
|
||||
/* WMI_LINK_STATS_TYPE_BASIC */
|
||||
struct wmi_link_stats_basic {
|
||||
u8 cid;
|
||||
/* 0: fail; 1: OK; 2: retrying */
|
||||
u8 bf_status;
|
||||
s8 rssi;
|
||||
u8 sqi;
|
||||
u8 bf_mcs;
|
||||
u8 per_average;
|
||||
u8 selected_rfc;
|
||||
__le16 bf_mcs;
|
||||
u8 rx_effective_ant_num;
|
||||
u8 my_rx_sector;
|
||||
u8 my_tx_sector;
|
||||
u8 other_rx_sector;
|
||||
u8 other_tx_sector;
|
||||
u8 reserved[7];
|
||||
/* 1/4 Db units */
|
||||
__le16 snr;
|
||||
__le32 tx_tpt;
|
||||
__le32 tx_goodput;
|
||||
__le32 rx_goodput;
|
||||
__le16 my_rx_sector;
|
||||
__le16 my_tx_sector;
|
||||
__le16 other_rx_sector;
|
||||
__le16 other_tx_sector;
|
||||
__le32 reserved[2];
|
||||
__le32 bf_count;
|
||||
__le32 rx_bcast_frames;
|
||||
} __packed;
|
||||
|
||||
/* WMI_LINK_STATS_TYPE_GLOBAL */
|
||||
struct wmi_link_stats_global {
|
||||
/* all ack-able frames */
|
||||
__le32 rx_frames;
|
||||
/* all ack-able frames */
|
||||
__le32 tx_frames;
|
||||
__le32 rx_ba_frames;
|
||||
__le32 tx_ba_frames;
|
||||
__le32 tx_beacons;
|
||||
__le32 rx_mic_errors;
|
||||
__le32 rx_crc_errors;
|
||||
__le32 tx_fail_no_ack;
|
||||
u8 reserved[8];
|
||||
} __packed;
|
||||
|
||||
/* WMI_SET_GRANT_MCS_EVENTID */
|
||||
|
在新工单中引用
屏蔽一个用户