1
0
Fork 0

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

ath.git patches for 4.20. Major changes:

ath10k

* limit available channels via DT ieee80211-freq-limit

wil6210

* add 802.11r Fast Roaming support for AP and station modes

* add support for channel 4
hifive-unleashed-5.1
Kalle Valo 2018-08-28 19:39:22 +03:00
commit 9cac6a9b62
26 changed files with 856 additions and 160 deletions

View File

@ -655,10 +655,10 @@ static void ath10k_ahb_hif_stop(struct ath10k *ar)
ath10k_ahb_irq_disable(ar);
synchronize_irq(ar_ahb->irq);
ath10k_pci_flush(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
ath10k_pci_flush(ar);
}
static int ath10k_ahb_hif_power_up(struct ath10k *ar)

View File

@ -1416,10 +1416,8 @@ ath10k_ce_alloc_src_ring(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(nentries);
src_ring = kzalloc(sizeof(*src_ring) +
(nentries *
sizeof(*src_ring->per_transfer_context)),
GFP_KERNEL);
src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
nentries), GFP_KERNEL);
if (src_ring == NULL)
return ERR_PTR(-ENOMEM);
@ -1476,10 +1474,8 @@ ath10k_ce_alloc_src_ring_64(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(nentries);
src_ring = kzalloc(sizeof(*src_ring) +
(nentries *
sizeof(*src_ring->per_transfer_context)),
GFP_KERNEL);
src_ring = kzalloc(struct_size(src_ring, per_transfer_context,
nentries), GFP_KERNEL);
if (!src_ring)
return ERR_PTR(-ENOMEM);
@ -1534,10 +1530,8 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(attr->dest_nentries);
dest_ring = kzalloc(sizeof(*dest_ring) +
(nentries *
sizeof(*dest_ring->per_transfer_context)),
GFP_KERNEL);
dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
nentries), GFP_KERNEL);
if (dest_ring == NULL)
return ERR_PTR(-ENOMEM);
@ -1580,10 +1574,8 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id,
nentries = roundup_pow_of_two(attr->dest_nentries);
dest_ring = kzalloc(sizeof(*dest_ring) +
(nentries *
sizeof(*dest_ring->per_transfer_context)),
GFP_KERNEL);
dest_ring = kzalloc(struct_size(dest_ring, per_transfer_context,
nentries), GFP_KERNEL);
if (!dest_ring)
return ERR_PTR(-ENOMEM);

View File

@ -91,6 +91,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA988X_HW_2_0_VERSION,
@ -124,6 +125,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA9887_HW_1_0_VERSION,
@ -157,6 +159,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA6174_HW_2_1_VERSION,
@ -189,6 +192,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA6174_HW_2_1_VERSION,
@ -221,6 +225,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA6174_HW_3_0_VERSION,
@ -253,6 +258,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA6174_HW_3_2_VERSION,
@ -288,6 +294,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
@ -326,6 +333,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
@ -369,6 +377,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
@ -411,6 +420,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
@ -443,6 +453,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
@ -477,6 +488,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
@ -516,6 +528,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = false,
.shadow_reg_support = false,
.rri_on_ddr = false,
.hw_filter_reset_required = true,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
@ -539,6 +552,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.per_ce_irq = true,
.shadow_reg_support = true,
.rri_on_ddr = true,
.hw_filter_reset_required = false,
},
};
@ -2405,7 +2419,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
* possible to implicitly make it correct by creating a dummy vdev and
* then deleting it.
*/
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
if (ar->hw_params.hw_filter_reset_required &&
mode == ATH10K_FIRMWARE_MODE_NORMAL) {
status = ath10k_core_reset_rx_filter(ar);
if (status) {
ath10k_err(ar,

View File

@ -589,6 +589,11 @@ struct ath10k_hw_params {
/* Number of bytes to be the offset for each FFT sample */
int spectral_bin_offset;
/* targets which require hw filter reset during boot up,
* to avoid it sending spurious acks.
*/
bool hw_filter_reset_required;
};
struct htt_rx_desc;

View File

@ -18,6 +18,7 @@
#include "mac.h"
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/acpi.h>
@ -8359,6 +8360,7 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
}
wiphy_read_of_freq_limits(ar->hw->wiphy);
ath10k_mac_setup_ht_vht_cap(ar);
ar->hw->wiphy->interface_modes =

View File

@ -2068,9 +2068,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
ath10k_pci_irq_disable(ar);
ath10k_pci_irq_sync(ar);
ath10k_pci_flush(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
ath10k_pci_flush(ar);
spin_lock_irqsave(&ar_pci->ps_lock, flags);
WARN_ON(ar_pci->ps_wake_refcount > 0);

View File

@ -1869,6 +1869,12 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
if (ret)
dev_kfree_skb_any(skb);
if (ret == -EAGAIN) {
ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
cmd_id);
queue_work(ar->workqueue, &ar->restart_work);
}
return ret;
}

View File

@ -638,7 +638,7 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel;
if ((vif->nw_type == INFRA_NETWORK)) {
if (vif->nw_type == INFRA_NETWORK) {
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
ath6kl_check_ch_switch(ar, channel);

View File

@ -37,10 +37,6 @@
#define AR5008_11NG_HT_SS_SHIFT 12
#define AR5008_11NG_HT_DS_SHIFT 20
static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
/*
* register values to turn OFDM weak signal detection OFF
*/

View File

@ -1074,7 +1074,6 @@ struct ath_softc {
struct ath_spec_scan_priv spec_priv;
struct ieee80211_vif *tx99_vif;
struct sk_buff *tx99_skb;
bool tx99_state;
s16 tx99_power;

View File

@ -116,7 +116,7 @@ void ath_debug_rate_stats(struct ath_softc *sc,
if (rxs->rate_idx >= ARRAY_SIZE(rstats->ht_stats))
goto exit;
if ((rxs->bw == RATE_INFO_BW_40))
if (rxs->bw == RATE_INFO_BW_40)
rstats->ht_stats[rxs->rate_idx].ht40_cnt++;
else
rstats->ht_stats[rxs->rate_idx].ht20_cnt++;

View File

@ -1251,15 +1251,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_vif *avp = (void *)vif->drv_priv;
struct ath_node *an = &avp->mcast_node;
mutex_lock(&sc->mutex);
if (IS_ENABLED(CONFIG_ATH9K_TX99))
return -EOPNOTSUPP;
if (IS_ENABLED(CONFIG_ATH9K_TX99)) {
if (sc->cur_chan->nvifs >= 1) {
mutex_unlock(&sc->mutex);
return -EOPNOTSUPP;
}
sc->tx99_vif = vif;
}
mutex_lock(&sc->mutex);
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
sc->cur_chan->nvifs++;
@ -1342,7 +1337,6 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
ath9k_p2p_remove_vif(sc, vif);
sc->cur_chan->nvifs--;
sc->tx99_vif = NULL;
if (!ath9k_is_chanctx_enabled())
list_del(&avp->list);

View File

@ -54,12 +54,6 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info;
struct sk_buff *skb;
struct ath_vif *avp;
if (!sc->tx99_vif)
return NULL;
avp = (struct ath_vif *)sc->tx99_vif->drv_priv;
skb = alloc_skb(len, GFP_KERNEL);
if (!skb)
@ -77,14 +71,11 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)
memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
tx_info = IEEE80211_SKB_CB(skb);
memset(tx_info, 0, sizeof(*tx_info));
rate = &tx_info->control.rates[0];
tx_info->band = sc->cur_chan->chandef.chan->band;
tx_info->flags = IEEE80211_TX_CTL_NO_ACK;
tx_info->control.vif = sc->tx99_vif;
rate->count = 1;
if (ah->curchan && IS_CHAN_HT(ah->curchan)) {
rate->flags |= IEEE80211_TX_RC_MCS;

View File

@ -2973,7 +2973,7 @@ int ath9k_tx99_send(struct ath_softc *sc, struct sk_buff *skb,
return -EINVAL;
}
ath_set_rates(sc->tx99_vif, NULL, bf);
ath_set_rates(NULL, NULL, bf);
ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr);
ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum);

View File

@ -174,13 +174,12 @@ static int wcn36xx_dxe_init_descs(struct device *dev, struct wcn36xx_dxe_ch *wcn
int i;
size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
wcn_ch->cpu_addr = dma_alloc_coherent(dev, size, &wcn_ch->dma_addr,
GFP_KERNEL);
wcn_ch->cpu_addr = dma_zalloc_coherent(dev, size,
&wcn_ch->dma_addr,
GFP_KERNEL);
if (!wcn_ch->cpu_addr)
return -ENOMEM;
memset(wcn_ch->cpu_addr, 0, size);
cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr;
cur_ctl = wcn_ch->head_blk_ctl;
@ -628,13 +627,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->mgmt_mem_pool.phy_addr,
GFP_KERNEL);
cpu_addr = dma_zalloc_coherent(wcn->dev, s,
&wcn->mgmt_mem_pool.phy_addr,
GFP_KERNEL);
if (!cpu_addr)
goto out_err;
wcn->mgmt_mem_pool.virt_addr = cpu_addr;
memset(cpu_addr, 0, s);
/* Allocate BD headers for DATA frames */
@ -643,13 +642,13 @@ int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
16 - (WCN36XX_BD_CHUNK_SIZE % 8);
s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
cpu_addr = dma_alloc_coherent(wcn->dev, s, &wcn->data_mem_pool.phy_addr,
GFP_KERNEL);
cpu_addr = dma_zalloc_coherent(wcn->dev, s,
&wcn->data_mem_pool.phy_addr,
GFP_KERNEL);
if (!cpu_addr)
goto out_err;
wcn->data_mem_pool.virt_addr = cpu_addr;
memset(cpu_addr, 0, s);
return 0;

View File

@ -792,10 +792,10 @@ static int wcn36xx_smd_process_ptt_msg_rsp(void *buf, size_t len,
rsp->header.len - sizeof(rsp->ptt_msg_resp_status));
if (rsp->header.len > 0) {
*p_ptt_rsp_msg = kmalloc(rsp->header.len, GFP_ATOMIC);
*p_ptt_rsp_msg = kmemdup(rsp->ptt_msg, rsp->header.len,
GFP_ATOMIC);
if (!*p_ptt_rsp_msg)
return -ENOMEM;
memcpy(*p_ptt_rsp_msg, rsp->ptt_msg, rsp->header.len);
}
return ret;
}

View File

@ -48,9 +48,29 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
CHAN60G(1, 0),
CHAN60G(2, 0),
CHAN60G(3, 0),
/* channel 4 not supported yet */
CHAN60G(4, 0),
};
static int wil_num_supported_channels(struct wil6210_priv *wil)
{
int num_channels = ARRAY_SIZE(wil_60ghz_channels);
if (!test_bit(WMI_FW_CAPABILITY_CHANNEL_4, wil->fw_capabilities))
num_channels--;
return num_channels;
}
void update_supported_bands(struct wil6210_priv *wil)
{
struct wiphy *wiphy = wil_to_wiphy(wil);
wil_dbg_misc(wil, "update supported bands");
wiphy->bands[NL80211_BAND_60GHZ]->n_channels =
wil_num_supported_channels(wil);
}
/* Vendor id to be used in vendor specific command and events
* to user space.
* NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID,
@ -199,7 +219,9 @@ wil_mgmt_stypes[NUM_NL80211_IFTYPES] = {
.tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_RESP >> 4) |
BIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
BIT(IEEE80211_STYPE_DISASSOC >> 4),
BIT(IEEE80211_STYPE_DISASSOC >> 4) |
BIT(IEEE80211_STYPE_AUTH >> 4) |
BIT(IEEE80211_STYPE_REASSOC_RESP >> 4),
.rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
@ -871,6 +893,26 @@ static void wil_print_crypto(struct wil6210_priv *wil,
c->control_port_no_encrypt);
}
static const char *
wil_get_auth_type_name(enum nl80211_auth_type auth_type)
{
switch (auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
return "OPEN_SYSTEM";
case NL80211_AUTHTYPE_SHARED_KEY:
return "SHARED_KEY";
case NL80211_AUTHTYPE_FT:
return "FT";
case NL80211_AUTHTYPE_NETWORK_EAP:
return "NETWORK_EAP";
case NL80211_AUTHTYPE_SAE:
return "SAE";
case NL80211_AUTHTYPE_AUTOMATIC:
return "AUTOMATIC";
default:
return "unknown";
}
}
static void wil_print_connect_params(struct wil6210_priv *wil,
struct cfg80211_connect_params *sme)
{
@ -884,11 +926,73 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
if (sme->ssid)
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
16, 1, sme->ssid, sme->ssid_len, true);
if (sme->prev_bssid)
wil_info(wil, " Previous BSSID=%pM\n", sme->prev_bssid);
wil_info(wil, " Auth Type: %s\n",
wil_get_auth_type_name(sme->auth_type));
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
wil_info(wil, " PBSS: %d\n", sme->pbss);
wil_print_crypto(wil, &sme->crypto);
}
static int wil_ft_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wmi_ft_auth_cmd auth_cmd;
int rc;
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
wil_err(wil, "FT: FW does not support FT roaming\n");
return -EOPNOTSUPP;
}
if (!sme->prev_bssid) {
wil_err(wil, "FT: prev_bssid was not set\n");
return -EINVAL;
}
if (ether_addr_equal(sme->prev_bssid, sme->bssid)) {
wil_err(wil, "FT: can not roam to same AP\n");
return -EINVAL;
}
if (!test_bit(wil_vif_fwconnected, vif->status)) {
wil_err(wil, "FT: roam while not connected\n");
return -EINVAL;
}
if (vif->privacy != sme->privacy) {
wil_err(wil, "FT: privacy mismatch, current (%d) roam (%d)\n",
vif->privacy, sme->privacy);
return -EINVAL;
}
if (sme->pbss) {
wil_err(wil, "FT: roam is not valid for PBSS\n");
return -EINVAL;
}
memset(&auth_cmd, 0, sizeof(auth_cmd));
auth_cmd.channel = sme->channel->hw_value - 1;
ether_addr_copy(auth_cmd.bssid, sme->bssid);
wil_info(wil, "FT: roaming\n");
set_bit(wil_vif_ft_roam, vif->status);
rc = wmi_send(wil, WMI_FT_AUTH_CMDID, vif->mid,
&auth_cmd, sizeof(auth_cmd));
if (rc == 0)
mod_timer(&vif->connect_timer,
jiffies + msecs_to_jiffies(5000));
else
clear_bit(wil_vif_ft_roam, vif->status);
return rc;
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_connect_params *sme)
@ -901,14 +1005,23 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
const u8 *rsn_eid;
int ch;
int rc = 0;
bool is_ft_roam = false;
u8 network_type;
enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS;
wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid);
wil_print_connect_params(wil, sme);
if (test_bit(wil_vif_fwconnecting, vif->status) ||
if (sme->auth_type == NL80211_AUTHTYPE_FT)
is_ft_roam = true;
if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC &&
test_bit(wil_vif_fwconnected, vif->status))
return -EALREADY;
is_ft_roam = true;
if (!is_ft_roam)
if (test_bit(wil_vif_fwconnecting, vif->status) ||
test_bit(wil_vif_fwconnected, vif->status))
return -EALREADY;
if (sme->ie_len > WMI_MAX_IE_LEN) {
wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len);
@ -918,8 +1031,13 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
rsn_eid = sme->ie ?
cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
NULL;
if (sme->privacy && !rsn_eid)
if (sme->privacy && !rsn_eid) {
wil_info(wil, "WSC connection\n");
if (is_ft_roam) {
wil_err(wil, "No WSC with FT roam\n");
return -EINVAL;
}
}
if (sme->pbss)
bss_type = IEEE80211_BSS_TYPE_PBSS;
@ -941,6 +1059,45 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
vif->privacy = sme->privacy;
vif->pbss = sme->pbss;
rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
if (rc)
goto out;
switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
case WLAN_CAPABILITY_DMG_TYPE_AP:
network_type = WMI_NETTYPE_INFRA;
break;
case WLAN_CAPABILITY_DMG_TYPE_PBSS:
network_type = WMI_NETTYPE_P2P;
break;
default:
wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
bss->capability);
rc = -EINVAL;
goto out;
}
ch = bss->channel->hw_value;
if (ch == 0) {
wil_err(wil, "BSS at unknown frequency %dMhz\n",
bss->channel->center_freq);
rc = -EOPNOTSUPP;
goto out;
}
if (is_ft_roam) {
if (network_type != WMI_NETTYPE_INFRA) {
wil_err(wil, "FT: Unsupported BSS type, capability= 0x%04x\n",
bss->capability);
rc = -EINVAL;
goto out;
}
rc = wil_ft_connect(wiphy, ndev, sme);
if (rc == 0)
vif->bss = bss;
goto out;
}
if (vif->privacy) {
/* For secure assoc, remove old keys */
rc = wmi_del_cipher_key(vif, 0, bss->bssid,
@ -957,28 +1114,9 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
}
}
/* WMI_SET_APPIE_CMD. ie may contain rsn info as well as other info
* elements. Send it also in case it's empty, to erase previously set
* ies in FW.
*/
rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
if (rc)
goto out;
/* WMI_CONNECT_CMD */
memset(&conn, 0, sizeof(conn));
switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
case WLAN_CAPABILITY_DMG_TYPE_AP:
conn.network_type = WMI_NETTYPE_INFRA;
break;
case WLAN_CAPABILITY_DMG_TYPE_PBSS:
conn.network_type = WMI_NETTYPE_P2P;
break;
default:
wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
bss->capability);
goto out;
}
conn.network_type = network_type;
if (vif->privacy) {
if (rsn_eid) { /* regular secure connection */
conn.dot11_auth_mode = WMI_AUTH11_SHARED;
@ -998,14 +1136,6 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
conn.ssid_len = min_t(u8, ssid_eid[1], 32);
memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);
ch = bss->channel->hw_value;
if (ch == 0) {
wil_err(wil, "BSS at unknown frequency %dMhz\n",
bss->channel->center_freq);
rc = -EOPNOTSUPP;
goto out;
}
conn.channel = ch - 1;
ether_addr_copy(conn.bssid, bss->bssid);
@ -1201,9 +1331,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid,
return &wil->sta[cid];
}
static void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
struct wil_sta_info *cs,
struct key_params *params)
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
struct wil_sta_info *cs,
struct key_params *params)
{
struct wil_tid_crypto_rx_single *cc;
int tid;
@ -1286,13 +1416,19 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
params->seq_len, params->seq);
if (IS_ERR(cs)) {
wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
mac_addr, key_usage_str[key_usage], key_index,
params->seq_len, params->seq);
return -EINVAL;
/* in FT, sta info may not be available as add_key may be
* sent by host before FW sends WMI_CONNECT_EVENT
*/
if (!test_bit(wil_vif_ft_roam, vif->status)) {
wil_err(wil, "Not connected, %pM %s[%d] PN %*phN\n",
mac_addr, key_usage_str[key_usage], key_index,
params->seq_len, params->seq);
return -EINVAL;
}
}
wil_del_rx_key(key_index, key_usage, cs);
if (!IS_ERR(cs))
wil_del_rx_key(key_index, key_usage, cs);
if (params->seq && params->seq_len != IEEE80211_GCMP_PN_LEN) {
wil_err(wil,
@ -1305,7 +1441,10 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy,
rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len,
params->key, key_usage);
if (!rc)
if (!rc && !IS_ERR(cs))
/* in FT set crypto will take place upon receiving
* WMI_RING_EN_EVENTID event
*/
wil_set_crypto_rx(key_index, key_usage, cs, params);
return rc;
@ -1468,21 +1607,36 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
}
/* internal functions for device reset and starting AP */
static u8 *
_wil_cfg80211_get_proberesp_ies(const u8 *proberesp, u16 proberesp_len,
u16 *ies_len)
{
u8 *ies = NULL;
if (proberesp) {
struct ieee80211_mgmt *f =
(struct ieee80211_mgmt *)proberesp;
size_t hlen = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
ies = f->u.probe_resp.variable;
if (ies_len)
*ies_len = proberesp_len - hlen;
}
return ies;
}
static int _wil_cfg80211_set_ies(struct wil6210_vif *vif,
struct cfg80211_beacon_data *bcon)
{
int rc;
u16 len = 0, proberesp_len = 0;
u8 *ies = NULL, *proberesp = NULL;
u8 *ies = NULL, *proberesp;
if (bcon->probe_resp) {
struct ieee80211_mgmt *f =
(struct ieee80211_mgmt *)bcon->probe_resp;
size_t hlen = offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
proberesp = f->u.probe_resp.variable;
proberesp_len = bcon->probe_resp_len - hlen;
}
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
bcon->probe_resp_len,
&proberesp_len);
rc = _wil_cfg80211_merge_extra_ies(proberesp,
proberesp_len,
bcon->proberesp_ies,
@ -1526,6 +1680,9 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
struct wireless_dev *wdev = ndev->ieee80211_ptr;
u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype);
u8 is_go = (wdev->iftype == NL80211_IFTYPE_P2P_GO);
u16 proberesp_len = 0;
u8 *proberesp;
bool ft = false;
if (pbss)
wmi_nettype = WMI_NETTYPE_P2P;
@ -1538,6 +1695,25 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_set_recovery_state(wil, fw_recovery_idle);
proberesp = _wil_cfg80211_get_proberesp_ies(bcon->probe_resp,
bcon->probe_resp_len,
&proberesp_len);
/* check that the probe response IEs has a MDE */
if ((proberesp && proberesp_len > 0 &&
cfg80211_find_ie(WLAN_EID_MOBILITY_DOMAIN,
proberesp,
proberesp_len)))
ft = true;
if (ft) {
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING,
wil->fw_capabilities)) {
wil_err(wil, "FW does not support FT roaming\n");
return -ENOTSUPP;
}
set_bit(wil_vif_ft_roam, vif->status);
}
mutex_lock(&wil->mutex);
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
@ -1699,6 +1875,7 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
mutex_lock(&wil->mutex);
wmi_pcp_stop(vif);
clear_bit(wil_vif_ft_roam, vif->status);
if (last)
__wil_down(wil);
@ -1718,8 +1895,9 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy,
struct wil6210_vif *vif = ndev_to_vif(dev);
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "add station %pM aid %d mid %d\n",
mac, params->aid, vif->mid);
wil_dbg_misc(wil, "add station %pM aid %d mid %d mask 0x%x set 0x%x\n",
mac, params->aid, vif->mid,
params->sta_flags_mask, params->sta_flags_set);
if (!disable_ap_sme) {
wil_err(wil, "not supported with AP SME enabled\n");
@ -2040,6 +2218,54 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
static int
wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
struct wil6210_vif *vif = ndev_to_vif(dev);
struct cfg80211_bss *bss;
struct wmi_ft_reassoc_cmd reassoc;
int rc = 0;
wil_dbg_misc(wil, "update ft ies, mid=%d\n", vif->mid);
wil_hex_dump_misc("FT IE ", DUMP_PREFIX_OFFSET, 16, 1,
ftie->ie, ftie->ie_len, true);
if (!test_bit(WMI_FW_CAPABILITY_FT_ROAMING, wil->fw_capabilities)) {
wil_err(wil, "FW does not support FT roaming\n");
return -EOPNOTSUPP;
}
rc = wmi_update_ft_ies(vif, ftie->ie_len, ftie->ie);
if (rc)
return rc;
if (!test_bit(wil_vif_ft_roam, vif->status))
/* vif is not roaming */
return 0;
/* wil_vif_ft_roam is set. wil_cfg80211_update_ft_ies is used as
* a trigger for reassoc
*/
bss = vif->bss;
if (!bss) {
wil_err(wil, "FT: bss is NULL\n");
return -EINVAL;
}
memset(&reassoc, 0, sizeof(reassoc));
ether_addr_copy(reassoc.bssid, bss->bssid);
rc = wmi_send(wil, WMI_FT_REASSOC_CMDID, vif->mid,
&reassoc, sizeof(reassoc));
if (rc)
wil_err(wil, "FT: reassoc failed (%d)\n", rc);
return rc;
}
static const struct cfg80211_ops wil_cfg80211_ops = {
.add_virtual_intf = wil_cfg80211_add_iface,
.del_virtual_intf = wil_cfg80211_del_iface,
@ -2075,6 +2301,7 @@ static const struct cfg80211_ops wil_cfg80211_ops = {
.resume = wil_cfg80211_resume,
.sched_scan_start = wil_cfg80211_sched_scan_start,
.sched_scan_stop = wil_cfg80211_sched_scan_stop,
.update_ft_ies = wil_cfg80211_update_ft_ies,
};
static void wil_wiphy_init(struct wiphy *wiphy)

View File

@ -725,32 +725,6 @@ struct dentry *wil_debugfs_create_ioblob(const char *name,
return debugfs_create_file(name, mode, parent, wil_blob, &fops_ioblob);
}
/*---reset---*/
static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
struct wil6210_priv *wil = file->private_data;
struct net_device *ndev = wil->main_ndev;
/**
* BUG:
* this code does NOT sync device state with the rest of system
* use with care, debug only!!!
*/
rtnl_lock();
dev_close(ndev);
ndev->flags &= ~IFF_UP;
rtnl_unlock();
wil_reset(wil, true);
return len;
}
static const struct file_operations fops_reset = {
.write = wil_write_file_reset,
.open = simple_open,
};
/*---write channel 1..4 to rxon for it, 0 to rxoff---*/
static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
@ -1263,6 +1237,9 @@ static int wil_rx_buff_mgmt_debugfs_show(struct seq_file *s, void *data)
int num_active;
int num_free;
if (!rbm->buff_arr)
return -EINVAL;
seq_printf(s, " size = %zu\n", rbm->size);
seq_printf(s, " free_list_empty_cnt = %lu\n",
rbm->free_list_empty_cnt);
@ -1695,6 +1672,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
char *status = "unknown";
u8 aid = 0;
u8 mid;
bool sta_connected = false;
switch (p->status) {
case wil_sta_unused:
@ -1709,8 +1687,20 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
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 (mid < wil->max_vifs) {
struct wil6210_vif *vif = wil->vifs[mid];
if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
p->status == wil_sta_connected)
sta_connected = true;
}
/* print roam counter only for connected stations */
if (sta_connected)
seq_printf(s, "[%d] %pM connected (roam counter %d) MID %d AID %d\n",
i, p->addr, p->stats.ft_roams, mid, aid);
else
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i,
p->addr, status, mid, aid);
if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock);
@ -2451,7 +2441,6 @@ static const struct {
{"desc", 0444, &fops_txdesc},
{"bf", 0444, &fops_bf},
{"mem_val", 0644, &fops_memread},
{"reset", 0244, &fops_reset},
{"rxon", 0244, &fops_rxon},
{"tx_mgmt", 0244, &fops_txmgmt},
{"wmi_send", 0244, &fops_wmi},

View File

@ -223,6 +223,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
struct net_device *ndev = vif_to_ndev(vif);
struct wireless_dev *wdev = vif_to_wdev(vif);
struct wil_sta_info *sta = &wil->sta[cid];
int min_ring_id = wil_get_min_tx_ring_id(wil);
might_sleep();
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
@ -273,7 +274,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
memset(sta->tid_crypto_rx, 0, sizeof(sta->tid_crypto_rx));
memset(&sta->group_crypto_rx, 0, sizeof(sta->group_crypto_rx));
/* release vrings */
for (i = 0; i < ARRAY_SIZE(wil->ring_tx); i++) {
for (i = min_ring_id; i < ARRAY_SIZE(wil->ring_tx); i++) {
if (wil->ring2cid_tid[i][0] == cid)
wil_ring_fini_tx(wil, i);
}
@ -360,6 +361,8 @@ static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
vif->bss = NULL;
}
clear_bit(wil_vif_fwconnecting, vif->status);
clear_bit(wil_vif_ft_roam, vif->status);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
@ -604,8 +607,10 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->sta[i].mid = U8_MAX;
}
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
spin_lock_init(&wil->ring_tx_data[i].lock);
wil->ring2cid_tid[i][0] = WIL6210_MAX_CID;
}
mutex_init(&wil->mutex);
mutex_init(&wil->vif_mutex);
@ -653,8 +658,6 @@ int wil_priv_init(struct wil6210_priv *wil)
/* edma configuration can be updated via debugfs before allocation */
wil->num_rx_status_rings = WIL_DEFAULT_NUM_RX_STATUS_RINGS;
wil->use_compressed_rx_status = true;
wil->use_rx_hw_reordering = true;
wil->tx_status_ring_order = WIL_TX_SRING_SIZE_ORDER_DEFAULT;
/* Rx status ring size should be bigger than the number of RX buffers
@ -1154,6 +1157,8 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
wil->max_agg_wsize = WIL_MAX_AGG_WSIZE;
wil->max_ampdu_size = WIL_MAX_AMPDU_SIZE;
}
update_supported_bands(wil);
}
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)

View File

@ -108,6 +108,7 @@ 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->use_compressed_rx_status = 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))

View File

@ -382,11 +382,13 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
}
/* apply */
r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
spin_lock_bh(&sta->tid_rx_lock);
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
sta->tid_rx[tid] = r;
spin_unlock_bh(&sta->tid_rx_lock);
if (!wil->use_rx_hw_reordering) {
r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
spin_lock_bh(&sta->tid_rx_lock);
wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
sta->tid_rx[tid] = r;
spin_unlock_bh(&sta->tid_rx_lock);
}
out:
return rc;

View File

@ -77,8 +77,9 @@ bool wil_is_tx_idle(struct wil6210_priv *wil)
{
int i;
unsigned long data_comp_to;
int min_ring_id = wil_get_min_tx_ring_id(wil);
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
struct wil_ring *vring = &wil->ring_tx[i];
int vring_index = vring - wil->ring_tx;
struct wil_ring_tx_data *txdata =
@ -765,7 +766,14 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
return;
}
if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (wdev->iftype == NL80211_IFTYPE_STATION) {
if (mcast && ether_addr_equal(eth->h_source, ndev->dev_addr)) {
/* mcast packet looped back to us */
rc = GRO_DROP;
dev_kfree_skb(skb);
goto stats;
}
} else if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (mcast) {
/* send multicast frames both to higher layers in
* local net stack and back to the wireless medium
@ -1051,6 +1059,88 @@ static int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
return rc;
}
static int wil_tx_vring_modify(struct wil6210_vif *vif, int ring_id, int cid,
int tid)
{
struct wil6210_priv *wil = vif_to_wil(vif);
int rc;
struct wmi_vring_cfg_cmd cmd = {
.action = cpu_to_le32(WMI_VRING_CMD_MODIFY),
.vring_cfg = {
.tx_sw_ring = {
.max_mpdu_size =
cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.ring_size = 0,
},
.ringid = ring_id,
.cidxtid = mk_cidxtid(cid, tid),
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
.mac_ctrl = 0,
.to_resolution = 0,
.agg_max_wsize = 0,
.schd_params = {
.priority = cpu_to_le16(0),
.timeslot_us = cpu_to_le16(0xfff),
},
},
};
struct {
struct wmi_cmd_hdr wmi;
struct wmi_vring_cfg_done_event cmd;
} __packed reply = {
.cmd = {.status = WMI_FW_STATUS_FAILURE},
};
struct wil_ring *vring = &wil->ring_tx[ring_id];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[ring_id];
wil_dbg_misc(wil, "vring_modify: ring %d cid %d tid %d\n", ring_id,
cid, tid);
lockdep_assert_held(&wil->mutex);
if (!vring->va) {
wil_err(wil, "Tx ring [%d] not allocated\n", ring_id);
return -EINVAL;
}
if (wil->ring2cid_tid[ring_id][0] != cid ||
wil->ring2cid_tid[ring_id][1] != tid) {
wil_err(wil, "ring info does not match cid=%u tid=%u\n",
wil->ring2cid_tid[ring_id][0],
wil->ring2cid_tid[ring_id][1]);
}
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc)
goto fail;
if (reply.cmd.status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "Tx modify failed, status 0x%02x\n",
reply.cmd.status);
rc = -EINVAL;
goto fail;
}
/* set BA aggregation window size to 0 to force a new BA with the
* new AP
*/
txdata->agg_wsize = 0;
if (txdata->dot1x_open && agg_wsize >= 0)
wil_addba_tx_request(wil, ring_id, agg_wsize);
return 0;
fail:
spin_lock_bh(&txdata->lock);
txdata->dot1x_open = false;
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil->ring2cid_tid[ring_id][0] = WIL6210_MAX_CID;
wil->ring2cid_tid[ring_id][1] = 0;
return rc;
}
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
{
struct wil6210_priv *wil = vif_to_wil(vif);
@ -1935,6 +2025,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
bool check_stop)
{
int i;
int min_ring_id = wil_get_min_tx_ring_id(wil);
if (unlikely(!vif))
return;
@ -1967,7 +2058,7 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
return;
/* check wake */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
struct wil_ring *cur_ring = &wil->ring_tx[i];
struct wil_ring_tx_data *txdata = &wil->ring_tx_data[i];
@ -2272,6 +2363,7 @@ void wil_init_txrx_ops_legacy_dma(struct wil6210_priv *wil)
wil->txrx_ops.ring_init_bcast = wil_vring_init_bcast;
wil->txrx_ops.tx_init = wil_tx_init;
wil->txrx_ops.tx_fini = wil_tx_fini;
wil->txrx_ops.tx_ring_modify = wil_tx_vring_modify;
/* RX ops */
wil->txrx_ops.rx_init = wil_rx_init;
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp;

View File

@ -279,9 +279,6 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
u16 buff_id;
*d = *_d;
pa = wil_rx_desc_get_addr_edma(&d->dma);
dmalen = le16_to_cpu(d->dma.length);
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
/* Extract the SKB from the rx_buff management array */
buff_id = __le16_to_cpu(d->mac.buff_id);
@ -291,10 +288,15 @@ static void wil_move_all_rx_buff_to_free_list(struct wil6210_priv *wil,
}
skb = wil->rx_buff_mgmt.buff_arr[buff_id].skb;
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (unlikely(!skb))
if (unlikely(!skb)) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
else
} else {
pa = wil_rx_desc_get_addr_edma(&d->dma);
dmalen = le16_to_cpu(d->dma.length);
dma_unmap_single(dev, pa, dmalen, DMA_FROM_DEVICE);
kfree_skb(skb);
}
/* Move the buffer from the active to the free list */
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
@ -745,6 +747,16 @@ static int wil_ring_init_tx_edma(struct wil6210_vif *vif, int ring_id,
return rc;
}
static int wil_tx_ring_modify_edma(struct wil6210_vif *vif, int ring_id,
int cid, int tid)
{
struct wil6210_priv *wil = vif_to_wil(vif);
wil_err(wil, "ring modify is not supported for EDMA\n");
return -EOPNOTSUPP;
}
/* This function is used only for RX SW reorder */
static int wil_check_bar(struct wil6210_priv *wil, void *msg, int cid,
struct sk_buff *skb, struct wil_net_stats *stats)
@ -906,6 +918,9 @@ again:
wil->rx_buff_mgmt.buff_arr[buff_id].skb = NULL;
if (!skb) {
wil_err(wil, "No Rx skb at buff_id %d\n", buff_id);
/* Move the buffer from the active list to the free list */
list_move(&wil->rx_buff_mgmt.buff_arr[buff_id].list,
&wil->rx_buff_mgmt.free);
goto again;
}
@ -1595,6 +1610,7 @@ void wil_init_txrx_ops_edma(struct wil6210_priv *wil)
wil->txrx_ops.tx_desc_map = wil_tx_desc_map_edma;
wil->txrx_ops.tx_desc_unmap = wil_tx_desc_unmap_edma;
wil->txrx_ops.tx_ring_tso = __wil_tx_ring_tso_edma;
wil->txrx_ops.tx_ring_modify = wil_tx_ring_modify_edma;
/* RX ops */
wil->txrx_ops.rx_init = wil_rx_init_edma;
wil->txrx_ops.wmi_addba_rx_resp = wmi_addba_rx_resp_edma;

View File

@ -449,6 +449,15 @@ static inline void parse_cidxtid(u8 cidxtid, u8 *cid, u8 *tid)
*tid = (cidxtid >> 4) & 0xf;
}
/**
* wil_cid_valid - check cid is valid
* @cid: CID value
*/
static inline bool wil_cid_valid(u8 cid)
{
return (cid >= 0 && cid < WIL6210_MAX_CID);
}
struct wil6210_mbox_ring {
u32 base;
u16 entry_size; /* max. size of mbox entry, incl. all headers */
@ -577,6 +586,7 @@ struct wil_net_stats {
unsigned long rx_csum_err;
u16 last_mcs_rx;
u64 rx_per_mcs[WIL_MCS_MAX + 1];
u32 ft_roams; /* relevant in STA mode */
};
/**
@ -599,6 +609,8 @@ struct wil_txrx_ops {
struct wil_ctx *ctx);
int (*tx_ring_tso)(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct wil_ring *ring, struct sk_buff *skb);
int (*tx_ring_modify)(struct wil6210_vif *vif, int ring_id,
int cid, int tid);
irqreturn_t (*irq_tx)(int irq, void *cookie);
/* RX ops */
int (*rx_init)(struct wil6210_priv *wil, u16 ring_size);
@ -821,6 +833,7 @@ extern u8 led_polarity;
enum wil6210_vif_status {
wil_vif_fwconnecting,
wil_vif_fwconnected,
wil_vif_ft_roam,
wil_vif_status_last /* keep last */
};
@ -1204,6 +1217,7 @@ int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
int wmi_echo(struct wil6210_priv *wil);
int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
int wmi_rx_chain_add(struct wil6210_priv *wil, struct wil_ring *vring);
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
@ -1319,6 +1333,9 @@ void wil6210_unmask_irq_tx_edma(struct wil6210_priv *wil);
void wil_rx_handle(struct wil6210_priv *wil, int *quota);
void wil6210_unmask_irq_rx(struct wil6210_priv *wil);
void wil6210_unmask_irq_rx_edma(struct wil6210_priv *wil);
void wil_set_crypto_rx(u8 key_index, enum wmi_key_usage key_usage,
struct wil_sta_info *cs,
struct key_params *params);
int wil_iftype_nl2wmi(enum nl80211_iftype type);
@ -1370,4 +1387,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid,
u8 tid, u8 token, u16 status, bool amsdu,
u16 agg_wsize, u16 timeout);
void update_supported_bands(struct wil6210_priv *wil);
#endif /* __WIL6210_H__ */

View File

@ -227,6 +227,14 @@ struct blink_on_off_time led_blink_time[] = {
{WIL_LED_BLINK_ON_FAST_MS, WIL_LED_BLINK_OFF_FAST_MS},
};
struct auth_no_hdr {
__le16 auth_alg;
__le16 auth_transaction;
__le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
} __packed;
u8 led_polarity = LED_POLARITY_LOW_ACTIVE;
/**
@ -468,6 +476,12 @@ static const char *cmdid2name(u16 cmdid)
return "WMI_LINK_STATS_CMD";
case WMI_SW_TX_REQ_EXT_CMDID:
return "WMI_SW_TX_REQ_EXT_CMDID";
case WMI_FT_AUTH_CMDID:
return "WMI_FT_AUTH_CMD";
case WMI_FT_REASSOC_CMDID:
return "WMI_FT_REASSOC_CMD";
case WMI_UPDATE_FT_IES_CMDID:
return "WMI_UPDATE_FT_IES_CMD";
default:
return "Untracked CMD";
}
@ -606,6 +620,12 @@ static const char *eventid2name(u16 eventid)
return "WMI_LINK_STATS_CONFIG_DONE_EVENT";
case WMI_LINK_STATS_EVENTID:
return "WMI_LINK_STATS_EVENT";
case WMI_COMMAND_NOT_SUPPORTED_EVENTID:
return "WMI_COMMAND_NOT_SUPPORTED_EVENT";
case WMI_FT_AUTH_STATUS_EVENTID:
return "WMI_FT_AUTH_STATUS_EVENT";
case WMI_FT_REASSOC_STATUS_EVENTID:
return "WMI_FT_REASSOC_STATUS_EVENT";
default:
return "Untracked EVENT";
}
@ -1156,6 +1176,9 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
struct wmi_ring_en_event *evt = d;
u8 vri = evt->ring_index;
struct wireless_dev *wdev = vif_to_wdev(vif);
struct wil_sta_info *sta;
int cid;
struct key_params params;
wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid);
@ -1164,13 +1187,33 @@ static void wmi_evt_ring_en(struct wil6210_vif *vif, int id, void *d, int len)
return;
}
if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme)
/* in AP mode with disable_ap_sme, this is done by
* wil_cfg80211_change_station()
if (wdev->iftype != NL80211_IFTYPE_AP || !disable_ap_sme ||
test_bit(wil_vif_ft_roam, vif->status))
/* in AP mode with disable_ap_sme that is not FT,
* this is done by wil_cfg80211_change_station()
*/
wil->ring_tx_data[vri].dot1x_open = true;
if (vri == vif->bcast_ring) /* no BA for bcast */
return;
cid = wil->ring2cid_tid[vri][0];
if (!wil_cid_valid(cid)) {
wil_err(wil, "invalid cid %d for vring %d\n", cid, vri);
return;
}
/* In FT mode we get key but not store it as it is received
* before WMI_CONNECT_EVENT received from FW.
* wil_set_crypto_rx is called here to reset the security PN
*/
sta = &wil->sta[cid];
if (test_bit(wil_vif_ft_roam, vif->status)) {
memset(&params, 0, sizeof(params));
wil_set_crypto_rx(0, WMI_KEY_USE_PAIRWISE, sta, &params);
if (wdev->iftype != NL80211_IFTYPE_AP)
clear_bit(wil_vif_ft_roam, vif->status);
}
if (agg_wsize >= 0)
wil_addba_tx_request(wil, vri, agg_wsize);
}
@ -1461,6 +1504,271 @@ wmi_evt_link_stats(struct wil6210_vif *vif, int id, void *d, int len)
evt->payload, payload_size);
}
/**
* find cid and ringid for the station vif
*
* return error, if other interfaces are used or ring was not found
*/
static int wil_find_cid_ringid_sta(struct wil6210_priv *wil,
struct wil6210_vif *vif,
int *cid,
int *ringid)
{
struct wil_ring *ring;
struct wil_ring_tx_data *txdata;
int min_ring_id = wil_get_min_tx_ring_id(wil);
int i;
u8 lcid;
if (!(vif->wdev.iftype == NL80211_IFTYPE_STATION ||
vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT)) {
wil_err(wil, "invalid interface type %d\n", vif->wdev.iftype);
return -EINVAL;
}
/* In the STA mode, it is expected to have only one ring
* for the AP we are connected to.
* find it and return the cid associated with it.
*/
for (i = min_ring_id; i < WIL6210_MAX_TX_RINGS; i++) {
ring = &wil->ring_tx[i];
txdata = &wil->ring_tx_data[i];
if (!ring->va || !txdata->enabled || txdata->mid != vif->mid)
continue;
lcid = wil->ring2cid_tid[i][0];
if (lcid >= WIL6210_MAX_CID) /* skip BCAST */
continue;
wil_dbg_wmi(wil, "find sta -> ringid %d cid %d\n", i, lcid);
*cid = lcid;
*ringid = i;
return 0;
}
wil_dbg_wmi(wil, "find sta cid while no rings active?\n");
return -ENOENT;
}
static void
wmi_evt_auth_status(struct wil6210_vif *vif, int id, void *d, int len)
{
struct wil6210_priv *wil = vif_to_wil(vif);
struct net_device *ndev = vif_to_ndev(vif);
struct wmi_ft_auth_status_event *data = d;
int ie_len = len - offsetof(struct wmi_ft_auth_status_event, ie_info);
int rc, cid = 0, ringid = 0;
struct cfg80211_ft_event_params ft;
u16 d_len;
/* auth_alg(u16) + auth_transaction(u16) + status_code(u16) */
const size_t auth_ie_offset = sizeof(u16) * 3;
struct auth_no_hdr *auth = (struct auth_no_hdr *)data->ie_info;
/* check the status */
if (ie_len >= 0 && data->status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "FT: auth failed. status %d\n", data->status);
goto fail;
}
if (ie_len < auth_ie_offset) {
wil_err(wil, "FT: auth event too short, len %d\n", len);
goto fail;
}
d_len = le16_to_cpu(data->ie_len);
if (d_len != ie_len) {
wil_err(wil,
"FT: auth ie length mismatch, d_len %d should be %d\n",
d_len, ie_len);
goto fail;
}
if (!test_bit(wil_vif_ft_roam, wil->status)) {
wil_err(wil, "FT: Not in roaming state\n");
goto fail;
}
if (le16_to_cpu(auth->auth_transaction) != 2) {
wil_err(wil, "FT: auth error. auth_transaction %d\n",
le16_to_cpu(auth->auth_transaction));
goto fail;
}
if (le16_to_cpu(auth->auth_alg) != WLAN_AUTH_FT) {
wil_err(wil, "FT: auth error. auth_alg %d\n",
le16_to_cpu(auth->auth_alg));
goto fail;
}
wil_dbg_wmi(wil, "FT: Auth to %pM successfully\n", data->mac_addr);
wil_hex_dump_wmi("FT Auth ies : ", DUMP_PREFIX_OFFSET, 16, 1,
data->ie_info, d_len, true);
/* find cid and ringid */
rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
if (rc) {
wil_err(wil, "No valid cid found\n");
goto fail;
}
if (vif->privacy) {
/* For secure assoc, remove old keys */
rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
WMI_KEY_USE_PAIRWISE);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n");
goto fail;
}
rc = wmi_del_cipher_key(vif, 0, wil->sta[cid].addr,
WMI_KEY_USE_RX_GROUP);
if (rc) {
wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n");
goto fail;
}
}
memset(&ft, 0, sizeof(ft));
ft.ies = data->ie_info + auth_ie_offset;
ft.ies_len = d_len - auth_ie_offset;
ft.target_ap = data->mac_addr;
cfg80211_ft_event(ndev, &ft);
return;
fail:
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
}
static void
wmi_evt_reassoc_status(struct wil6210_vif *vif, int id, void *d, int len)
{
struct wil6210_priv *wil = vif_to_wil(vif);
struct net_device *ndev = vif_to_ndev(vif);
struct wiphy *wiphy = wil_to_wiphy(wil);
struct wmi_ft_reassoc_status_event *data = d;
int ies_len = len - offsetof(struct wmi_ft_reassoc_status_event,
ie_info);
int rc = -ENOENT, cid = 0, ringid = 0;
int ch; /* channel number (primary) */
size_t assoc_req_ie_len = 0, assoc_resp_ie_len = 0;
u8 *assoc_req_ie = NULL, *assoc_resp_ie = NULL;
/* capinfo(u16) + listen_interval(u16) + current_ap mac addr + IEs */
const size_t assoc_req_ie_offset = sizeof(u16) * 2 + ETH_ALEN;
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
u16 d_len;
int freq;
struct cfg80211_roam_info info;
if (ies_len < 0) {
wil_err(wil, "ft reassoc event too short, len %d\n", len);
goto fail;
}
wil_dbg_wmi(wil, "Reasoc Status event: status=%d, aid=%d",
data->status, data->aid);
wil_dbg_wmi(wil, " mac_addr=%pM, beacon_ie_len=%d",
data->mac_addr, data->beacon_ie_len);
wil_dbg_wmi(wil, " reassoc_req_ie_len=%d, reassoc_resp_ie_len=%d",
le16_to_cpu(data->reassoc_req_ie_len),
le16_to_cpu(data->reassoc_resp_ie_len));
d_len = le16_to_cpu(data->beacon_ie_len) +
le16_to_cpu(data->reassoc_req_ie_len) +
le16_to_cpu(data->reassoc_resp_ie_len);
if (d_len != ies_len) {
wil_err(wil,
"ft reassoc ie length mismatch, d_len %d should be %d\n",
d_len, ies_len);
goto fail;
}
/* check the status */
if (data->status != WMI_FW_STATUS_SUCCESS) {
wil_err(wil, "ft reassoc failed. status %d\n", data->status);
goto fail;
}
/* find cid and ringid */
rc = wil_find_cid_ringid_sta(wil, vif, &cid, &ringid);
if (rc) {
wil_err(wil, "No valid cid found\n");
goto fail;
}
ch = data->channel + 1;
wil_info(wil, "FT: Roam %pM channel [%d] cid %d aid %d\n",
data->mac_addr, ch, cid, data->aid);
wil_hex_dump_wmi("reassoc AI : ", DUMP_PREFIX_OFFSET, 16, 1,
data->ie_info, len - sizeof(*data), true);
/* figure out IE's */
if (le16_to_cpu(data->reassoc_req_ie_len) > assoc_req_ie_offset) {
assoc_req_ie = &data->ie_info[assoc_req_ie_offset];
assoc_req_ie_len = le16_to_cpu(data->reassoc_req_ie_len) -
assoc_req_ie_offset;
}
if (le16_to_cpu(data->reassoc_resp_ie_len) <= assoc_resp_ie_offset) {
wil_err(wil, "FT: reassoc resp ie len is too short, len %d\n",
le16_to_cpu(data->reassoc_resp_ie_len));
goto fail;
}
assoc_resp_ie = &data->ie_info[le16_to_cpu(data->reassoc_req_ie_len) +
assoc_resp_ie_offset];
assoc_resp_ie_len = le16_to_cpu(data->reassoc_resp_ie_len) -
assoc_resp_ie_offset;
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "FT: status_resetting, cancel reassoc event\n");
/* no need for cleanup, wil_reset will do that */
return;
}
mutex_lock(&wil->mutex);
/* ring modify to set the ring for the roamed AP settings */
wil_dbg_wmi(wil,
"ft modify tx config for connection CID %d ring %d\n",
cid, ringid);
rc = wil->txrx_ops.tx_ring_modify(vif, ringid, cid, 0);
if (rc) {
wil_err(wil, "modify TX for CID %d MID %d ring %d failed (%d)\n",
cid, vif->mid, ringid, rc);
mutex_unlock(&wil->mutex);
goto fail;
}
/* Update the driver STA members with the new bss */
wil->sta[cid].aid = data->aid;
wil->sta[cid].stats.ft_roams++;
ether_addr_copy(wil->sta[cid].addr, vif->bss->bssid);
mutex_unlock(&wil->mutex);
del_timer_sync(&vif->connect_timer);
cfg80211_ref_bss(wiphy, vif->bss);
freq = ieee80211_channel_to_frequency(ch, NL80211_BAND_60GHZ);
memset(&info, 0, sizeof(info));
info.channel = ieee80211_get_channel(wiphy, freq);
info.bss = vif->bss;
info.req_ie = assoc_req_ie;
info.req_ie_len = assoc_req_ie_len;
info.resp_ie = assoc_resp_ie;
info.resp_ie_len = assoc_resp_ie_len;
cfg80211_roamed(ndev, &info, GFP_KERNEL);
vif->bss = NULL;
return;
fail:
wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID, false);
}
/**
* Some events are ignored for purpose; and need not be interpreted as
* "unhandled events"
@ -1492,6 +1800,8 @@ static const struct {
{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},
{WMI_FT_AUTH_STATUS_EVENTID, wmi_evt_auth_status},
{WMI_FT_REASSOC_STATUS_EVENTID, wmi_evt_reassoc_status},
};
/*
@ -2086,6 +2396,40 @@ out:
return rc;
}
int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie)
{
struct wil6210_priv *wil = vif_to_wil(vif);
u16 len;
struct wmi_update_ft_ies_cmd *cmd;
int rc;
if (!ie)
ie_len = 0;
len = sizeof(struct wmi_update_ft_ies_cmd) + ie_len;
if (len < ie_len) {
wil_err(wil, "wraparound. ie len %d\n", ie_len);
return -EINVAL;
}
cmd = kzalloc(len, GFP_KERNEL);
if (!cmd) {
rc = -ENOMEM;
goto out;
}
cmd->ie_len = cpu_to_le16(ie_len);
memcpy(cmd->ie_info, ie, ie_len);
rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len);
kfree(cmd);
out:
if (rc)
wil_err(wil, "update ft ies failed : %d\n", rc);
return rc;
}
/**
* wmi_rxon - turn radio on/off
* @on: turn on if true, off otherwise

View File

@ -103,6 +103,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_AMSDU = 23,
WMI_FW_CAPABILITY_RAW_MODE = 24,
WMI_FW_CAPABILITY_TX_REQ_EXT = 25,
WMI_FW_CAPABILITY_CHANNEL_4 = 26,
WMI_FW_CAPABILITY_MAX,
};
@ -2369,6 +2370,7 @@ struct wmi_ft_reassoc_status_event {
__le16 beacon_ie_len;
__le16 reassoc_req_ie_len;
__le16 reassoc_resp_ie_len;
u8 reserved[4];
u8 ie_info[0];
} __packed;