Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for 4.19. Major changes:

ath10k

* add debugfs file warm_hw_reset

wil6210

* add debugfs files tx_latency, link_stats and link_stats_global

* add 3-MSI support

* allow scan on AP interface

* support max aggregation window size 64
This commit is contained in:
Kalle Valo 2018-08-06 12:34:43 +03:00
commit 33c740411a
37 changed files with 2046 additions and 205 deletions

View File

@ -133,11 +133,8 @@ static void ath10k_ahb_clock_deinit(struct ath10k *ar)
static int ath10k_ahb_clock_enable(struct ath10k *ar)
{
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
struct device *dev;
int ret;
dev = &ar_ahb->pdev->dev;
if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) ||
IS_ERR_OR_NULL(ar_ahb->ref_clk) ||
IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
@ -451,12 +448,10 @@ static int ath10k_ahb_resource_init(struct ath10k *ar)
{
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
struct platform_device *pdev;
struct device *dev;
struct resource *res;
int ret;
pdev = ar_ahb->pdev;
dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {

View File

@ -2095,6 +2095,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |
WMI_STAT_PEER;
ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;
ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC;
break;
case ATH10K_FW_WMI_OP_VERSION_10_4:
ar->max_num_peers = TARGET_10_4_NUM_PEERS;

View File

@ -186,6 +186,11 @@ struct ath10k_wmi {
const struct wmi_ops *ops;
const struct wmi_peer_flags_map *peer_flags;
u32 mgmt_max_num_pending_tx;
/* Protected by data_lock */
struct idr mgmt_pending_tx;
u32 num_mem_chunks;
u32 rx_decap_mode;
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];

View File

@ -2297,6 +2297,52 @@ static const struct file_operations fops_tpc_stats_final = {
.llseek = default_llseek,
};
static ssize_t ath10k_write_warm_hw_reset(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
int ret;
bool val;
if (kstrtobool_from_user(user_buf, count, &val))
return -EFAULT;
if (!val)
return -EINVAL;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON) {
ret = -ENETDOWN;
goto exit;
}
if (!(test_bit(WMI_SERVICE_RESET_CHIP, ar->wmi.svc_map)))
ath10k_warn(ar, "wmi service for reset chip is not available\n");
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pdev_reset,
WMI_RST_MODE_WARM_RESET);
if (ret) {
ath10k_warn(ar, "failed to enable warm hw reset: %d\n", ret);
goto exit;
}
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_warm_hw_reset = {
.write = ath10k_write_warm_hw_reset,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_create(struct ath10k *ar)
{
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
@ -2425,6 +2471,9 @@ int ath10k_debug_register(struct ath10k *ar)
ar->debug.debugfs_phy, ar,
&fops_tpc_stats_final);
debugfs_create_file("warm_hw_reset", 0600, ar->debug.debugfs_phy, ar,
&fops_warm_hw_reset);
return 0;
}

View File

@ -208,10 +208,10 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
struct ath10k *ar = htt->ar;
int ret;
lockdep_assert_held(&htt->tx_lock);
spin_lock_bh(&htt->tx_lock);
ret = idr_alloc(&htt->pending_tx, skb, 0,
htt->max_num_pending_tx, GFP_ATOMIC);
spin_unlock_bh(&htt->tx_lock);
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret);
@ -1077,9 +1077,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
len += sizeof(cmd->hdr);
len += sizeof(cmd->mgmt_tx);
spin_lock_bh(&htt->tx_lock);
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
spin_unlock_bh(&htt->tx_lock);
if (res < 0)
goto err;
@ -1161,9 +1159,7 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt,
struct htt_msdu_ext_desc *ext_desc = NULL;
struct htt_msdu_ext_desc *ext_desc_t = NULL;
spin_lock_bh(&htt->tx_lock);
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
spin_unlock_bh(&htt->tx_lock);
if (res < 0)
goto err;
@ -1363,9 +1359,7 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt,
struct htt_msdu_ext_desc_64 *ext_desc = NULL;
struct htt_msdu_ext_desc_64 *ext_desc_t = NULL;
spin_lock_bh(&htt->tx_lock);
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
spin_unlock_bh(&htt->tx_lock);
if (res < 0)
goto err;

View File

@ -699,6 +699,7 @@ ath10k_rx_desc_get_l3_pad_bytes(struct ath10k_hw_params *hw,
#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
#define TARGET_TLV_NUM_WOW_PATTERNS 22
#define TARGET_TLV_MGMT_NUM_MSDU_DESC (50)
/* Target specific defines for WMI-HL-1.0 firmware */
#define TARGET_HL_10_TLV_NUM_PEERS 14

View File

@ -101,6 +101,8 @@ static struct ieee80211_rate ath10k_rates_rev2[] = {
#define ath10k_g_rates_rev2 (ath10k_rates_rev2 + 0)
#define ath10k_g_rates_rev2_size (ARRAY_SIZE(ath10k_rates_rev2))
#define ath10k_wmi_legacy_rates ath10k_rates
static bool ath10k_mac_bitrate_is_cck(int bitrate)
{
switch (bitrate) {
@ -3085,6 +3087,13 @@ static int ath10k_update_channel_list(struct ath10k *ar)
passive = channel->flags & IEEE80211_CHAN_NO_IR;
ch->passive = passive;
/* the firmware is ignoring the "radar" flag of the
* channel and is scanning actively using Probe Requests
* on "Radar detection"/DFS channels which are not
* marked as "available"
*/
ch->passive |= ch->chan_radar;
ch->freq = channel->center_freq;
ch->band_center_freq1 = channel->center_freq;
ch->min_power = 0;
@ -5439,8 +5448,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
int ret = 0;
struct cfg80211_chan_def def;
u32 vdev_param, pdev_param, slottime, preamble;
u16 bitrate, hw_value;
u8 rate;
int rateidx, ret = 0;
enum nl80211_band band;
mutex_lock(&ar->conf_mutex);
@ -5608,6 +5621,44 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
}
if (changed & BSS_CHANGED_MCAST_RATE &&
!WARN_ON(ath10k_mac_vif_chan(arvif->vif, &def))) {
band = def.chan->band;
rateidx = vif->bss_conf.mcast_rate[band] - 1;
if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
rateidx += ATH10K_MAC_FIRST_OFDM_RATE_IDX;
bitrate = ath10k_wmi_legacy_rates[rateidx].bitrate;
hw_value = ath10k_wmi_legacy_rates[rateidx].hw_value;
if (ath10k_mac_bitrate_is_cck(bitrate))
preamble = WMI_RATE_PREAMBLE_CCK;
else
preamble = WMI_RATE_PREAMBLE_OFDM;
rate = ATH10K_HW_RATECODE(hw_value, 0, preamble);
ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d mcast_rate %x\n",
arvif->vdev_id, rate);
vdev_param = ar->wmi.vdev_param->mcast_data_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, rate);
if (ret)
ath10k_warn(ar,
"failed to set mcast rate on vdev %i: %d\n",
arvif->vdev_id, ret);
vdev_param = ar->wmi.vdev_param->bcast_data_rate;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
vdev_param, rate);
if (ret)
ath10k_warn(ar,
"failed to set bcast rate on vdev %i: %d\n",
arvif->vdev_id, ret);
}
mutex_unlock(&ar->conf_mutex);
}
@ -6063,13 +6114,13 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
mode = chan_to_phymode(&def);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n",
sta->addr, bw, mode);
sta->addr, bw, mode);
err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr,
WMI_PEER_PHYMODE, mode);
WMI_PEER_PHYMODE, mode);
if (err) {
ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n",
sta->addr, mode, err);
sta->addr, mode, err);
goto exit;
}
@ -6935,7 +6986,6 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
const struct cfg80211_bitrate_mask *mask,
u8 *rate, u8 *nss)
{
struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
int rate_idx;
int i;
u16 bitrate;
@ -6945,8 +6995,11 @@ ath10k_mac_bitrate_mask_get_single_rate(struct ath10k *ar,
if (hweight32(mask->control[band].legacy) == 1) {
rate_idx = ffs(mask->control[band].legacy) - 1;
hw_rate = sband->bitrates[rate_idx].hw_value;
bitrate = sband->bitrates[rate_idx].bitrate;
if (ar->phy_capability & WHAL_WLAN_11A_CAPABILITY)
rate_idx += ATH10K_MAC_FIRST_OFDM_RATE_IDX;
hw_rate = ath10k_wmi_legacy_rates[rate_idx].hw_value;
bitrate = ath10k_wmi_legacy_rates[rate_idx].bitrate;
if (ath10k_mac_bitrate_is_cck(bitrate))
preamble = WMI_RATE_PREAMBLE_CCK;

View File

@ -31,6 +31,8 @@ struct wmi_ops {
struct wmi_scan_ev_arg *arg);
int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb,
struct wmi_mgmt_rx_ev_arg *arg);
int (*pull_mgmt_tx_compl)(struct ath10k *ar, struct sk_buff *skb,
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg);
int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
struct wmi_ch_info_ev_arg *arg);
int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
@ -261,6 +263,16 @@ ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb,
return ar->wmi.ops->pull_scan(ar, skb, arg);
}
static inline int
ath10k_wmi_pull_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb,
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg)
{
if (!ar->wmi.ops->pull_mgmt_tx_compl)
return -EOPNOTSUPP;
return ar->wmi.ops->pull_mgmt_tx_compl(ar, skb, arg);
}
static inline int
ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
struct wmi_mgmt_rx_ev_arg *arg)

View File

@ -618,6 +618,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_TLV_TDLS_PEER_EVENTID:
ath10k_wmi_event_tdls_peer(ar, skb);
break;
case WMI_TLV_MGMT_TX_COMPLETION_EVENTID:
ath10k_wmi_event_mgmt_tx_compl(ar, skb);
break;
default:
ath10k_warn(ar, "Unknown eventid: %d\n", id);
break;
@ -659,6 +662,31 @@ static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar,
return 0;
}
static int
ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev(struct ath10k *ar, struct sk_buff *skb,
struct wmi_tlv_mgmt_tx_compl_ev_arg *arg)
{
const void **tb;
const struct wmi_tlv_mgmt_tx_compl_ev *ev;
int ret;
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
if (IS_ERR(tb)) {
ret = PTR_ERR(tb);
ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
return ret;
}
ev = tb[WMI_TLV_TAG_STRUCT_MGMT_TX_COMPL_EVENT];
arg->desc_id = ev->desc_id;
arg->status = ev->status;
arg->pdev_id = ev->pdev_id;
kfree(tb);
return 0;
}
static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
struct sk_buff *skb,
struct wmi_mgmt_rx_ev_arg *arg)
@ -1586,6 +1614,11 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
cfg->keep_alive_pattern_size = __cpu_to_le32(0);
cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1);
cfg->wmi_send_separate = __cpu_to_le32(0);
cfg->num_ocb_vdevs = __cpu_to_le32(0);
cfg->num_ocb_channels = __cpu_to_le32(0);
cfg->num_ocb_schedules = __cpu_to_le32(0);
cfg->host_capab = __cpu_to_le32(0);
ath10k_wmi_put_host_mem_chunks(ar, chunks);
@ -1787,7 +1820,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
{
struct wmi_tlv_vdev_start_cmd *cmd;
struct wmi_channel *ch;
struct wmi_p2p_noa_descriptor *noa;
struct wmi_tlv *tlv;
struct sk_buff *skb;
size_t len;
@ -1845,7 +1877,6 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
tlv = ptr;
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
tlv->len = 0;
noa = (void *)tlv->value;
/* Note: This is a nested TLV containing:
* [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
@ -2607,6 +2638,30 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
return skb;
}
static int
ath10k_wmi_mgmt_tx_alloc_msdu_id(struct ath10k *ar, struct sk_buff *skb,
dma_addr_t paddr)
{
struct ath10k_wmi *wmi = &ar->wmi;
struct ath10k_mgmt_tx_pkt_addr *pkt_addr;
int ret;
pkt_addr = kmalloc(sizeof(*pkt_addr), GFP_ATOMIC);
if (!pkt_addr)
return -ENOMEM;
pkt_addr->vaddr = skb;
pkt_addr->paddr = paddr;
spin_lock_bh(&ar->data_lock);
ret = idr_alloc(&wmi->mgmt_pending_tx, pkt_addr, 0,
wmi->mgmt_max_num_pending_tx, GFP_ATOMIC);
spin_unlock_bh(&ar->data_lock);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx alloc msdu_id ret %d\n", ret);
return ret;
}
static struct sk_buff *
ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
dma_addr_t paddr)
@ -2618,9 +2673,9 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
u32 buf_len = msdu->len;
struct wmi_tlv *tlv;
struct sk_buff *skb;
int len, desc_id;
u32 vdev_id;
void *ptr;
int len;
if (!cb->vif)
return ERR_PTR(-EINVAL);
@ -2651,13 +2706,17 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
if (!skb)
return ERR_PTR(-ENOMEM);
desc_id = ath10k_wmi_mgmt_tx_alloc_msdu_id(ar, msdu, paddr);
if (desc_id < 0)
goto err_free_skb;
ptr = (void *)skb->data;
tlv = ptr;
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_MGMT_TX_CMD);
tlv->len = __cpu_to_le16(sizeof(*cmd));
cmd = (void *)tlv->value;
cmd->vdev_id = __cpu_to_le32(vdev_id);
cmd->desc_id = 0;
cmd->desc_id = __cpu_to_le32(desc_id);
cmd->chanfreq = 0;
cmd->buf_len = __cpu_to_le32(buf_len);
cmd->frame_len = __cpu_to_le32(msdu->len);
@ -2674,6 +2733,10 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
memcpy(ptr, msdu->data, buf_len);
return skb;
err_free_skb:
dev_kfree_skb(skb);
return ERR_PTR(desc_id);
}
static struct sk_buff *
@ -2702,7 +2765,8 @@ ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
static struct sk_buff *
ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u64 module_enable,
u32 log_level) {
u32 log_level)
{
struct wmi_tlv_dbglog_cmd *cmd;
struct wmi_tlv *tlv;
struct sk_buff *skb;
@ -3837,6 +3901,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
.pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
.pull_mgmt_tx_compl = ath10k_wmi_tlv_op_pull_mgmt_tx_compl_ev,
.pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
.pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
.pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,

View File

@ -320,6 +320,7 @@ enum wmi_tlv_event_id {
WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID,
WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
WMI_TLV_MGMT_TX_COMPLETION_EVENTID,
WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG),
WMI_TLV_TX_ADDBA_COMPLETE_EVENTID,
WMI_TLV_BA_RSP_SSN_EVENTID,
@ -1573,6 +1574,17 @@ struct wmi_tlv {
u8 value[0];
} __packed;
struct ath10k_mgmt_tx_pkt_addr {
void *vaddr;
dma_addr_t paddr;
};
struct wmi_tlv_mgmt_tx_compl_ev {
__le32 desc_id;
__le32 status;
__le32 pdev_id;
};
#define WMI_TLV_MGMT_RX_NUM_RSSI 4
struct wmi_tlv_mgmt_rx_ev {
@ -1670,6 +1682,11 @@ struct wmi_tlv_resource_config {
__le32 keep_alive_pattern_size;
__le32 max_tdls_concurrent_sleep_sta;
__le32 max_tdls_concurrent_buffer_sta;
__le32 wmi_send_separate;
__le32 num_ocb_vdevs;
__le32 num_ocb_channels;
__le32 num_ocb_schedules;
__le32 host_capab;
} __packed;
struct wmi_tlv_init_cmd {

View File

@ -1333,7 +1333,7 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
.enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED,
.cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED,
.rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED,
.pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED,
.pdev_reset = WMI_10X_PDEV_PARAM_PDEV_RESET,
.wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED,
.arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED,
.arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED,
@ -2313,6 +2313,59 @@ static bool ath10k_wmi_rx_is_decrypted(struct ath10k *ar,
return true;
}
static int wmi_process_mgmt_tx_comp(struct ath10k *ar, u32 desc_id,
u32 status)
{
struct ath10k_mgmt_tx_pkt_addr *pkt_addr;
struct ath10k_wmi *wmi = &ar->wmi;
struct ieee80211_tx_info *info;
struct sk_buff *msdu;
int ret;
spin_lock_bh(&ar->data_lock);
pkt_addr = idr_find(&wmi->mgmt_pending_tx, desc_id);
if (!pkt_addr) {
ath10k_warn(ar, "received mgmt tx completion for invalid msdu_id: %d\n",
desc_id);
ret = -ENOENT;
goto out;
}
msdu = pkt_addr->vaddr;
dma_unmap_single(ar->dev, pkt_addr->paddr,
msdu->len, DMA_FROM_DEVICE);
info = IEEE80211_SKB_CB(msdu);
info->flags |= status;
ieee80211_tx_status_irqsafe(ar->hw, msdu);
ret = 0;
out:
idr_remove(&wmi->mgmt_pending_tx, desc_id);
spin_unlock_bh(&ar->data_lock);
return ret;
}
int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_tlv_mgmt_tx_compl_ev_arg arg;
int ret;
ret = ath10k_wmi_pull_mgmt_tx_compl(ar, skb, &arg);
if (ret) {
ath10k_warn(ar, "failed to parse mgmt comp event: %d\n", ret);
return ret;
}
wmi_process_mgmt_tx_comp(ar, __le32_to_cpu(arg.desc_id),
__le32_to_cpu(arg.status));
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv evnt mgmt tx completion\n");
return 0;
}
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_mgmt_rx_ev_arg arg = {};
@ -9073,6 +9126,11 @@ int ath10k_wmi_attach(struct ath10k *ar)
INIT_WORK(&ar->radar_confirmation_work,
ath10k_radar_confirmation_work);
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
ar->running_fw->fw_file.fw_features)) {
idr_init(&ar->wmi.mgmt_pending_tx);
}
return 0;
}
@ -9091,8 +9149,35 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar)
ar->wmi.num_mem_chunks = 0;
}
static int ath10k_wmi_mgmt_tx_clean_up_pending(int msdu_id, void *ptr,
void *ctx)
{
struct ath10k_mgmt_tx_pkt_addr *pkt_addr = ptr;
struct ath10k *ar = ctx;
struct sk_buff *msdu;
ath10k_dbg(ar, ATH10K_DBG_WMI,
"force cleanup mgmt msdu_id %hu\n", msdu_id);
msdu = pkt_addr->vaddr;
dma_unmap_single(ar->dev, pkt_addr->paddr,
msdu->len, DMA_FROM_DEVICE);
ieee80211_free_txskb(ar->hw, msdu);
return 0;
}
void ath10k_wmi_detach(struct ath10k *ar)
{
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
ar->running_fw->fw_file.fw_features)) {
spin_lock_bh(&ar->data_lock);
idr_for_each(&ar->wmi.mgmt_pending_tx,
ath10k_wmi_mgmt_tx_clean_up_pending, ar);
idr_destroy(&ar->wmi.mgmt_pending_tx);
spin_unlock_bh(&ar->data_lock);
}
cancel_work_sync(&ar->svc_rdy_work);
if (ar->svc_rdy_skb)

View File

@ -462,6 +462,7 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
SVCSTR(WMI_SERVICE_RESET_CHIP);
default:
return NULL;
}
@ -3934,7 +3935,11 @@ enum wmi_10x_pdev_param {
WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE,
WMI_10X_PDEV_PARAM_RTS_FIXED_RATE,
WMI_10X_PDEV_PARAM_CAL_PERIOD
WMI_10X_PDEV_PARAM_CAL_PERIOD,
WMI_10X_PDEV_PARAM_ATF_STRICT_SCH,
WMI_10X_PDEV_PARAM_ATF_SCHED_DURATION,
WMI_10X_PDEV_PARAM_SET_PROMISC_MODE_CMDID,
WMI_10X_PDEV_PARAM_PDEV_RESET
};
enum wmi_10_4_pdev_param {
@ -6501,6 +6506,15 @@ struct wmi_force_fw_hang_cmd {
__le32 delay_ms;
} __packed;
enum wmi_pdev_reset_mode_type {
WMI_RST_MODE_TX_FLUSH = 1,
WMI_RST_MODE_WARM_RESET,
WMI_RST_MODE_COLD_RESET,
WMI_RST_MODE_WARM_RESET_RESTORE_CAL,
WMI_RST_MODE_COLD_RESET_RESTORE_CAL,
WMI_RST_MODE_MAX,
};
enum ath10k_dbglog_level {
ATH10K_DBGLOG_LEVEL_VERBOSE = 0,
ATH10K_DBGLOG_LEVEL_INFO = 1,
@ -6600,6 +6614,12 @@ struct wmi_scan_ev_arg {
__le32 vdev_id;
};
struct wmi_tlv_mgmt_tx_compl_ev_arg {
__le32 desc_id;
__le32 status;
__le32 pdev_id;
};
struct wmi_mgmt_rx_ev_arg {
__le32 channel;
__le32 snr;
@ -7071,6 +7091,7 @@ int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_event_mgmt_tx_compl(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);

View File

@ -483,7 +483,6 @@ static u32
ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
{
u32 mix, step;
u32 *rf;
const struct ath5k_gain_opt *go;
const struct ath5k_gain_opt_step *g_step;
const struct ath5k_rf_reg *rf_regs;
@ -502,7 +501,6 @@ ath5k_hw_rf_gainf_corr(struct ath5k_hw *ah)
if (ah->ah_rf_banks == NULL)
return 0;
rf = ah->ah_rf_banks;
ah->ah_gain.g_f_corr = 0;
/* No VGA (Variable Gain Amplifier) override, skip */
@ -549,13 +547,10 @@ ath5k_hw_rf_check_gainf_readback(struct ath5k_hw *ah)
{
const struct ath5k_rf_reg *rf_regs;
u32 step, mix_ovr, level[4];
u32 *rf;
if (ah->ah_rf_banks == NULL)
return false;
rf = ah->ah_rf_banks;
if (ah->ah_radio == AR5K_RF5111) {
rf_regs = rf_regs_5111;

View File

@ -534,7 +534,7 @@ int ath6kl_bmi_init(struct ath6kl *ar)
/* cmd + addr + len + data_size */
ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);
ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC);
ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_KERNEL);
if (!ar->bmi.cmd_buf)
return -ENOMEM;

View File

@ -746,10 +746,8 @@ static int ath6kl_htc_pipe_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
struct htc_endpoint *ep;
struct htc_packet *packet;
u8 ep_id, *netdata;
u32 netlen;
netdata = skb->data;
netlen = skb->len;
htc_hdr = (struct htc_frame_hdr *) netdata;
@ -855,12 +853,8 @@ static int htc_process_trailer(struct htc_target *target, u8 *buffer,
{
struct htc_credit_report *report;
struct htc_record_hdr *record;
u8 *record_buf, *orig_buf;
int orig_len, status;
orig_buf = buffer;
orig_len = len;
status = 0;
u8 *record_buf;
int status = 0;
while (len > 0) {
if (len < sizeof(struct htc_record_hdr)) {

View File

@ -272,7 +272,7 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
{
struct ath6kl_dbglog_hdr debug_hdr;
struct ath6kl_dbglog_buf debug_buf;
u32 address, length, dropped, firstbuf, debug_hdr_addr;
u32 address, length, firstbuf, debug_hdr_addr;
int ret, loop;
u8 *buf;
@ -303,7 +303,6 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
address = TARG_VTOP(ar->target_type,
le32_to_cpu(debug_hdr.dbuf_addr));
firstbuf = address;
dropped = le32_to_cpu(debug_hdr.dropped);
ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
if (ret)
goto out;

View File

@ -1701,7 +1701,6 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
struct ath6kl_sta *sta;
struct aggr_info_conn *aggr_conn = NULL;
struct rxtid *rxtid;
struct rxtid_stats *stats;
u16 hold_q_size;
u8 tid, aid;
@ -1722,7 +1721,6 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
return;
rxtid = &aggr_conn->rx_tid[tid];
stats = &aggr_conn->stat[tid];
if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",

View File

@ -676,10 +676,10 @@ static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
return 0;
ah->cal_list_curr = currCal = currCal->calNext;
if (currCal->calState == CAL_WAITING) {
if (currCal->calState == CAL_WAITING)
ath9k_hw_reset_calibration(ah, currCal);
return 0;
}
return 0;
}
/* Do NF cal only at longer intervals */

View File

@ -1800,6 +1800,8 @@ static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
static void ar9003_hw_spectral_scan_trigger(struct ath_hw *ah)
{
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ENABLE);
/* Activate spectral scan */
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN,
AR_PHY_SPECTRAL_SCAN_ACTIVE);

View File

@ -2942,16 +2942,19 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
struct ieee80211_channel *channel;
int chan_pwr, new_pwr;
u16 ctl = NO_CTL;
if (!chan)
return;
if (!test)
ctl = ath9k_regd_get_ctl(reg, chan);
channel = chan->chan;
chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
new_pwr = min_t(int, chan_pwr, reg->power_limit);
ah->eep_ops->set_txpower(ah, chan,
ath9k_regd_get_ctl(reg, chan),
ah->eep_ops->set_txpower(ah, chan, ctl,
get_antenna_gain(ah, chan), new_pwr, test);
}

View File

@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int nframes, int nbad,
int txok);
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
int seqno);
struct ath_buf *bf);
static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
struct ath_txq *txq,
struct ath_atx_tid *tid,
@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = info->status.status_driver_data[0];
if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
IEEE80211_TX_STATUS_EOSP)) {
ieee80211_tx_status(hw, skb);
return;
}
@ -295,7 +296,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
}
if (fi->baw_tracked) {
ath_tx_update_baw(sc, tid, bf->bf_state.seqno);
ath_tx_update_baw(sc, tid, bf);
sendbar = true;
}
@ -311,10 +312,15 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
}
static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
int seqno)
struct ath_buf *bf)
{
struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
u16 seqno = bf->bf_state.seqno;
int index, cindex;
if (!fi->baw_tracked)
return;
index = ATH_BA_INDEX(tid->seq_start, seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
@ -335,6 +341,9 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
u16 seqno = bf->bf_state.seqno;
int index, cindex;
if (fi->baw_tracked)
return;
index = ATH_BA_INDEX(tid->seq_start, seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
__set_bit(cindex, tid->tx_buf);
@ -611,7 +620,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* complete the acked-ones/xretried ones; update
* block-ack window
*/
ath_tx_update_baw(sc, tid, seqno);
ath_tx_update_baw(sc, tid, bf);
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
memcpy(tx_info->control.rates, rates, sizeof(rates));
@ -641,7 +650,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* run out of tx buf.
*/
if (!tbf) {
ath_tx_update_baw(sc, tid, seqno);
ath_tx_update_baw(sc, tid, bf);
ath_tx_complete_buf(sc, bf, txq,
&bf_head, NULL, ts,
@ -969,7 +978,8 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_lastbf = bf;
tx_info = IEEE80211_SKB_CB(skb);
tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
IEEE80211_TX_STATUS_EOSP);
/*
* No aggregation session is running, but there may be frames
@ -1009,11 +1019,14 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
INIT_LIST_HEAD(&bf_head);
list_add(&bf->list, &bf_head);
ath_tx_update_baw(sc, tid, seqno);
ath_tx_update_baw(sc, tid, bf);
ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0);
continue;
}
if (bf_isampdu(bf))
ath_tx_addto_baw(sc, tid, bf);
return bf;
}
@ -1071,8 +1084,6 @@ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf->bf_next = NULL;
/* link buffers of this frame to the aggregate */
if (!fi->baw_tracked)
ath_tx_addto_baw(sc, tid, bf);
bf->bf_state.ndelim = ndelim;
list_add_tail(&bf->list, bf_q);
@ -1659,6 +1670,22 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
}
}
static void
ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val)
{
struct ieee80211_hdr *hdr;
u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA);
u16 mask_val = mask * val;
hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
if ((hdr->frame_control & mask) != mask_val) {
hdr->frame_control = (hdr->frame_control & ~mask) | mask_val;
dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
sizeof(*hdr), DMA_TO_DEVICE);
}
}
void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@ -1689,12 +1716,11 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
if (!bf)
break;
ath9k_set_moredata(sc, bf, true);
list_add_tail(&bf->list, &bf_q);
ath_set_rates(tid->an->vif, tid->an->sta, bf);
if (bf_isampdu(bf)) {
ath_tx_addto_baw(sc, tid, bf);
if (bf_isampdu(bf))
bf->bf_state.bf_type &= ~BUF_AGGR;
}
if (bf_tail)
bf_tail->bf_next = bf;
@ -1712,6 +1738,9 @@ void ath9k_release_buffered_frames(struct ieee80211_hw *hw,
if (list_empty(&bf_q))
return;
if (!more_data)
ath9k_set_moredata(sc, bf_tail, false);
info = IEEE80211_SKB_CB(bf_tail->bf_mpdu);
info->flags |= IEEE80211_TX_STATUS_EOSP;
@ -2407,7 +2436,6 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
.txq = sc->beacon.cabq
};
struct ath_tx_info info = {};
struct ieee80211_hdr *hdr;
struct ath_buf *bf_tail = NULL;
struct ath_buf *bf;
LIST_HEAD(bf_q);
@ -2451,15 +2479,10 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (list_empty(&bf_q))
return;
bf = list_last_entry(&bf_q, struct ath_buf, list);
ath9k_set_moredata(sc, bf, false);
bf = list_first_entry(&bf_q, struct ath_buf, list);
hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data;
if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) {
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
sizeof(*hdr), DMA_TO_DEVICE);
}
ath_txq_lock(sc, txctl.txq);
ath_tx_fill_desc(sc, bf, txctl.txq, 0);
ath_tx_txqaddbuf(sc, txctl.txq, &bf_q, false);

View File

@ -689,11 +689,12 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
wil_dbg_misc(wil, "scan: wdev=0x%p iftype=%d\n", wdev, wdev->iftype);
/* check we are client side */
/* scan is supported on client interfaces and on AP interface */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_DEVICE:
case NL80211_IFTYPE_AP:
break;
default:
return -EOPNOTSUPP;
@ -1089,18 +1090,51 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
int rc;
bool tx_status;
/* Note, currently we do not support the "wait" parameter, user-space
* must call remain_on_channel before mgmt_tx or listen on a channel
* another way (AP/PCP or connected station)
* in addition we need to check if specified "chan" argument is
* different from currently "listened" channel and fail if it is.
wil_dbg_misc(wil, "mgmt_tx: channel %d offchan %d, wait %d\n",
params->chan ? params->chan->hw_value : -1,
params->offchan,
params->wait);
/* Note, currently we support the "wait" parameter only on AP mode.
* In other modes, user-space must call remain_on_channel before
* mgmt_tx or listen on a channel other than active one.
*/
rc = wmi_mgmt_tx(vif, buf, len);
tx_status = (rc == 0);
if (params->chan && params->chan->hw_value == 0) {
wil_err(wil, "invalid channel\n");
return -EINVAL;
}
if (wdev->iftype != NL80211_IFTYPE_AP) {
wil_dbg_misc(wil,
"send WMI_SW_TX_REQ_CMDID on non-AP interfaces\n");
rc = wmi_mgmt_tx(vif, buf, len);
goto out;
}
if (!params->chan || params->chan->hw_value == vif->channel) {
wil_dbg_misc(wil,
"send WMI_SW_TX_REQ_CMDID for on-channel\n");
rc = wmi_mgmt_tx(vif, buf, len);
goto out;
}
if (params->offchan == 0) {
wil_err(wil,
"invalid channel params: current %d requested %d, off-channel not allowed\n",
vif->channel, params->chan->hw_value);
return -EBUSY;
}
/* use the wmi_mgmt_tx_ext only on AP mode and off-channel */
rc = wmi_mgmt_tx_ext(vif, buf, len, params->chan->hw_value,
params->wait);
out:
tx_status = (rc == 0);
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
tx_status, GFP_KERNEL);
return rc;
}

View File

@ -1388,7 +1388,7 @@ static const struct file_operations fops_bf = {
};
/*---------temp------------*/
static void print_temp(struct seq_file *s, const char *prefix, u32 t)
static void print_temp(struct seq_file *s, const char *prefix, s32 t)
{
switch (t) {
case 0:
@ -1396,7 +1396,8 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t)
seq_printf(s, "%s N/A\n", prefix);
break;
default:
seq_printf(s, "%s %d.%03d\n", prefix, t / 1000, t % 1000);
seq_printf(s, "%s %s%d.%03d\n", prefix, (t < 0 ? "-" : ""),
abs(t / 1000), abs(t % 1000));
break;
}
}
@ -1404,7 +1405,7 @@ static void print_temp(struct seq_file *s, const char *prefix, u32 t)
static int wil_temp_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
u32 t_m, t_r;
s32 t_m, t_r;
int rc = wmi_get_temperature(wil, &t_m, &t_r);
if (rc) {
@ -1640,6 +1641,7 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
unsigned long long drop_dup = r->drop_dup, drop_old = r->drop_old;
unsigned long long drop_dup_mcast = r->drop_dup_mcast;
seq_printf(s, "([%2d]) 0x%03x [", r->buf_size, r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
@ -1649,9 +1651,9 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
seq_printf(s, "%c", r->reorder_buf[i] ? '*' : '_');
}
seq_printf(s,
"] total %llu drop %llu (dup %llu + old %llu) last 0x%03x\n",
r->total, drop_dup + drop_old, drop_dup, drop_old,
r->ssn_last_drop);
"] total %llu drop %llu (dup %llu + old %llu + dup mcast %llu) last 0x%03x\n",
r->total, drop_dup + drop_old + drop_dup_mcast, drop_dup,
drop_old, drop_dup_mcast, r->ssn_last_drop);
}
static void wil_print_rxtid_crypto(struct seq_file *s, int tid,
@ -1733,13 +1735,12 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
p->stats.rx_short_frame,
p->stats.rx_large_frame,
p->stats.rx_replay);
if (wil->use_enhanced_dma_hw)
seq_printf(s,
"mic error %lu, key error %lu, amsdu error %lu\n",
p->stats.rx_mic_error,
p->stats.rx_key_error,
p->stats.rx_amsdu_error);
seq_printf(s,
"mic error %lu, key error %lu, amsdu error %lu, csum error %lu\n",
p->stats.rx_mic_error,
p->stats.rx_key_error,
p->stats.rx_amsdu_error,
p->stats.rx_csum_err);
seq_puts(s, "Rx/MCS:");
for (mcs = 0; mcs < ARRAY_SIZE(p->stats.rx_per_mcs);
@ -1801,6 +1802,343 @@ static const struct file_operations fops_mids = {
.llseek = seq_lseek,
};
static int wil_tx_latency_debugfs_show(struct seq_file *s, void *data)
__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{
struct wil6210_priv *wil = s->private;
int i, bin;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown";
u8 aid = 0;
u8 mid;
if (!p->tx_latency_bins)
continue;
switch (p->status) {
case wil_sta_unused:
status = "unused ";
break;
case wil_sta_conn_pending:
status = "pending ";
break;
case wil_sta_connected:
status = "connected";
aid = p->aid;
break;
}
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
mid, aid);
if (p->status == wil_sta_connected) {
u64 num_packets = 0;
u64 tx_latency_avg = p->stats.tx_latency_total_us;
seq_puts(s, "Tx/Latency bin:");
for (bin = 0; bin < WIL_NUM_LATENCY_BINS; bin++) {
seq_printf(s, " %lld",
p->tx_latency_bins[bin]);
num_packets += p->tx_latency_bins[bin];
}
seq_puts(s, "\n");
if (!num_packets)
continue;
do_div(tx_latency_avg, num_packets);
seq_printf(s, "Tx/Latency min/avg/max (us): %d/%lld/%d",
p->stats.tx_latency_min_us,
tx_latency_avg,
p->stats.tx_latency_max_us);
seq_puts(s, "\n");
}
}
return 0;
}
static int wil_tx_latency_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, wil_tx_latency_debugfs_show,
inode->i_private);
}
static ssize_t wil_tx_latency_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 val, rc, i;
bool enable;
rc = kstrtoint_from_user(buf, len, 0, &val);
if (rc) {
wil_err(wil, "Invalid argument\n");
return rc;
}
if (val == 1)
/* default resolution */
val = 500;
if (val && (val < 50 || val > 1000)) {
wil_err(wil, "Invalid resolution %d\n", val);
return -EINVAL;
}
enable = !!val;
if (wil->tx_latency == enable)
return len;
wil_info(wil, "%s TX latency measurements (resolution %dusec)\n",
enable ? "Enabling" : "Disabling", val);
if (enable) {
size_t sz = sizeof(u64) * WIL_NUM_LATENCY_BINS;
wil->tx_latency_res = val;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *sta = &wil->sta[i];
kfree(sta->tx_latency_bins);
sta->tx_latency_bins = kzalloc(sz, GFP_KERNEL);
if (!sta->tx_latency_bins)
return -ENOMEM;
sta->stats.tx_latency_min_us = U32_MAX;
sta->stats.tx_latency_max_us = 0;
sta->stats.tx_latency_total_us = 0;
}
}
wil->tx_latency = enable;
return len;
}
static const struct file_operations fops_tx_latency = {
.open = wil_tx_latency_seq_open,
.release = single_release,
.read = seq_read,
.write = wil_tx_latency_write,
.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)
{
@ -2134,6 +2472,9 @@ static const struct {
{"srings", 0444, &fops_srings},
{"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,
@ -2250,10 +2591,14 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
void wil6210_debugfs_remove(struct wil6210_priv *wil)
{
int i;
debugfs_remove_recursive(wil->debug);
wil->debug = NULL;
kfree(wil->dbg_data.data_arr);
for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
kfree(wil->sta[i].tx_latency_bins);
/* free pmc memory without sending command to fw, as it will
* be reset on the way down anyway

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2014-2015,2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -22,6 +23,8 @@
MODULE_FIRMWARE(WIL_FW_NAME_DEFAULT);
MODULE_FIRMWARE(WIL_FW_NAME_SPARROW_PLUS);
MODULE_FIRMWARE(WIL_BOARD_FILE_NAME);
MODULE_FIRMWARE(WIL_FW_NAME_TALYN);
MODULE_FIRMWARE(WIL_BRD_NAME_TALYN);
static
void wil_memset_toio_32(volatile void __iomem *dst, u32 val,

View File

@ -145,7 +145,7 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
capabilities);
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
memcpy(wil->fw_capabilities, rec->capabilities,
min(sizeof(wil->fw_capabilities), capa_size));
min_t(size_t, sizeof(wil->fw_capabilities), capa_size));
wil_hex_dump_fw("CAPA", DUMP_PREFIX_OFFSET, 16, 1,
rec->capabilities, capa_size, false);
return 0;

View File

@ -625,6 +625,15 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
wil6210_unmask_irq_misc(wil, false);
/* in non-triple MSI case, this is done inside wil6210_thread_irq
* because it has to be done after unmasking the pseudo.
*/
if (wil->n_msi == 3 && wil->suspend_resp_rcvd) {
wil_dbg_irq(wil, "set suspend_resp_comp to true\n");
wil->suspend_resp_comp = true;
wake_up_interruptible(&wil->wq);
}
return IRQ_HANDLED;
}
@ -782,6 +791,40 @@ static irqreturn_t wil6210_hardirq(int irq, void *cookie)
return rc;
}
static int wil6210_request_3msi(struct wil6210_priv *wil, int irq)
{
int rc;
/* IRQ's are in the following order:
* - Tx
* - Rx
* - Misc
*/
rc = request_irq(irq, wil->txrx_ops.irq_tx, IRQF_SHARED,
WIL_NAME "_tx", wil);
if (rc)
return rc;
rc = request_irq(irq + 1, wil->txrx_ops.irq_rx, IRQF_SHARED,
WIL_NAME "_rx", wil);
if (rc)
goto free0;
rc = request_threaded_irq(irq + 2, wil6210_irq_misc,
wil6210_irq_misc_thread,
IRQF_SHARED, WIL_NAME "_misc", wil);
if (rc)
goto free1;
return 0;
free1:
free_irq(irq + 1, wil);
free0:
free_irq(irq, wil);
return rc;
}
/* can't use wil_ioread32_and_clear because ICC value is not set yet */
static inline void wil_clear32(void __iomem *addr)
{
@ -822,11 +865,12 @@ void wil6210_clear_halp(struct wil6210_priv *wil)
wil6210_unmask_halp(wil);
}
int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
int wil6210_init_irq(struct wil6210_priv *wil, int irq)
{
int rc;
wil_dbg_misc(wil, "init_irq: %s\n", use_msi ? "MSI" : "INTx");
wil_dbg_misc(wil, "init_irq: %s, n_msi=%d\n",
wil->n_msi ? "MSI" : "INTx", wil->n_msi);
if (wil->use_enhanced_dma_hw) {
wil->txrx_ops.irq_tx = wil6210_irq_tx_edma;
@ -835,10 +879,14 @@ int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi)
wil->txrx_ops.irq_tx = wil6210_irq_tx;
wil->txrx_ops.irq_rx = wil6210_irq_rx;
}
rc = request_threaded_irq(irq, wil6210_hardirq,
wil6210_thread_irq,
use_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
if (wil->n_msi == 3)
rc = wil6210_request_3msi(wil, irq);
else
rc = request_threaded_irq(irq, wil6210_hardirq,
wil6210_thread_irq,
wil->n_msi ? 0 : IRQF_SHARED,
WIL_NAME, wil);
return rc;
}
@ -848,4 +896,8 @@ void wil6210_fini_irq(struct wil6210_priv *wil, int irq)
wil_mask_irq(wil);
free_irq(irq, wil);
if (wil->n_msi == 3) {
free_irq(irq + 1, wil);
free_irq(irq + 2, wil);
}
}

View File

@ -28,6 +28,7 @@
#define WAIT_FOR_HALP_VOTE_MS 100
#define WAIT_FOR_SCAN_ABORT_MS 1000
#define WIL_DEFAULT_NUM_RX_STATUS_RINGS 1
#define WIL_BOARD_FILE_MAX_NAMELEN 128
bool debug_fw; /* = false; */
module_param(debug_fw, bool, 0444);
@ -278,6 +279,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
/* statistics */
memset(&sta->stats, 0, sizeof(sta->stats));
sta->stats.tx_latency_min_us = U32_MAX;
}
static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
@ -1128,6 +1130,9 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
wiphy->max_sched_scan_plans = WMI_MAX_PLANS_NUM;
}
if (test_bit(WMI_FW_CAPABILITY_TX_REQ_EXT, wil->fw_capabilities))
wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX;
if (wil->platform_ops.set_features) {
features = (test_bit(WMI_FW_CAPABILITY_REF_CLOCK_CONTROL,
wil->fw_capabilities) &&
@ -1135,8 +1140,20 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
wil->platform_capa)) ?
BIT(WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL) : 0;
if (wil->n_msi == 3)
features |= BIT(WIL_PLATFORM_FEATURE_TRIPLE_MSI);
wil->platform_ops.set_features(wil->platform_handle, features);
}
if (test_bit(WMI_FW_CAPABILITY_BACK_WIN_SIZE_64,
wil->fw_capabilities)) {
wil->max_agg_wsize = WIL_MAX_AGG_WSIZE_64;
wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE_128;
} else {
wil->max_agg_wsize = WIL_MAX_AGG_WSIZE;
wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE;
}
}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
@ -1148,6 +1165,28 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
le32_to_cpus(&r->head);
}
/* construct actual board file name to use */
void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len)
{
const char *board_file;
const char *wil_talyn_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
WIL_FW_NAME_TALYN;
if (wil->board_file) {
board_file = wil->board_file;
} else {
/* If specific FW file is used for Talyn,
* use specific board file
*/
if (strcmp(wil->wil_fw_name, wil_talyn_fw_name) == 0)
board_file = WIL_BRD_NAME_TALYN;
else
board_file = WIL_BOARD_FILE_NAME;
}
strlcpy(buf, board_file, len);
}
static int wil_get_bl_info(struct wil6210_priv *wil)
{
struct net_device *ndev = wil->main_ndev;
@ -1269,7 +1308,7 @@ static int wil_get_otp_info(struct wil6210_priv *wil)
static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
{
ulong to = msecs_to_jiffies(1000);
ulong to = msecs_to_jiffies(2000);
ulong left = wait_for_completion_timeout(&wil->wmi_ready, to);
if (0 == left) {
@ -1519,8 +1558,17 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_set_oob_mode(wil, oob_mode);
if (load_fw) {
char board_file[WIL_BOARD_FILE_MAX_NAMELEN];
if (wil->secured_boot) {
wil_err(wil, "secured boot is not supported\n");
return -ENOTSUPP;
}
board_file[0] = '\0';
wil_get_board_file(wil, board_file, sizeof(board_file));
wil_info(wil, "Use firmware <%s> + board <%s>\n",
wil->wil_fw_name, WIL_BOARD_FILE_NAME);
wil->wil_fw_name, board_file);
if (!no_flash)
wil_bl_prepare_halt(wil);
@ -1532,11 +1580,9 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
if (rc)
goto out;
if (wil->brd_file_addr)
rc = wil_request_board(wil, WIL_BOARD_FILE_NAME);
rc = wil_request_board(wil, board_file);
else
rc = wil_request_firmware(wil,
WIL_BOARD_FILE_NAME,
true);
rc = wil_request_firmware(wil, board_file, true);
if (rc)
goto out;
@ -1568,6 +1614,13 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil->txrx_ops.configure_interrupt_moderation(wil);
/* Enable OFU rdy valid bug fix, to prevent hang in oful34_rx
* while there is back-pressure from Host during RX
*/
if (wil->hw_version >= HW_VER_TALYN_MB)
wil_s(wil, RGF_DMA_MISC_CTL,
BIT_OFUL34_RDY_VALID_BUG_FIX_EN);
rc = wil_restore_vifs(wil);
if (rc) {
wil_err(wil, "failed to restore vifs, rc %d\n", rc);

View File

@ -24,11 +24,11 @@
#include <linux/rtnetlink.h>
#include <linux/pm_runtime.h>
static bool use_msi = true;
module_param(use_msi, bool, 0444);
MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
static int n_msi = 3;
module_param(n_msi, int, 0444);
MODULE_PARM_DESC(n_msi, " Use MSI interrupt: 0 - use INTx, 1 - single, or 3 - (default) ");
static bool ftm_mode;
bool ftm_mode;
module_param(ftm_mode, bool, 0444);
MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
@ -93,6 +93,10 @@ int wil_set_capabilities(struct wil6210_priv *wil)
if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) &
BIT_NO_FLASH_INDICATION)
set_bit(hw_capa_no_flash, wil->hw_capa);
wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
WIL_FW_NAME_TALYN;
if (wil_fw_verify_file_exists(wil, wil_fw_name))
wil->wil_fw_name = wil_fw_name;
break;
case JTAG_DEV_ID_TALYN_MB:
wil->hw_name = "Talyn-MB";
@ -104,6 +108,10 @@ int wil_set_capabilities(struct wil6210_priv *wil)
set_bit(hw_capa_no_flash, wil->hw_capa);
wil->use_enhanced_dma_hw = true;
wil->use_rx_hw_reordering = true;
wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN :
WIL_FW_NAME_TALYN;
if (wil_fw_verify_file_exists(wil, wil_fw_name))
wil->wil_fw_name = wil_fw_name;
break;
default:
wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n",
@ -142,12 +150,24 @@ int wil_set_capabilities(struct wil6210_priv *wil)
void wil_disable_irq(struct wil6210_priv *wil)
{
disable_irq(wil->pdev->irq);
int irq = wil->pdev->irq;
disable_irq(irq);
if (wil->n_msi == 3) {
disable_irq(irq + 1);
disable_irq(irq + 2);
}
}
void wil_enable_irq(struct wil6210_priv *wil)
{
enable_irq(wil->pdev->irq);
int irq = wil->pdev->irq;
enable_irq(irq);
if (wil->n_msi == 3) {
enable_irq(irq + 1);
enable_irq(irq + 2);
}
}
static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
@ -174,28 +194,47 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
* and only MSI should be used
*/
int msi_only = pdev->msi_enabled;
bool _use_msi = use_msi;
wil_dbg_misc(wil, "if_pcie_enable\n");
pci_set_master(pdev);
wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx");
if (use_msi && pci_enable_msi(pdev)) {
wil_err(wil, "pci_enable_msi failed, use INTx\n");
_use_msi = false;
/* how many MSI interrupts to request? */
switch (n_msi) {
case 3:
case 1:
wil_dbg_misc(wil, "Setup %d MSI interrupts\n", n_msi);
break;
case 0:
wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
break;
default:
wil_err(wil, "Invalid n_msi=%d, default to 1\n", n_msi);
n_msi = 1;
}
if (!_use_msi && msi_only) {
if (n_msi == 3 &&
pci_alloc_irq_vectors(pdev, n_msi, n_msi, PCI_IRQ_MSI) < n_msi) {
wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
n_msi = 1;
}
if (n_msi == 1 && pci_enable_msi(pdev)) {
wil_err(wil, "pci_enable_msi failed, use INTx\n");
n_msi = 0;
}
wil->n_msi = n_msi;
if (wil->n_msi == 0 && msi_only) {
wil_err(wil, "Interrupt pin not routed, unable to use INTx\n");
rc = -ENODEV;
goto stop_master;
}
rc = wil6210_init_irq(wil, pdev->irq, _use_msi);
rc = wil6210_init_irq(wil, pdev->irq);
if (rc)
goto stop_master;
goto release_vectors;
/* need reset here to obtain MAC */
mutex_lock(&wil->mutex);
@ -208,8 +247,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
release_irq:
wil6210_fini_irq(wil, pdev->irq);
/* safe to call if no MSI */
pci_disable_msi(pdev);
release_vectors:
/* safe to call if no allocation */
pci_free_irq_vectors(pdev);
stop_master:
pci_clear_master(pdev);
return rc;

View File

@ -95,7 +95,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
struct wil6210_vif *vif;
struct net_device *ndev;
int tid, cid, mid, mcast;
int tid, cid, mid, mcast, retry;
u16 seq;
struct wil_sta_info *sta;
struct wil_tid_ampdu_rx *r;
@ -103,7 +103,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
int index;
wil->txrx_ops.get_reorder_params(wil, skb, &tid, &cid, &mid, &seq,
&mcast);
&mcast, &retry);
sta = &wil->sta[cid];
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
@ -117,11 +117,6 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
ndev = vif_to_ndev(vif);
if (unlikely(mcast)) {
wil_netif_rx_any(skb, ndev);
return;
}
spin_lock(&sta->tid_rx_lock);
r = sta->tid_rx[tid];
@ -130,6 +125,19 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
goto out;
}
if (unlikely(mcast)) {
if (retry && seq == r->mcast_last_seq) {
r->drop_dup_mcast++;
wil_dbg_txrx(wil, "Rx drop: dup mcast seq 0x%03x\n",
seq);
dev_kfree_skb(skb);
goto out;
}
r->mcast_last_seq = seq;
wil_netif_rx_any(skb, ndev);
goto out;
}
r->total++;
hseq = r->head_seq_num;
@ -262,6 +270,7 @@ struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
r->buf_size = size;
r->stored_mpdu_num = 0;
r->first_time = true;
r->mcast_last_seq = U16_MAX;
return r;
}
@ -288,7 +297,7 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
/* ADDBA processing */
static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
{
u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE /
u16 max_agg_size = min_t(u16, wil->max_agg_wsize, wil->max_ampdu_size /
(mtu_max + WIL_MAX_MPDU_OVERHEAD));
if (!req_agg_wsize)
@ -355,11 +364,11 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
if (status == WLAN_STATUS_SUCCESS) {
if (req_agg_wsize == 0) {
wil_dbg_misc(wil, "Suggest BACK wsize %d\n",
WIL_MAX_AGG_WSIZE);
agg_wsize = WIL_MAX_AGG_WSIZE;
wil->max_agg_wsize);
agg_wsize = wil->max_agg_wsize;
} else {
agg_wsize = min_t(u16,
WIL_MAX_AGG_WSIZE, req_agg_wsize);
wil->max_agg_wsize, req_agg_wsize);
}
}

View File

@ -281,6 +281,12 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct wil_ring *vring,
skb_reserve(skb, headroom);
skb_put(skb, sz);
/**
* Make sure that the network stack calculates checksum for packets
* which failed the HW checksum calculation
*/
skb->ip_summed = CHECKSUM_NONE;
pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(dev, pa))) {
kfree_skb(skb);
@ -569,6 +575,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* mis-calculates TCP checksum - if it should be 0x0,
* it writes 0xffff in violation of RFC 1624
*/
else
stats->rx_csum_err++;
}
if (snaplen) {
@ -678,6 +686,21 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
return 0;
}
static int wil_rx_error_check(struct wil6210_priv *wil, struct sk_buff *skb,
struct wil_net_stats *stats)
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
if ((d->dma.status & RX_DMA_STATUS_ERROR) &&
(d->dma.error & RX_DMA_ERROR_MIC)) {
stats->rx_mic_error++;
wil_dbg_txrx(wil, "MIC error, dropping packet\n");
return -EFAULT;
}
return 0;
}
static void wil_get_netif_rx_params(struct sk_buff *skb, int *cid,
int *security)
{
@ -736,6 +759,12 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
goto stats;
}
/* check errors reported by HW and update statistics */
if (unlikely(wil->txrx_ops.rx_error_check(wil, skb, stats))) {
dev_kfree_skb(skb);
return;
}
if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (mcast) {
/* send multicast frames both to higher layers in
@ -1672,6 +1701,11 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
*/
wmb();
if (wil->tx_latency)
*(ktime_t *)&skb->cb = ktime_get();
else
memset(skb->cb, 0, sizeof(ktime_t));
wil_w(wil, vring->hwtail, vring->swhead);
return 0;
@ -1823,6 +1857,11 @@ static int __wil_tx_ring(struct wil6210_priv *wil, struct wil6210_vif *vif,
*/
wmb();
if (wil->tx_latency)
*(ktime_t *)&skb->cb = ktime_get();
else
memset(skb->cb, 0, sizeof(ktime_t));
wil_w(wil, ring->hwtail, ring->swhead);
return 0;
@ -2044,6 +2083,31 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NET_XMIT_DROP;
}
void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
struct wil_sta_info *sta)
{
int skb_time_us;
int bin;
if (!wil->tx_latency)
return;
if (ktime_to_ms(*(ktime_t *)&skb->cb) == 0)
return;
skb_time_us = ktime_us_delta(ktime_get(), *(ktime_t *)&skb->cb);
bin = skb_time_us / wil->tx_latency_res;
bin = min_t(int, bin, WIL_NUM_LATENCY_BINS - 1);
wil_dbg_txrx(wil, "skb time %dus => bin %d\n", skb_time_us, bin);
sta->tx_latency_bins[bin]++;
sta->stats.tx_latency_total_us += skb_time_us;
if (skb_time_us < sta->stats.tx_latency_min_us)
sta->stats.tx_latency_min_us = skb_time_us;
if (skb_time_us > sta->stats.tx_latency_max_us)
sta->stats.tx_latency_max_us = skb_time_us;
}
/**
* Clean up transmitted skb's from the Tx VRING
*
@ -2130,6 +2194,9 @@ int wil_tx_complete(struct wil6210_vif *vif, int ringid)
if (stats) {
stats->tx_packets++;
stats->tx_bytes += skb->len;
wil_tx_latency_calc(wil, skb,
&wil->sta[cid]);
}
} else {
ndev->stats.tx_errors++;
@ -2180,7 +2247,7 @@ static inline void wil_tx_fini(struct wil6210_priv *wil) {}
static void wil_get_reorder_params(struct wil6210_priv *wil,
struct sk_buff *skb, int *tid, int *cid,
int *mid, u16 *seq, int *mcast)
int *mid, u16 *seq, int *mcast, int *retry)
{
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
@ -2189,6 +2256,7 @@ static void wil_get_reorder_params(struct wil6210_priv *wil,
*mid = wil_rxdesc_mid(d);
*seq = wil_rxdesc_seq(d);
*mcast = wil_rxdesc_mcast(d);
*retry = wil_rxdesc_retry(d);
}
void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
@ -2211,6 +2279,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
wil->txrx_ops.get_netif_rx_params =
wil_get_netif_rx_params;
wil->txrx_ops.rx_crypto_check = wil_rx_crypto_check;
wil->txrx_ops.rx_error_check = wil_rx_error_check;
wil->txrx_ops.is_rx_idle = wil_is_rx_idle;
wil->txrx_ops.rx_fini = wil_rx_fini;
}

View File

@ -500,6 +500,11 @@ static inline int wil_rxdesc_ext_subtype(struct vring_rx_desc *d)
return WIL_GET_BITS(d->mac.d0, 28, 31);
}
static inline int wil_rxdesc_retry(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->mac.d0, 31, 31);
}
static inline int wil_rxdesc_key_id(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->mac.d1, 4, 5);
@ -615,5 +620,7 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
struct wil_tid_ampdu_rx *r);
void wil_tx_data_init(struct wil_ring_tx_data *txdata);
void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil);
void wil_tx_latency_calc(struct wil6210_priv *wil, struct sk_buff *skb,
struct wil_sta_info *sta);
#endif /* WIL6210_TXRX_H */

View File

@ -27,6 +27,8 @@
#include "trace.h"
#define WIL_EDMA_MAX_DATA_OFFSET (2)
/* RX buffer size must be aligned to 4 bytes */
#define WIL_EDMA_RX_BUF_LEN_DEFAULT (2048)
static void wil_tx_desc_unmap_edma(struct device *dev,
union wil_tx_desc *desc,
@ -158,8 +160,7 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
struct wil_ring *ring, u32 i)
{
struct device *dev = wil_to_dev(wil);
unsigned int sz = wil->rx_buf_len + ETH_HLEN +
WIL_EDMA_MAX_DATA_OFFSET;
unsigned int sz = ALIGN(wil->rx_buf_len, 4);
dma_addr_t pa;
u16 buff_id;
struct list_head *active = &wil->rx_buff_mgmt.active;
@ -182,6 +183,12 @@ static int wil_ring_alloc_skb_edma(struct wil6210_priv *wil,
skb_put(skb, sz);
/**
* Make sure that the network stack calculates checksum for packets
* which failed the HW checksum calculation
*/
skb->ip_summed = CHECKSUM_NONE;
pa = dma_map_single(dev, skb->data, skb->len, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(dev, pa))) {
kfree_skb(skb);
@ -503,7 +510,7 @@ static int wil_init_rx_desc_ring(struct wil6210_priv *wil, u16 desc_ring_size,
static void wil_get_reorder_params_edma(struct wil6210_priv *wil,
struct sk_buff *skb, int *tid,
int *cid, int *mid, u16 *seq,
int *mcast)
int *mcast, int *retry)
{
struct wil_rx_status_extended *s = wil_skb_rxstatus(skb);
@ -512,6 +519,7 @@ static void wil_get_reorder_params_edma(struct wil6210_priv *wil,
*mid = wil_rx_status_get_mid(s);
*seq = le16_to_cpu(wil_rx_status_get_seq(wil, s));
*mcast = wil_rx_status_get_mcast(s);
*retry = wil_rx_status_get_retry(s);
}
static void wil_get_netif_rx_params_edma(struct sk_buff *skb, int *cid,
@ -593,7 +601,7 @@ static bool wil_is_rx_idle_edma(struct wil6210_priv *wil)
static void wil_rx_buf_len_init_edma(struct wil6210_priv *wil)
{
wil->rx_buf_len = rx_large_buf ?
WIL_MAX_ETH_MTU : TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
WIL_MAX_ETH_MTU : WIL_EDMA_RX_BUF_LEN_DEFAULT;
}
static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
@ -626,8 +634,7 @@ static int wil_rx_init_edma(struct wil6210_priv *wil, u16 desc_ring_size)
wil_rx_buf_len_init_edma(wil);
max_rx_pl_per_desc = wil->rx_buf_len + ETH_HLEN +
WIL_EDMA_MAX_DATA_OFFSET;
max_rx_pl_per_desc = ALIGN(wil->rx_buf_len, 4);
/* Use debugfs dbg_num_rx_srings if set, reserve one sring for TX */
if (wil->num_rx_status_rings > WIL6210_MAX_STATUS_RINGS - 1)
@ -794,14 +801,15 @@ static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
return -EAGAIN;
}
static int wil_rx_edma_check_errors(struct wil6210_priv *wil, void *msg,
struct wil_net_stats *stats,
struct sk_buff *skb)
static int wil_rx_error_check_edma(struct wil6210_priv *wil,
struct sk_buff *skb,
struct wil_net_stats *stats)
{
int error;
int l2_rx_status;
int l3_rx_status;
int l4_rx_status;
void *msg = wil_skb_rxstatus(skb);
error = wil_rx_status_get_error(msg);
if (!error) {
@ -845,6 +853,8 @@ static int wil_rx_edma_check_errors(struct wil6210_priv *wil, void *msg,
* mis-calculates TCP checksum - if it should be 0x0,
* it writes 0xffff in violation of RFC 1624
*/
else
stats->rx_csum_err++;
return 0;
}
@ -859,12 +869,10 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
struct sk_buff *skb;
dma_addr_t pa;
struct wil_ring_rx_data *rxdata = &sring->rx_data;
unsigned int sz = wil->rx_buf_len + ETH_HLEN +
WIL_EDMA_MAX_DATA_OFFSET;
unsigned int sz = ALIGN(wil->rx_buf_len, 4);
struct wil_net_stats *stats = NULL;
u16 dmalen;
int cid;
int rc;
bool eop, headstolen;
int delta;
u8 dr_bit;
@ -936,13 +944,6 @@ static struct sk_buff *wil_sring_reap_rx_edma(struct wil6210_priv *wil,
goto skipping;
}
/* Check and treat errors reported by HW */
rc = wil_rx_edma_check_errors(wil, msg, stats, skb);
if (rc) {
rxdata->skipping = true;
goto skipping;
}
if (unlikely(dmalen > sz)) {
wil_err(wil, "Rx size too large: %d bytes!\n", dmalen);
stats->rx_large_frame++;
@ -1223,6 +1224,9 @@ int wil_tx_sring_handler(struct wil6210_priv *wil,
if (stats) {
stats->tx_packets++;
stats->tx_bytes += skb->len;
wil_tx_latency_calc(wil, skb,
&wil->sta[cid]);
}
} else {
ndev->stats.tx_errors++;
@ -1473,6 +1477,11 @@ static int __wil_tx_ring_tso_edma(struct wil6210_priv *wil,
*/
wmb();
if (wil->tx_latency)
*(ktime_t *)&skb->cb = ktime_get();
else
memset(skb->cb, 0, sizeof(ktime_t));
wil_w(wil, ring->hwtail, ring->swhead);
return 0;
@ -1592,6 +1601,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
wil->txrx_ops.get_reorder_params = wil_get_reorder_params_edma;
wil->txrx_ops.get_netif_rx_params = wil_get_netif_rx_params_edma;
wil->txrx_ops.rx_crypto_check = wil_rx_crypto_check_edma;
wil->txrx_ops.rx_error_check = wil_rx_error_check_edma;
wil->txrx_ops.is_rx_idle = wil_is_rx_idle_edma;
wil->txrx_ops.rx_fini = wil_rx_fini_edma;
}

View File

@ -471,6 +471,12 @@ static inline __le16 wil_rx_status_get_seq(struct wil6210_priv *wil, void *msg)
return ((struct wil_rx_status_extended *)msg)->ext.seq_num;
}
static inline u8 wil_rx_status_get_retry(void *msg)
{
/* retry bit is missing in EDMA HW. return 1 to be on the safe side */
return 1;
}
static inline int wil_rx_status_get_mid(void *msg)
{
if (!(((struct wil_rx_status_compressed *)msg)->d0 &

View File

@ -37,6 +37,7 @@ extern bool rx_align_2;
extern bool rx_large_buf;
extern bool debug_fw;
extern bool disable_ap_sme;
extern bool ftm_mode;
struct wil6210_priv;
struct wil6210_vif;
@ -50,11 +51,17 @@ union wil_tx_desc;
#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw"
#define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw"
#define WIL_FW_NAME_TALYN "wil6436.fw"
#define WIL_FW_NAME_FTM_TALYN "wil6436_ftm.fw"
#define WIL_BRD_NAME_TALYN "wil6436.brd"
#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
#define WIL_NUM_LATENCY_BINS 200
/* maximum number of virtual interfaces the driver supports
* (including the main interface)
*/
@ -85,6 +92,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */
#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */
#define WIL_MAX_AMPDU_SIZE_128 (128 * 1024) /* FW/HW limit */
#define WIL_MAX_AGG_WSIZE_64 (64) /* FW/HW limit */
#define WIL6210_MAX_STATUS_RINGS (8)
/* Hardware offload block adds the following:
@ -293,6 +302,8 @@ struct RGF_ICR {
#define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER BIT(2)
#define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR BIT(3)
#define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH BIT(4)
#define RGF_DMA_MISC_CTL (0x881d6c)
#define BIT_OFUL34_RDY_VALID_BUG_FIX_EN BIT(7)
#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
@ -543,6 +554,31 @@ struct wil_status_ring {
struct wil_ring_rx_data rx_data;
};
#define WIL_STA_TID_NUM (16)
#define WIL_MCS_MAX (12) /* Maximum MCS supported */
struct wil_net_stats {
unsigned long rx_packets;
unsigned long tx_packets;
unsigned long rx_bytes;
unsigned long tx_bytes;
unsigned long tx_errors;
u32 tx_latency_min_us;
u32 tx_latency_max_us;
u64 tx_latency_total_us;
unsigned long rx_dropped;
unsigned long rx_non_data_frame;
unsigned long rx_short_frame;
unsigned long rx_large_frame;
unsigned long rx_replay;
unsigned long rx_mic_error;
unsigned long rx_key_error; /* eDMA specific */
unsigned long rx_amsdu_error; /* eDMA specific */
unsigned long rx_csum_err;
u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
};
/**
* struct tx_rx_ops - different TX/RX ops for legacy and enhanced
* DMA flow
@ -572,10 +608,12 @@ struct wil_txrx_ops {
u16 agg_wsize, u16 timeout);
void (*get_reorder_params)(struct wil6210_priv *wil,
struct sk_buff *skb, int *tid, int *cid,
int *mid, u16 *seq, int *mcast);
int *mid, u16 *seq, int *mcast, int *retry);
void (*get_netif_rx_params)(struct sk_buff *skb,
int *cid, int *security);
int (*rx_crypto_check)(struct wil6210_priv *wil, struct sk_buff *skb);
int (*rx_error_check)(struct wil6210_priv *wil, struct sk_buff *skb,
struct wil_net_stats *stats);
bool (*is_rx_idle)(struct wil6210_priv *wil);
irqreturn_t (*irq_rx)(int irq, void *cookie);
};
@ -625,6 +663,8 @@ struct pci_dev;
* @drop_dup: duplicate frames dropped for this reorder buffer
* @drop_old: old frames dropped for this reorder buffer
* @first_time: true when this buffer used 1-st time
* @mcast_last_seq: sequence number (SN) of last received multicast packet
* @drop_dup_mcast: duplicate multicast frames dropped for this reorder buffer
*/
struct wil_tid_ampdu_rx {
struct sk_buff **reorder_buf;
@ -638,6 +678,8 @@ struct wil_tid_ampdu_rx {
unsigned long long drop_dup;
unsigned long long drop_old;
bool first_time; /* is it 1-st time this buffer used? */
u16 mcast_last_seq; /* multicast dup detection */
unsigned long long drop_dup_mcast;
};
/**
@ -672,27 +714,6 @@ enum wil_sta_status {
wil_sta_connected = 2,
};
#define WIL_STA_TID_NUM (16)
#define WIL_MCS_MAX (12) /* Maximum MCS supported */
struct wil_net_stats {
unsigned long rx_packets;
unsigned long tx_packets;
unsigned long rx_bytes;
unsigned long tx_bytes;
unsigned long tx_errors;
unsigned long rx_dropped;
unsigned long rx_non_data_frame;
unsigned long rx_short_frame;
unsigned long rx_large_frame;
unsigned long rx_replay;
unsigned long rx_mic_error; /* eDMA specific */
unsigned long rx_key_error; /* eDMA specific */
unsigned long rx_amsdu_error; /* eDMA specific */
u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
};
/**
* struct wil_sta_info - data for peer
*
@ -706,6 +727,14 @@ struct wil_sta_info {
u8 mid;
enum wil_sta_status status;
struct wil_net_stats stats;
/**
* 20 latency bins. 1st bin counts packets with latency
* of 0..tx_latency_res, last bin counts packets with latency
* of 19*tx_latency_res and above.
* 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 */
@ -820,6 +849,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 */
};
/**
@ -847,11 +878,18 @@ 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;
struct wiphy *wiphy;
struct net_device *main_ndev;
int n_msi;
void __iomem *csr;
DECLARE_BITMAP(status, wil_status_last);
u8 fw_version[ETHTOOL_FWVERS_LEN];
@ -937,6 +975,8 @@ struct wil6210_priv {
u8 wakeup_trigger;
struct wil_suspend_stats suspend_stats;
struct wil_debugfs_data dbg_data;
bool tx_latency; /* collect TX latency measurements */
size_t tx_latency_res; /* bin resolution in usec */
void *platform_handle;
struct wil_platform_ops platform_ops;
@ -977,6 +1017,11 @@ struct wil6210_priv {
bool use_rx_hw_reordering;
bool secured_boot;
u8 boot_config;
struct wil_fw_stats_global fw_stats_global;
u32 max_agg_wsize;
u32 max_ampdu_size;
};
#define wil_to_wiphy(i) (i->wiphy)
@ -1060,6 +1105,8 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val)
wil_w(wil, reg, wil_r(wil, reg) & ~val);
}
void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len);
#if defined(CONFIG_DYNAMIC_DEBUG)
#define wil_hex_dump_txrx(prefix_str, prefix_type, rowsize, \
groupsize, buf, len, ascii) \
@ -1176,13 +1223,14 @@ 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);
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq, bool use_msi);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
void wil_mask_irq(struct wil6210_priv *wil);
void wil_unmask_irq(struct wil6210_priv *wil);
@ -1304,6 +1352,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
struct cfg80211_sched_scan_request *request);
int wmi_stop_sched_scan(struct wil6210_priv *wil);
int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len);
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
u8 channel, u16 duration_ms);
int reverse_memcmp(const void *cs, const void *ct, size_t count);

View File

@ -29,6 +29,7 @@ enum wil_platform_event {
enum wil_platform_features {
WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL = 0,
WIL_PLATFORM_FEATURE_TRIPLE_MSI = 1,
WIL_PLATFORM_FEATURE_MAX,
};

View File

@ -464,6 +464,10 @@ 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";
case WMI_SW_TX_REQ_EXT_CMDID:
return "WMI_SW_TX_REQ_EXT_CMDID";
default:
return "Untracked CMD";
}
@ -598,6 +602,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 +1337,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 +1491,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},
};
/*
@ -2983,6 +3116,60 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len)
return rc;
}
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
u8 channel, u16 duration_ms)
{
size_t total;
struct wil6210_priv *wil = vif_to_wil(vif);
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
struct wmi_sw_tx_req_ext_cmd *cmd;
struct {
struct wmi_cmd_hdr wmi;
struct wmi_sw_tx_complete_event evt;
} __packed evt = {
.evt = {.status = WMI_FW_STATUS_FAILURE},
};
int rc;
wil_dbg_wmi(wil, "mgmt_tx_ext mid %d channel %d duration %d\n",
vif->mid, channel, duration_ms);
wil_hex_dump_wmi("mgmt_tx_ext frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
len, true);
if (len < sizeof(struct ieee80211_hdr_3addr)) {
wil_err(wil, "short frame. len %zu\n", len);
return -EINVAL;
}
total = sizeof(*cmd) + len;
if (total < len) {
wil_err(wil, "mgmt_tx_ext invalid len %zu\n", len);
return -EINVAL;
}
cmd = kzalloc(total, GFP_KERNEL);
if (!cmd)
return -ENOMEM;
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
cmd->len = cpu_to_le16(len);
memcpy(cmd->payload, buf, len);
cmd->channel = channel - 1;
cmd->duration_ms = cpu_to_le16(duration_ms);
rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total,
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "mgmt_tx_ext failed with status %d\n",
evt.evt.status);
rc = -EINVAL;
}
kfree(cmd);
return rc;
}
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
{
int rc;
@ -3242,3 +3429,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;
}

View File

@ -53,6 +53,17 @@
* must always be kept equal to (WMI_RF_RX2TX_LENGTH+1)
*/
#define WMI_RF_RX2TX_CONF_LENGTH (4)
/* Qos configuration */
#define WMI_QOS_NUM_OF_PRIORITY (4)
#define WMI_QOS_MIN_DEFAULT_WEIGHT (10)
#define WMI_QOS_VRING_SLOT_MIN_MS (2)
#define WMI_QOS_VRING_SLOT_MAX_MS (10)
/* (WMI_QOS_MIN_DEFAULT_WEIGHT * WMI_QOS_VRING_SLOT_MAX_MS /
* WMI_QOS_VRING_SLOT_MIN_MS)
*/
#define WMI_QOS_MAX_WEIGHT 50
#define WMI_QOS_SET_VIF_PRIORITY (0xFF)
#define WMI_QOS_DEFAULT_PRIORITY (WMI_QOS_NUM_OF_PRIORITY)
/* Mailbox interface
* used for commands and events
@ -86,7 +97,12 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_PNO = 15,
WMI_FW_CAPABILITY_REF_CLOCK_CONTROL = 18,
WMI_FW_CAPABILITY_AP_SME_OFFLOAD_NONE = 19,
WMI_FW_CAPABILITY_MULTI_VIFS = 20,
WMI_FW_CAPABILITY_FT_ROAMING = 21,
WMI_FW_CAPABILITY_BACK_WIN_SIZE_64 = 22,
WMI_FW_CAPABILITY_AMSDU = 23,
WMI_FW_CAPABILITY_RAW_MODE = 24,
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
WMI_FW_CAPABILITY_MAX,
};
@ -110,6 +126,9 @@ enum wmi_command_id {
WMI_SET_PROBED_SSID_CMDID = 0x0A,
/* deprecated */
WMI_SET_LISTEN_INT_CMDID = 0x0B,
WMI_FT_AUTH_CMDID = 0x0C,
WMI_FT_REASSOC_CMDID = 0x0D,
WMI_UPDATE_FT_IES_CMDID = 0x0E,
WMI_BCON_CTRL_CMDID = 0x0F,
WMI_ADD_CIPHER_KEY_CMDID = 0x16,
WMI_DELETE_CIPHER_KEY_CMDID = 0x17,
@ -118,6 +137,12 @@ enum wmi_command_id {
WMI_SET_WSC_STATUS_CMDID = 0x41,
WMI_PXMT_RANGE_CFG_CMDID = 0x42,
WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x43,
WMI_RADAR_GENERAL_CONFIG_CMDID = 0x100,
WMI_RADAR_CONFIG_SELECT_CMDID = 0x101,
WMI_RADAR_PARAMS_CONFIG_CMDID = 0x102,
WMI_RADAR_SET_MODE_CMDID = 0x103,
WMI_RADAR_CONTROL_CMDID = 0x104,
WMI_RADAR_PCI_CONTROL_CMDID = 0x105,
WMI_MEM_READ_CMDID = 0x800,
WMI_MEM_WR_CMDID = 0x801,
WMI_ECHO_CMDID = 0x803,
@ -158,6 +183,10 @@ enum wmi_command_id {
WMI_SET_PCP_CHANNEL_CMDID = 0x829,
WMI_GET_PCP_CHANNEL_CMDID = 0x82A,
WMI_SW_TX_REQ_CMDID = 0x82B,
/* Event is shared between WMI_SW_TX_REQ_CMDID and
* WMI_SW_TX_REQ_EXT_CMDID
*/
WMI_SW_TX_REQ_EXT_CMDID = 0x82C,
WMI_MLME_PUSH_CMDID = 0x835,
WMI_BEAMFORMING_MGMT_CMDID = 0x836,
WMI_BF_TXSS_MGMT_CMDID = 0x837,
@ -207,7 +236,12 @@ enum wmi_command_id {
WMI_GET_PCP_FACTOR_CMDID = 0x91B,
/* Power Save Configuration Commands */
WMI_PS_DEV_PROFILE_CFG_CMDID = 0x91C,
WMI_RS_ENABLE_CMDID = 0x91E,
WMI_RS_CFG_EX_CMDID = 0x91F,
WMI_GET_DETAILED_RS_RES_EX_CMDID = 0x920,
/* deprecated */
WMI_RS_CFG_CMDID = 0x921,
/* deprecated */
WMI_GET_DETAILED_RS_RES_CMDID = 0x922,
WMI_AOA_MEAS_CMDID = 0x923,
WMI_BRP_SET_ANT_LIMIT_CMDID = 0x924,
@ -236,7 +270,9 @@ enum wmi_command_id {
WMI_PRIO_TX_SECTORS_ORDER_CMDID = 0x9A5,
WMI_PRIO_TX_SECTORS_NUMBER_CMDID = 0x9A6,
WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_CMDID = 0x9A7,
/* deprecated */
WMI_BF_CONTROL_CMDID = 0x9AA,
WMI_BF_CONTROL_EX_CMDID = 0x9AB,
WMI_TX_STATUS_RING_ADD_CMDID = 0x9C0,
WMI_RX_STATUS_RING_ADD_CMDID = 0x9C1,
WMI_TX_DESC_RING_ADD_CMDID = 0x9C2,
@ -252,6 +288,11 @@ enum wmi_command_id {
WMI_GET_CCA_INDICATIONS_CMDID = 0xA07,
WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_CMDID = 0xA08,
WMI_INTERNAL_FW_IOCTL_CMDID = 0xA0B,
WMI_LINK_STATS_CMDID = 0xA0C,
WMI_SET_GRANT_MCS_CMDID = 0xA0E,
WMI_SET_AP_SLOT_SIZE_CMDID = 0xA0F,
WMI_SET_VRING_PRIORITY_WEIGHT_CMDID = 0xA10,
WMI_SET_VRING_PRIORITY_CMDID = 0xA11,
WMI_SET_MAC_ADDRESS_CMDID = 0xF003,
WMI_ABORT_SCAN_CMDID = 0xF007,
WMI_SET_PROMISCUOUS_MODE_CMDID = 0xF041,
@ -450,6 +491,30 @@ struct wmi_start_sched_scan_cmd {
struct wmi_sched_scan_plan scan_plans[WMI_MAX_PLANS_NUM];
} __packed;
/* WMI_FT_AUTH_CMDID */
struct wmi_ft_auth_cmd {
u8 bssid[WMI_MAC_LEN];
/* enum wmi_channel */
u8 channel;
/* enum wmi_channel */
u8 edmg_channel;
u8 reserved[4];
} __packed;
/* WMI_FT_REASSOC_CMDID */
struct wmi_ft_reassoc_cmd {
u8 bssid[WMI_MAC_LEN];
u8 reserved[2];
} __packed;
/* WMI_UPDATE_FT_IES_CMDID */
struct wmi_update_ft_ies_cmd {
/* Length of the FT IEs */
__le16 ie_len;
u8 reserved[2];
u8 ie_info[0];
} __packed;
/* WMI_SET_PROBED_SSID_CMDID */
#define MAX_PROBED_SSID_INDEX (3)
@ -506,6 +571,109 @@ struct wmi_pxmt_snr2_range_cfg_cmd {
s8 snr2range_arr[2];
} __packed;
/* WMI_RADAR_GENERAL_CONFIG_CMDID */
struct wmi_radar_general_config_cmd {
/* Number of pulses (CIRs) in FW FIFO to initiate pulses transfer
* from FW to Host
*/
__le32 fifo_watermark;
/* In unit of us, in the range [100, 1000000] */
__le32 t_burst;
/* Valid in the range [1, 32768], 0xFFFF means infinite */
__le32 n_bursts;
/* In unit of 330Mhz clk, in the range [4, 2000]*330 */
__le32 t_pulse;
/* In the range of [1,4096] */
__le16 n_pulses;
/* Number of taps after cTap per CIR */
__le16 n_samples;
/* Offset from the main tap (0 = zero-distance). In the range of [0,
* 255]
*/
u8 first_sample_offset;
/* Number of Pulses to average, 1, 2, 4, 8 */
u8 pulses_to_avg;
/* Number of adjacent taps to average, 1, 2, 4, 8 */
u8 samples_to_avg;
/* The index to config general params */
u8 general_index;
u8 reserved[4];
} __packed;
/* WMI_RADAR_CONFIG_SELECT_CMDID */
struct wmi_radar_config_select_cmd {
/* Select the general params index to use */
u8 general_index;
u8 reserved[3];
/* 0 means don't update burst_active_vector */
__le32 burst_active_vector;
/* 0 means don't update pulse_active_vector */
__le32 pulse_active_vector;
} __packed;
/* WMI_RADAR_PARAMS_CONFIG_CMDID */
struct wmi_radar_params_config_cmd {
/* The burst index selected to config */
u8 burst_index;
/* 0-not active, 1-active */
u8 burst_en;
/* The pulse index selected to config */
u8 pulse_index;
/* 0-not active, 1-active */
u8 pulse_en;
/* TX RF to use on current pulse */
u8 tx_rfc_idx;
u8 tx_sector;
/* Offset from calibrated value.(expected to be 0)(value is row in
* Gain-LUT, not dB)
*/
s8 tx_rf_gain_comp;
/* expected to be 0 */
s8 tx_bb_gain_comp;
/* RX RF to use on current pulse */
u8 rx_rfc_idx;
u8 rx_sector;
/* Offset from calibrated value.(expected to be 0)(value is row in
* Gain-LUT, not dB)
*/
s8 rx_rf_gain_comp;
/* Value in dB.(expected to be 0) */
s8 rx_bb_gain_comp;
/* Offset from calibrated value.(expected to be 0) */
s8 rx_timing_offset;
u8 reserved[3];
} __packed;
/* WMI_RADAR_SET_MODE_CMDID */
struct wmi_radar_set_mode_cmd {
/* 0-disable/1-enable */
u8 enable;
/* enum wmi_channel */
u8 channel;
/* In the range of [0,7], 0xff means use default */
u8 tx_rfc_idx;
/* In the range of [0,7], 0xff means use default */
u8 rx_rfc_idx;
} __packed;
/* WMI_RADAR_CONTROL_CMDID */
struct wmi_radar_control_cmd {
/* 0-stop/1-start */
u8 start;
u8 reserved[3];
} __packed;
/* WMI_RADAR_PCI_CONTROL_CMDID */
struct wmi_radar_pci_control_cmd {
/* pcie host buffer start address */
__le64 base_addr;
/* pcie host control block address */
__le64 control_block_addr;
/* pcie host buffer size */
__le32 buffer_size;
__le32 reserved;
} __packed;
/* WMI_RF_MGMT_CMDID */
enum wmi_rf_mgmt_type {
WMI_RF_MGMT_W_DISABLE = 0x00,
@ -643,12 +811,18 @@ struct wmi_pcp_start_cmd {
u8 pcp_max_assoc_sta;
u8 hidden_ssid;
u8 is_go;
u8 reserved0[5];
/* enum wmi_channel WMI_CHANNEL_9..WMI_CHANNEL_12 */
u8 edmg_channel;
u8 raw_mode;
u8 reserved[3];
/* A-BFT length override if non-0 */
u8 abft_len;
/* enum wmi_ap_sme_offload_mode_e */
u8 ap_sme_offload_mode;
u8 network_type;
/* enum wmi_channel WMI_CHANNEL_1..WMI_CHANNEL_6; for EDMG this is
* the primary channel number
*/
u8 channel;
u8 disable_sec_offload;
u8 disable_sec;
@ -661,6 +835,17 @@ struct wmi_sw_tx_req_cmd {
u8 payload[0];
} __packed;
/* WMI_SW_TX_REQ_EXT_CMDID */
struct wmi_sw_tx_req_ext_cmd {
u8 dst_mac[WMI_MAC_LEN];
__le16 len;
__le16 duration_ms;
/* Channel to use, 0xFF for currently active channel */
u8 channel;
u8 reserved[5];
u8 payload[0];
} __packed;
/* WMI_VRING_SWITCH_TIMING_CONFIG_CMDID */
struct wmi_vring_switch_timing_config_cmd {
/* Set vring timing configuration:
@ -687,6 +872,7 @@ struct wmi_vring_cfg_schd {
enum wmi_vring_cfg_encap_trans_type {
WMI_VRING_ENC_TYPE_802_3 = 0x00,
WMI_VRING_ENC_TYPE_NATIVE_WIFI = 0x01,
WMI_VRING_ENC_TYPE_NONE = 0x02,
};
enum wmi_vring_cfg_ds_cfg {
@ -744,7 +930,11 @@ struct wmi_vring_cfg {
u8 cid;
/* Used when cidxtid = CIDXTID_EXTENDED_CID_TID */
u8 tid;
u8 reserved[2];
/* Update the vring's priority for Qos purpose. Set to
* WMI_QOS_DEFAULT_PRIORITY to use MID's QoS priority
*/
u8 qos_priority;
u8 reserved;
} __packed;
enum wmi_vring_cfg_cmd_action {
@ -775,20 +965,6 @@ struct wmi_bcast_vring_cfg_cmd {
struct wmi_bcast_vring_cfg vring_cfg;
} __packed;
/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */
struct wmi_lo_power_calib_from_otp_cmd {
/* index to read from OTP. zero based */
u8 index;
u8 reserved[3];
} __packed;
/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */
struct wmi_lo_power_calib_from_otp_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
struct wmi_edma_ring_cfg {
__le64 ring_mem_base;
/* size in number of items */
@ -861,6 +1037,20 @@ struct wmi_bcast_desc_ring_add_cmd {
u8 reserved[4];
} __packed;
/* WMI_LO_POWER_CALIB_FROM_OTP_CMDID */
struct wmi_lo_power_calib_from_otp_cmd {
/* index to read from OTP. zero based */
u8 index;
u8 reserved[3];
} __packed;
/* WMI_LO_POWER_CALIB_FROM_OTP_EVENTID */
struct wmi_lo_power_calib_from_otp_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_RING_BA_EN_CMDID */
struct wmi_ring_ba_en_cmd {
u8 ring_id;
@ -1094,8 +1284,8 @@ struct wmi_echo_cmd {
} __packed;
/* WMI_DEEP_ECHO_CMDID
* Check FW and ucode are alive
* Returned event: WMI_ECHO_RSP_EVENTID
* Check FW and uCode is alive
* Returned event: WMI_DEEP_ECHO_RSP_EVENTID
*/
struct wmi_deep_echo_cmd {
__le32 value;
@ -1419,6 +1609,10 @@ struct wmi_fixed_scheduling_config_complete_event {
u8 reserved[3];
} __packed;
/* This value exists for backwards compatibility only.
* Do not use it in new commands.
* Use dynamic arrays where possible.
*/
#define WMI_NUM_MCS (13)
/* WMI_FIXED_SCHEDULING_CONFIG_CMDID */
@ -1466,6 +1660,52 @@ struct wmi_set_multi_directed_omnis_config_event {
u8 reserved[3];
} __packed;
/* WMI_RADAR_GENERAL_CONFIG_EVENTID */
struct wmi_radar_general_config_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_RADAR_CONFIG_SELECT_EVENTID */
struct wmi_radar_config_select_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
/* In unit of bytes */
__le32 fifo_size;
/* In unit of bytes */
__le32 pulse_size;
} __packed;
/* WMI_RADAR_PARAMS_CONFIG_EVENTID */
struct wmi_radar_params_config_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_RADAR_SET_MODE_EVENTID */
struct wmi_radar_set_mode_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_RADAR_CONTROL_EVENTID */
struct wmi_radar_control_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_RADAR_PCI_CONTROL_EVENTID */
struct wmi_radar_pci_control_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_SET_LONG_RANGE_CONFIG_CMDID */
struct wmi_set_long_range_config_cmd {
__le32 reserved;
@ -1478,12 +1718,12 @@ struct wmi_set_long_range_config_complete_event {
u8 reserved[3];
} __packed;
/* payload max size is 236 bytes: max event buffer size (256) - WMI headers
/* payload max size is 1024 bytes: max event buffer size (1044) - WMI headers
* (16) - prev struct field size (4)
*/
#define WMI_MAX_IOCTL_PAYLOAD_SIZE (236)
#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (236)
#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (236)
#define WMI_MAX_IOCTL_PAYLOAD_SIZE (1024)
#define WMI_MAX_IOCTL_REPLY_PAYLOAD_SIZE (1024)
#define WMI_MAX_INTERNAL_EVENT_PAYLOAD_SIZE (1024)
enum wmi_internal_fw_ioctl_code {
WMI_INTERNAL_FW_CODE_NONE = 0x0,
@ -1523,7 +1763,37 @@ struct wmi_internal_fw_event_event {
__le32 payload[0];
} __packed;
/* WMI_BF_CONTROL_CMDID */
/* WMI_SET_VRING_PRIORITY_WEIGHT_CMDID */
struct wmi_set_vring_priority_weight_cmd {
/* Array of weights. Valid values are
* WMI_QOS_MIN_DEFAULT_WEIGHT...WMI_QOS_MAX_WEIGHT. Weight #0 is
* hard-coded WMI_QOS_MIN_WEIGHT. This array provide the weights
* #1..#3
*/
u8 weight[3];
u8 reserved;
} __packed;
/* WMI_SET_VRING_PRIORITY_CMDID */
struct wmi_vring_priority {
u8 vring_idx;
/* Weight index. Valid value is 0-3 */
u8 priority;
u8 reserved[2];
} __packed;
/* WMI_SET_VRING_PRIORITY_CMDID */
struct wmi_set_vring_priority_cmd {
/* number of entries in vring_priority. Set to
* WMI_QOS_SET_VIF_PRIORITY to update the VIF's priority, and there
* will be only one entry in vring_priority
*/
u8 num_of_vrings;
u8 reserved[3];
struct wmi_vring_priority vring_priority[0];
} __packed;
/* WMI_BF_CONTROL_CMDID - deprecated */
struct wmi_bf_control_cmd {
/* wmi_bf_triggers */
__le32 triggers;
@ -1565,6 +1835,95 @@ struct wmi_bf_control_cmd {
u8 reserved2[2];
} __packed;
/* BF configuration for each MCS */
struct wmi_bf_control_ex_mcs {
/* Long term throughput threshold [Mbps] */
u8 long_term_mbps_th_tbl;
u8 reserved;
/* Long term timeout threshold table [msec] */
__le16 long_term_trig_timeout_per_mcs;
} __packed;
/* WMI_BF_CONTROL_EX_CMDID */
struct wmi_bf_control_ex_cmd {
/* wmi_bf_triggers */
__le32 triggers;
/* enum wmi_edmg_tx_mode */
u8 tx_mode;
/* DISABLED = 0, ENABLED = 1 , DRY_RUN = 2 */
u8 txss_mode;
/* DISABLED = 0, ENABLED = 1, DRY_RUN = 2 */
u8 brp_mode;
/* Max cts threshold (correspond to
* WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP)
*/
u8 bf_trigger_max_cts_failure_thr;
/* Max cts threshold in dense (correspond to
* WMI_BF_TRIGGER_MAX_CTS_FAILURE_IN_TXOP)
*/
u8 bf_trigger_max_cts_failure_dense_thr;
/* Max b-ack threshold (correspond to
* WMI_BF_TRIGGER_MAX_BACK_FAILURE)
*/
u8 bf_trigger_max_back_failure_thr;
/* Max b-ack threshold in dense (correspond to
* WMI_BF_TRIGGER_MAX_BACK_FAILURE)
*/
u8 bf_trigger_max_back_failure_dense_thr;
u8 reserved0;
/* Wrong sectors threshold */
__le32 wrong_sector_bis_thr;
/* BOOL to enable/disable long term trigger */
u8 long_term_enable;
/* 1 = Update long term thresholds from the long_term_mbps_th_tbl and
* long_term_trig_timeout_per_mcs arrays, 0 = Ignore
*/
u8 long_term_update_thr;
u8 each_mcs_cfg_size;
u8 reserved1;
/* Configuration for each MCS */
struct wmi_bf_control_ex_mcs each_mcs_cfg[0];
} __packed;
/* WMI_LINK_STATS_CMD */
enum wmi_link_stats_action {
WMI_LINK_STATS_SNAPSHOT = 0x00,
WMI_LINK_STATS_PERIODIC = 0x01,
WMI_LINK_STATS_STOP_PERIODIC = 0x02,
};
/* WMI_LINK_STATS_EVENT record identifiers */
enum wmi_link_stats_record_type {
WMI_LINK_STATS_TYPE_BASIC = 0x01,
WMI_LINK_STATS_TYPE_GLOBAL = 0x02,
};
/* WMI_LINK_STATS_CMDID */
struct wmi_link_stats_cmd {
/* bitmask of required record types
* (wmi_link_stats_record_type_e)
*/
__le32 record_type_mask;
/* 0xff for all cids */
u8 cid;
/* wmi_link_stats_action_e */
u8 action;
u8 reserved[6];
/* range = 100 - 10000 */
__le32 interval_msec;
} __packed;
/* WMI_SET_GRANT_MCS_CMDID */
struct wmi_set_grant_mcs_cmd {
u8 mcs;
u8 reserved[3];
} __packed;
/* WMI_SET_AP_SLOT_SIZE_CMDID */
struct wmi_set_ap_slot_size_cmd {
__le32 slot_size;
} __packed;
/* WMI Events
* List of Events (target to host)
*/
@ -1577,10 +1936,19 @@ enum wmi_event_id {
WMI_SCHED_SCAN_RESULT_EVENTID = 0x1007,
WMI_SCAN_COMPLETE_EVENTID = 0x100A,
WMI_REPORT_STATISTICS_EVENTID = 0x100B,
WMI_FT_AUTH_STATUS_EVENTID = 0x100C,
WMI_FT_REASSOC_STATUS_EVENTID = 0x100D,
WMI_RADAR_GENERAL_CONFIG_EVENTID = 0x1100,
WMI_RADAR_CONFIG_SELECT_EVENTID = 0x1101,
WMI_RADAR_PARAMS_CONFIG_EVENTID = 0x1102,
WMI_RADAR_SET_MODE_EVENTID = 0x1103,
WMI_RADAR_CONTROL_EVENTID = 0x1104,
WMI_RADAR_PCI_CONTROL_EVENTID = 0x1105,
WMI_RD_MEM_RSP_EVENTID = 0x1800,
WMI_FW_READY_EVENTID = 0x1801,
WMI_EXIT_FAST_MEM_ACC_MODE_EVENTID = 0x200,
WMI_ECHO_RSP_EVENTID = 0x1803,
WMI_DEEP_ECHO_RSP_EVENTID = 0x1804,
/* deprecated */
WMI_FS_TUNE_DONE_EVENTID = 0x180A,
/* deprecated */
@ -1606,6 +1974,9 @@ enum wmi_event_id {
WMI_DELBA_EVENTID = 0x1826,
WMI_GET_SSID_EVENTID = 0x1828,
WMI_GET_PCP_CHANNEL_EVENTID = 0x182A,
/* Event is shared between WMI_SW_TX_REQ_CMDID and
* WMI_SW_TX_REQ_EXT_CMDID
*/
WMI_SW_TX_COMPLETE_EVENTID = 0x182B,
WMI_BEAMFORMING_MGMT_DONE_EVENTID = 0x1836,
WMI_BF_TXSS_MGMT_DONE_EVENTID = 0x1837,
@ -1653,7 +2024,12 @@ enum wmi_event_id {
WMI_PCP_FACTOR_EVENTID = 0x191A,
/* Power Save Configuration Events */
WMI_PS_DEV_PROFILE_CFG_EVENTID = 0x191C,
WMI_RS_ENABLE_EVENTID = 0x191E,
WMI_RS_CFG_EX_EVENTID = 0x191F,
WMI_GET_DETAILED_RS_RES_EX_EVENTID = 0x1920,
/* deprecated */
WMI_RS_CFG_DONE_EVENTID = 0x1921,
/* deprecated */
WMI_GET_DETAILED_RS_RES_EVENTID = 0x1922,
WMI_AOA_MEAS_EVENTID = 0x1923,
WMI_BRP_SET_ANT_LIMIT_EVENTID = 0x1924,
@ -1681,7 +2057,9 @@ enum wmi_event_id {
WMI_PRIO_TX_SECTORS_ORDER_EVENTID = 0x19A5,
WMI_PRIO_TX_SECTORS_NUMBER_EVENTID = 0x19A6,
WMI_PRIO_TX_SECTORS_SET_DEFAULT_CFG_EVENTID = 0x19A7,
/* deprecated */
WMI_BF_CONTROL_EVENTID = 0x19AA,
WMI_BF_CONTROL_EX_EVENTID = 0x19AB,
WMI_TX_STATUS_RING_CFG_DONE_EVENTID = 0x19C0,
WMI_RX_STATUS_RING_CFG_DONE_EVENTID = 0x19C1,
WMI_TX_DESC_RING_CFG_DONE_EVENTID = 0x19C2,
@ -1697,6 +2075,12 @@ enum wmi_event_id {
WMI_SET_CCA_INDICATIONS_BI_AVG_NUM_EVENTID = 0x1A08,
WMI_INTERNAL_FW_EVENT_EVENTID = 0x1A0A,
WMI_INTERNAL_FW_IOCTL_EVENTID = 0x1A0B,
WMI_LINK_STATS_CONFIG_DONE_EVENTID = 0x1A0C,
WMI_LINK_STATS_EVENTID = 0x1A0D,
WMI_SET_GRANT_MCS_EVENTID = 0x1A0E,
WMI_SET_AP_SLOT_SIZE_EVENTID = 0x1A0F,
WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID = 0x1A10,
WMI_SET_VRING_PRIORITY_EVENTID = 0x1A11,
WMI_SET_CHANNEL_EVENTID = 0x9000,
WMI_ASSOC_REQ_EVENTID = 0x9001,
WMI_EAPOL_RX_EVENTID = 0x9002,
@ -1961,6 +2345,33 @@ struct wmi_scan_complete_event {
__le32 status;
} __packed;
/* WMI_FT_AUTH_STATUS_EVENTID */
struct wmi_ft_auth_status_event {
/* enum wmi_fw_status */
u8 status;
u8 reserved[3];
u8 mac_addr[WMI_MAC_LEN];
__le16 ie_len;
u8 ie_info[0];
} __packed;
/* WMI_FT_REASSOC_STATUS_EVENTID */
struct wmi_ft_reassoc_status_event {
/* enum wmi_fw_status */
u8 status;
/* association id received from new AP */
u8 aid;
/* enum wmi_channel */
u8 channel;
/* enum wmi_channel */
u8 edmg_channel;
u8 mac_addr[WMI_MAC_LEN];
__le16 beacon_ie_len;
__le16 reassoc_req_ie_len;
__le16 reassoc_resp_ie_len;
u8 ie_info[0];
} __packed;
/* wmi_rx_mgmt_info */
struct wmi_rx_mgmt_info {
u8 mcs;
@ -2317,6 +2728,11 @@ struct wmi_echo_rsp_event {
__le32 echoed_value;
} __packed;
/* WMI_DEEP_ECHO_RSP_EVENTID */
struct wmi_deep_echo_rsp_event {
__le32 echoed_value;
} __packed;
/* WMI_RF_PWR_ON_DELAY_RSP_EVENTID */
struct wmi_rf_pwr_on_delay_rsp_event {
/* wmi_fw_status */
@ -2455,6 +2871,81 @@ struct wmi_rs_cfg {
__le32 mcs_en_vec;
} __packed;
enum wmi_edmg_tx_mode {
WMI_TX_MODE_DMG = 0x0,
WMI_TX_MODE_EDMG_CB1 = 0x1,
WMI_TX_MODE_EDMG_CB2 = 0x2,
WMI_TX_MODE_EDMG_CB1_LONG_LDPC = 0x3,
WMI_TX_MODE_EDMG_CB2_LONG_LDPC = 0x4,
WMI_TX_MODE_MAX,
};
/* Rate search parameters common configuration */
struct wmi_rs_cfg_ex_common {
/* enum wmi_edmg_tx_mode */
u8 mode;
/* stop threshold [0-100] */
u8 stop_th;
/* MCS1 stop threshold [0-100] */
u8 mcs1_fail_th;
u8 max_back_failure_th;
/* Debug feature for disabling internal RS trigger (which is
* currently triggered by BF Done)
*/
u8 dbg_disable_internal_trigger;
u8 reserved[3];
__le32 back_failure_mask;
} __packed;
/* Rate search parameters configuration per MCS */
struct wmi_rs_cfg_ex_mcs {
/* The maximal allowed PER for each MCS
* MCS will be considered as failed if PER during RS is higher
*/
u8 per_threshold;
/* Number of MPDUs for each MCS
* this is the minimal statistic required to make an educated
* decision
*/
u8 min_frame_cnt;
u8 reserved[2];
} __packed;
/* WMI_RS_CFG_EX_CMDID */
struct wmi_rs_cfg_ex_cmd {
/* Configuration for all MCSs */
struct wmi_rs_cfg_ex_common common_cfg;
u8 each_mcs_cfg_size;
u8 reserved[3];
/* Configuration for each MCS */
struct wmi_rs_cfg_ex_mcs each_mcs_cfg[0];
} __packed;
/* WMI_RS_CFG_EX_EVENTID */
struct wmi_rs_cfg_ex_event {
/* enum wmi_edmg_tx_mode */
u8 mode;
/* enum wmi_fw_status */
u8 status;
u8 reserved[2];
} __packed;
/* WMI_RS_ENABLE_CMDID */
struct wmi_rs_enable_cmd {
u8 cid;
/* enable or disable rate search */
u8 rs_enable;
u8 reserved[2];
__le32 mcs_en_vec;
} __packed;
/* WMI_RS_ENABLE_EVENTID */
struct wmi_rs_enable_event {
/* enum wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* Slot types */
enum wmi_sched_scheme_slot_type {
WMI_SCHED_SLOT_SP = 0x0,
@ -2547,7 +3038,7 @@ struct wmi_scheduling_scheme_event {
u8 reserved[1];
} __packed;
/* WMI_RS_CFG_CMDID */
/* WMI_RS_CFG_CMDID - deprecated */
struct wmi_rs_cfg_cmd {
/* connection id */
u8 cid;
@ -2557,7 +3048,7 @@ struct wmi_rs_cfg_cmd {
struct wmi_rs_cfg rs_cfg;
} __packed;
/* WMI_RS_CFG_DONE_EVENTID */
/* WMI_RS_CFG_DONE_EVENTID - deprecated */
struct wmi_rs_cfg_done_event {
u8 cid;
/* enum wmi_fw_status */
@ -2565,7 +3056,7 @@ struct wmi_rs_cfg_done_event {
u8 reserved[2];
} __packed;
/* WMI_GET_DETAILED_RS_RES_CMDID */
/* WMI_GET_DETAILED_RS_RES_CMDID - deprecated */
struct wmi_get_detailed_rs_res_cmd {
/* connection id */
u8 cid;
@ -2590,7 +3081,7 @@ struct wmi_rs_results {
u8 mcs;
} __packed;
/* WMI_GET_DETAILED_RS_RES_EVENTID */
/* WMI_GET_DETAILED_RS_RES_EVENTID - deprecated */
struct wmi_get_detailed_rs_res_event {
u8 cid;
/* enum wmi_rs_results_status */
@ -2600,6 +3091,45 @@ struct wmi_get_detailed_rs_res_event {
u8 reserved[3];
} __packed;
/* WMI_GET_DETAILED_RS_RES_EX_CMDID */
struct wmi_get_detailed_rs_res_ex_cmd {
u8 cid;
u8 reserved[3];
} __packed;
/* Rate search results */
struct wmi_rs_results_ex_common {
/* RS timestamp */
__le32 tsf;
/* RS selected MCS */
u8 mcs;
/* enum wmi_edmg_tx_mode */
u8 mode;
u8 reserved[2];
} __packed;
/* Rate search results */
struct wmi_rs_results_ex_mcs {
/* number of sent MPDUs */
u8 num_of_tx_pkt;
/* number of non-acked MPDUs */
u8 num_of_non_acked_pkt;
u8 reserved[2];
} __packed;
/* WMI_GET_DETAILED_RS_RES_EX_EVENTID */
struct wmi_get_detailed_rs_res_ex_event {
u8 cid;
/* enum wmi_rs_results_status */
u8 status;
u8 reserved0[2];
struct wmi_rs_results_ex_common common_rs_results;
u8 each_mcs_results_size;
u8 reserved1[3];
/* Results for each MCS */
struct wmi_rs_results_ex_mcs each_mcs_results[0];
} __packed;
/* BRP antenna limit mode */
enum wmi_brp_ant_limit_mode {
/* Disable BRP force antenna limit */
@ -3350,13 +3880,20 @@ struct wmi_get_assoc_list_res_event {
u8 reserved[3];
} __packed;
/* WMI_BF_CONTROL_EVENTID */
/* WMI_BF_CONTROL_EVENTID - deprecated */
struct wmi_bf_control_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_BF_CONTROL_EX_EVENTID */
struct wmi_bf_control_ex_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_COMMAND_NOT_SUPPORTED_EVENTID */
struct wmi_command_not_supported_event {
/* device id */
@ -3426,4 +3963,96 @@ struct wmi_internal_fw_set_channel_event {
u8 reserved[3];
} __packed;
/* WMI_LINK_STATS_CONFIG_DONE_EVENTID */
struct wmi_link_stats_config_done_event {
/* wmi_fw_status_e */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_LINK_STATS_EVENTID */
struct wmi_link_stats_event {
__le64 tsf;
__le16 payload_size;
u8 has_next;
u8 reserved[5];
/* a stream of wmi_link_stats_record_s */
u8 payload[0];
} __packed;
/* 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;
s8 rssi;
u8 sqi;
u8 bf_mcs;
u8 per_average;
u8 selected_rfc;
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;
__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 */
struct wmi_set_grant_mcs_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_SET_AP_SLOT_SIZE_EVENTID */
struct wmi_set_ap_slot_size_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_SET_VRING_PRIORITY_WEIGHT_EVENTID */
struct wmi_set_vring_priority_weight_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
/* WMI_SET_VRING_PRIORITY_EVENTID */
struct wmi_set_vring_priority_event {
/* wmi_fw_status */
u8 status;
u8 reserved[3];
} __packed;
#endif /* __WILOCITY_WMI_H__ */