Merge remote-tracking branch 'wireless-next/master' into iwlwifi-next
This commit is contained in:
@@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ar5523_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct ar5523 *ar = hw->priv;
|
||||
|
||||
|
@@ -53,7 +53,7 @@ TRACE_EVENT(ath6kl_wmi_cmd,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"id %d len %d",
|
||||
"id %d len %zd",
|
||||
__entry->id, __entry->buf_len
|
||||
)
|
||||
);
|
||||
@@ -76,7 +76,7 @@ TRACE_EVENT(ath6kl_wmi_event,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"id %d len %d",
|
||||
"id %d len %zd",
|
||||
__entry->id, __entry->buf_len
|
||||
)
|
||||
);
|
||||
@@ -108,7 +108,7 @@ TRACE_EVENT(ath6kl_sdio,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s addr 0x%x flags 0x%x len %d\n",
|
||||
"%s addr 0x%x flags 0x%x len %zd\n",
|
||||
__entry->tx ? "tx" : "rx",
|
||||
__entry->addr,
|
||||
__entry->flags,
|
||||
@@ -161,7 +161,7 @@ TRACE_EVENT(ath6kl_sdio_scat,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s addr 0x%x flags 0x%x entries %d total_len %d\n",
|
||||
"%s addr 0x%x flags 0x%x entries %d total_len %zd\n",
|
||||
__entry->tx ? "tx" : "rx",
|
||||
__entry->addr,
|
||||
__entry->flags,
|
||||
@@ -186,7 +186,7 @@ TRACE_EVENT(ath6kl_sdio_irq,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"irq len %d\n", __entry->buf_len
|
||||
"irq len %zd\n", __entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
@@ -211,7 +211,7 @@ TRACE_EVENT(ath6kl_htc_rx,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"status %d endpoint %d len %d\n",
|
||||
"status %d endpoint %d len %zd\n",
|
||||
__entry->status,
|
||||
__entry->endpoint,
|
||||
__entry->buf_len
|
||||
@@ -239,7 +239,7 @@ TRACE_EVENT(ath6kl_htc_tx,
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"status %d endpoint %d len %d\n",
|
||||
"status %d endpoint %d len %zd\n",
|
||||
__entry->status,
|
||||
__entry->endpoint,
|
||||
__entry->buf_len
|
||||
|
@@ -1745,7 +1745,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
|
||||
mutex_unlock(&sc->mutex);
|
||||
}
|
||||
|
||||
static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
@@ -1703,7 +1703,7 @@ found:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct ar9170 *ar = hw->priv;
|
||||
unsigned int vid;
|
||||
|
@@ -2780,9 +2780,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
|
||||
switch (dev->dev->bus_type) {
|
||||
#ifdef CONFIG_B43_BCMA
|
||||
case B43_BUS_BCMA:
|
||||
bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
|
||||
(bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
|
||||
BCMA_CC_GPIOCTL) & ~mask) | set);
|
||||
bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_B43_SSB
|
||||
@@ -2807,8 +2805,7 @@ static void b43_gpio_cleanup(struct b43_wldev *dev)
|
||||
switch (dev->dev->bus_type) {
|
||||
#ifdef CONFIG_B43_BCMA
|
||||
case B43_BUS_BCMA:
|
||||
bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
|
||||
0);
|
||||
bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, ~0, 0);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_B43_SSB
|
||||
|
@@ -104,14 +104,8 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
|
||||
maxpwr = sprom->maxpwr_bg;
|
||||
lpphy->max_tx_pwr_med_band = maxpwr;
|
||||
cckpo = sprom->cck2gpo;
|
||||
/*
|
||||
* We don't read SPROM's opo as specs say. On rev8 SPROMs
|
||||
* opo == ofdm2gpo and we don't know any SSB with LP-PHY
|
||||
* and SPROM rev below 8.
|
||||
*/
|
||||
B43_WARN_ON(sprom->revision < 8);
|
||||
ofdmpo = sprom->ofdm2gpo;
|
||||
if (cckpo) {
|
||||
ofdmpo = sprom->ofdm2gpo;
|
||||
for (i = 0; i < 4; i++) {
|
||||
lpphy->tx_max_rate[i] =
|
||||
maxpwr - (ofdmpo & 0xF) * 2;
|
||||
@@ -124,11 +118,11 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
|
||||
ofdmpo >>= 4;
|
||||
}
|
||||
} else {
|
||||
ofdmpo &= 0xFF;
|
||||
u8 opo = sprom->opo;
|
||||
for (i = 0; i < 4; i++)
|
||||
lpphy->tx_max_rate[i] = maxpwr;
|
||||
for (i = 4; i < 15; i++)
|
||||
lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
|
||||
lpphy->tx_max_rate[i] = maxpwr - opo;
|
||||
}
|
||||
} else { /* 5GHz */
|
||||
lpphy->tx_isolation_low_band = sprom->tri5gl;
|
||||
|
@@ -724,7 +724,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct brcms_info *wl = hw->priv;
|
||||
int ret;
|
||||
|
@@ -4704,8 +4704,7 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(il_mac_change_interface);
|
||||
|
||||
void
|
||||
il_mac_flush(struct ieee80211_hw *hw, bool drop)
|
||||
void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct il_priv *il = hw->priv;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(500);
|
||||
|
@@ -1720,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum nl80211_iftype newtype, bool newp2p);
|
||||
void il_mac_flush(struct ieee80211_hw *hw, bool drop);
|
||||
void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
|
||||
int il_alloc_txq_mem(struct il_priv *il);
|
||||
void il_free_txq_mem(struct il_priv *il);
|
||||
|
||||
|
@@ -1100,7 +1100,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
||||
}
|
||||
|
||||
static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
|
||||
|
@@ -964,6 +964,12 @@ static int mac80211_hwsim_change_interface(struct ieee80211_hw *hw,
|
||||
newtype, vif->addr);
|
||||
hwsim_check_magic(vif);
|
||||
|
||||
/*
|
||||
* interface may change from non-AP to AP in
|
||||
* which case this needs to be set up again
|
||||
*/
|
||||
vif->cab_queue = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1389,7 +1395,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
/* Not implemented, queues only on kernel side */
|
||||
}
|
||||
|
@@ -259,3 +259,22 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
|
||||
|
||||
return ret_len;
|
||||
}
|
||||
|
||||
int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
struct mwifiex_11ac_vht_cfg *cfg)
|
||||
{
|
||||
struct host_cmd_11ac_vht_cfg *vhtcfg = &cmd->params.vht_cfg;
|
||||
|
||||
cmd->command = cpu_to_le16(HostCmd_CMD_11AC_CFG);
|
||||
cmd->size = cpu_to_le16(sizeof(struct host_cmd_11ac_vht_cfg) +
|
||||
S_DS_GEN);
|
||||
vhtcfg->action = cpu_to_le16(cmd_action);
|
||||
vhtcfg->band_config = cfg->band_config;
|
||||
vhtcfg->misc_config = cfg->misc_config;
|
||||
vhtcfg->cap_info = cpu_to_le32(cfg->cap_info);
|
||||
vhtcfg->mcs_tx_set = cpu_to_le32(cfg->mcs_tx_set);
|
||||
vhtcfg->mcs_rx_set = cpu_to_le32(cfg->mcs_rx_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -20,7 +20,24 @@
|
||||
#ifndef _MWIFIEX_11AC_H_
|
||||
#define _MWIFIEX_11AC_H_
|
||||
|
||||
#define VHT_CFG_2GHZ BIT(0)
|
||||
#define VHT_CFG_5GHZ BIT(1)
|
||||
|
||||
enum vht_cfg_misc_config {
|
||||
VHT_CAP_TX_OPERATION = 1,
|
||||
VHT_CAP_ASSOCIATION,
|
||||
VHT_CAP_UAP_ONLY
|
||||
};
|
||||
|
||||
#define DEFAULT_VHT_MCS_SET 0xfffa
|
||||
#define DISABLE_VHT_MCS_SET 0xffff
|
||||
|
||||
#define VHT_BW_80_160_80P80 BIT(2)
|
||||
|
||||
int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
|
||||
struct mwifiex_bssdescriptor *bss_desc,
|
||||
u8 **buffer);
|
||||
int mwifiex_cmd_11ac_cfg(struct mwifiex_private *priv,
|
||||
struct host_cmd_ds_command *cmd, u16 cmd_action,
|
||||
struct mwifiex_11ac_vht_cfg *cfg);
|
||||
#endif /* _MWIFIEX_11AC_H_ */
|
||||
|
@@ -1374,6 +1374,13 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
}
|
||||
|
||||
mwifiex_set_ht_params(priv, bss_cfg, params);
|
||||
|
||||
if (priv->adapter->is_hw_11ac_capable) {
|
||||
mwifiex_set_vht_params(priv, bss_cfg, params);
|
||||
mwifiex_set_vht_width(priv, params->chandef.width,
|
||||
priv->ap_11ac_enabled);
|
||||
}
|
||||
|
||||
mwifiex_set_wmm_params(priv, bss_cfg, params);
|
||||
|
||||
if (params->inactivity_timeout > 0) {
|
||||
|
@@ -295,6 +295,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
|
||||
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
|
||||
#define HostCmd_CMD_MGMT_FRAME_REG 0x010c
|
||||
#define HostCmd_CMD_REMAIN_ON_CHAN 0x010d
|
||||
#define HostCmd_CMD_11AC_CFG 0x0112
|
||||
|
||||
#define PROTOCOL_NO_SECURITY 0x01
|
||||
#define PROTOCOL_STATIC_WEP 0x02
|
||||
@@ -1363,6 +1364,15 @@ struct host_cmd_ds_sys_config {
|
||||
u8 tlv[0];
|
||||
};
|
||||
|
||||
struct host_cmd_11ac_vht_cfg {
|
||||
__le16 action;
|
||||
u8 band_config;
|
||||
u8 misc_config;
|
||||
__le32 cap_info;
|
||||
__le32 mcs_tx_set;
|
||||
__le32 mcs_rx_set;
|
||||
} __packed;
|
||||
|
||||
struct host_cmd_tlv_akmp {
|
||||
struct host_cmd_tlv tlv;
|
||||
__le16 key_mgmt;
|
||||
@@ -1620,6 +1630,7 @@ struct host_cmd_ds_command {
|
||||
struct host_cmd_ds_802_11_eeprom_access eeprom;
|
||||
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
|
||||
struct host_cmd_ds_sys_config uap_sys_config;
|
||||
struct host_cmd_11ac_vht_cfg vht_cfg;
|
||||
} params;
|
||||
} __packed;
|
||||
|
||||
|
@@ -272,6 +272,14 @@ struct mwifiex_ds_pm_cfg {
|
||||
} param;
|
||||
};
|
||||
|
||||
struct mwifiex_11ac_vht_cfg {
|
||||
u8 band_config;
|
||||
u8 misc_config;
|
||||
u32 cap_info;
|
||||
u32 mcs_tx_set;
|
||||
u32 mcs_rx_set;
|
||||
};
|
||||
|
||||
struct mwifiex_ds_11n_tx_cfg {
|
||||
u16 tx_htcap;
|
||||
u16 tx_htinfo;
|
||||
|
@@ -913,8 +913,14 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv,
|
||||
void mwifiex_set_ht_params(struct mwifiex_private *priv,
|
||||
struct mwifiex_uap_bss_param *bss_cfg,
|
||||
struct cfg80211_ap_settings *params);
|
||||
void mwifiex_set_vht_params(struct mwifiex_private *priv,
|
||||
struct mwifiex_uap_bss_param *bss_cfg,
|
||||
struct cfg80211_ap_settings *params);
|
||||
void mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
|
||||
struct cfg80211_ap_settings *params);
|
||||
void mwifiex_set_vht_width(struct mwifiex_private *priv,
|
||||
enum nl80211_chan_width width,
|
||||
bool ap_11ac_disable);
|
||||
void
|
||||
mwifiex_set_wmm_params(struct mwifiex_private *priv,
|
||||
struct mwifiex_uap_bss_param *bss_cfg,
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "main.h"
|
||||
#include "wmm.h"
|
||||
#include "11n.h"
|
||||
#include "11ac.h"
|
||||
|
||||
/*
|
||||
* This function prepares command to set/get RSSI information.
|
||||
@@ -1258,6 +1259,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
|
||||
cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) +
|
||||
S_DS_GEN);
|
||||
break;
|
||||
case HostCmd_CMD_11AC_CFG:
|
||||
ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
cmd_ptr->command = cpu_to_le16(cmd_no);
|
||||
cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action);
|
||||
|
@@ -907,6 +907,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
|
||||
case HostCmd_CMD_REMAIN_ON_CHAN:
|
||||
ret = mwifiex_ret_remain_on_chan(priv, resp, data_buf);
|
||||
break;
|
||||
case HostCmd_CMD_11AC_CFG:
|
||||
break;
|
||||
case HostCmd_CMD_P2P_MODE_CFG:
|
||||
ret = mwifiex_ret_p2p_mode_cfg(priv, resp, data_buf);
|
||||
break;
|
||||
|
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "11ac.h"
|
||||
|
||||
/* This function parses security related parameters from cfg80211_ap_settings
|
||||
* and sets into FW understandable bss_config structure.
|
||||
@@ -177,6 +178,60 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
|
||||
return;
|
||||
}
|
||||
|
||||
/* This function updates 11ac related parameters from IE
|
||||
* and sets them into bss_config structure.
|
||||
*/
|
||||
void mwifiex_set_vht_params(struct mwifiex_private *priv,
|
||||
struct mwifiex_uap_bss_param *bss_cfg,
|
||||
struct cfg80211_ap_settings *params)
|
||||
{
|
||||
const u8 *vht_ie;
|
||||
|
||||
vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
|
||||
params->beacon.tail_len);
|
||||
if (vht_ie) {
|
||||
memcpy(&bss_cfg->vht_cap, vht_ie + 2,
|
||||
sizeof(struct ieee80211_vht_cap));
|
||||
priv->ap_11ac_enabled = 1;
|
||||
} else {
|
||||
priv->ap_11ac_enabled = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable VHT only when cfg80211_ap_settings has VHT IE.
|
||||
* Otherwise disable VHT.
|
||||
*/
|
||||
void mwifiex_set_vht_width(struct mwifiex_private *priv,
|
||||
enum nl80211_chan_width width,
|
||||
bool ap_11ac_enable)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
struct mwifiex_11ac_vht_cfg vht_cfg;
|
||||
|
||||
vht_cfg.band_config = VHT_CFG_5GHZ;
|
||||
vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
|
||||
|
||||
if (!ap_11ac_enable) {
|
||||
vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
|
||||
vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
|
||||
} else {
|
||||
vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
|
||||
vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
|
||||
}
|
||||
|
||||
vht_cfg.misc_config = VHT_CAP_UAP_ONLY;
|
||||
|
||||
if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
|
||||
vht_cfg.misc_config |= VHT_BW_80_160_80P80;
|
||||
|
||||
mwifiex_send_cmd_sync(priv, HostCmd_CMD_11AC_CFG,
|
||||
HostCmd_ACT_GEN_SET, 0, &vht_cfg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* This function finds supported rates IE from beacon parameter and sets
|
||||
* these rates into bss_config structure.
|
||||
*/
|
||||
|
@@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv)
|
||||
return total;
|
||||
}
|
||||
|
||||
static void p54_flush(struct ieee80211_hw *dev, bool drop)
|
||||
static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
|
||||
{
|
||||
struct p54_common *priv = dev->priv;
|
||||
unsigned int total, i;
|
||||
|
@@ -1366,7 +1366,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, u16 queue,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
|
||||
void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
|
||||
void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
|
||||
int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
|
||||
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
|
||||
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
|
||||
|
@@ -748,7 +748,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
|
||||
|
||||
void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
|
||||
void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct rt2x00_dev *rt2x00dev = hw->priv;
|
||||
struct data_queue *queue;
|
||||
|
@@ -1166,7 +1166,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
|
||||
* before switch channle or power save, or tx buffer packet
|
||||
* maybe send after offchannel or rf sleep, this may cause
|
||||
* dis-association by AP */
|
||||
static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
|
||||
|
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
(u32)hdr->addr1[2], (u32)hdr->addr1[3],
|
||||
(u32)hdr->addr1[4], (u32)hdr->addr1[5]);
|
||||
memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
|
||||
ieee80211_rx_irqsafe(hw, skb);
|
||||
ieee80211_rx(hw, skb);
|
||||
}
|
||||
|
||||
void rtl8192cu_rx_hdl(struct ieee80211_hw *hw, struct sk_buff * skb)
|
||||
|
@@ -308,6 +308,8 @@ static int _rtl_usb_init_tx(struct ieee80211_hw *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _rtl_rx_work(unsigned long param);
|
||||
|
||||
static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
@@ -324,6 +326,12 @@ static int _rtl_usb_init_rx(struct ieee80211_hw *hw)
|
||||
pr_info("rx_max_size %d, rx_urb_num %d, in_ep %d\n",
|
||||
rtlusb->rx_max_size, rtlusb->rx_urb_num, rtlusb->in_ep);
|
||||
init_usb_anchor(&rtlusb->rx_submitted);
|
||||
init_usb_anchor(&rtlusb->rx_cleanup_urbs);
|
||||
|
||||
skb_queue_head_init(&rtlusb->rx_queue);
|
||||
rtlusb->rx_work_tasklet.func = _rtl_rx_work;
|
||||
rtlusb->rx_work_tasklet.data = (unsigned long)rtlusb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -405,40 +413,30 @@ static void rtl_usb_init_sw(struct ieee80211_hw *hw)
|
||||
rtlusb->disableHWSM = true;
|
||||
}
|
||||
|
||||
#define __RADIO_TAP_SIZE_RSV 32
|
||||
|
||||
static void _rtl_rx_completed(struct urb *urb);
|
||||
|
||||
static struct sk_buff *_rtl_prep_rx_urb(struct ieee80211_hw *hw,
|
||||
struct rtl_usb *rtlusb,
|
||||
struct urb *urb,
|
||||
gfp_t gfp_mask)
|
||||
static int _rtl_prep_rx_urb(struct ieee80211_hw *hw, struct rtl_usb *rtlusb,
|
||||
struct urb *urb, gfp_t gfp_mask)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
void *buf;
|
||||
|
||||
skb = __dev_alloc_skb((rtlusb->rx_max_size + __RADIO_TAP_SIZE_RSV),
|
||||
gfp_mask);
|
||||
if (!skb) {
|
||||
buf = usb_alloc_coherent(rtlusb->udev, rtlusb->rx_max_size, gfp_mask,
|
||||
&urb->transfer_dma);
|
||||
if (!buf) {
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Failed to __dev_alloc_skb!!\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
"Failed to usb_alloc_coherent!!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* reserve some space for mac80211's radiotap */
|
||||
skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
|
||||
usb_fill_bulk_urb(urb, rtlusb->udev,
|
||||
usb_rcvbulkpipe(rtlusb->udev, rtlusb->in_ep),
|
||||
skb->data, min(skb_tailroom(skb),
|
||||
(int)rtlusb->rx_max_size),
|
||||
_rtl_rx_completed, skb);
|
||||
buf, rtlusb->rx_max_size, _rtl_rx_completed, rtlusb);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
_rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
|
||||
return skb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef __RADIO_TAP_SIZE_RSV
|
||||
|
||||
static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -522,22 +520,11 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
|
||||
if (unicast)
|
||||
rtlpriv->link_info.num_rx_inperiod++;
|
||||
}
|
||||
if (likely(rtl_action_proc(hw, skb, false))) {
|
||||
struct sk_buff *uskb = NULL;
|
||||
u8 *pdata;
|
||||
|
||||
uskb = dev_alloc_skb(skb->len + 128);
|
||||
if (uskb) { /* drop packet on allocation failure */
|
||||
memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status,
|
||||
sizeof(rx_status));
|
||||
pdata = (u8 *)skb_put(uskb, skb->len);
|
||||
memcpy(pdata, skb->data, skb->len);
|
||||
ieee80211_rx_irqsafe(hw, uskb);
|
||||
}
|
||||
if (likely(rtl_action_proc(hw, skb, false)))
|
||||
ieee80211_rx(hw, skb);
|
||||
else
|
||||
dev_kfree_skb_any(skb);
|
||||
} else {
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,15 +541,70 @@ static void _rtl_rx_pre_process(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||
while (!skb_queue_empty(&rx_queue)) {
|
||||
_skb = skb_dequeue(&rx_queue);
|
||||
_rtl_usb_rx_process_agg(hw, _skb);
|
||||
ieee80211_rx_irqsafe(hw, _skb);
|
||||
ieee80211_rx(hw, _skb);
|
||||
}
|
||||
}
|
||||
|
||||
#define __RX_SKB_MAX_QUEUED 32
|
||||
|
||||
static void _rtl_rx_work(unsigned long param)
|
||||
{
|
||||
struct rtl_usb *rtlusb = (struct rtl_usb *)param;
|
||||
struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
|
||||
struct sk_buff *skb;
|
||||
|
||||
while ((skb = skb_dequeue(&rtlusb->rx_queue))) {
|
||||
if (unlikely(IS_USB_STOP(rtlusb))) {
|
||||
dev_kfree_skb_any(skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (likely(!rtlusb->usb_rx_segregate_hdl)) {
|
||||
_rtl_usb_rx_process_noagg(hw, skb);
|
||||
} else {
|
||||
/* TO DO */
|
||||
_rtl_rx_pre_process(hw, skb);
|
||||
pr_err("rx agg not supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int padding = 0;
|
||||
|
||||
/* make function no-op when possible */
|
||||
if (NET_IP_ALIGN == 0 || len < sizeof(*hdr))
|
||||
return 0;
|
||||
|
||||
/* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */
|
||||
/* TODO: deduplicate common code, define helper function instead? */
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control)) {
|
||||
u8 *qc = ieee80211_get_qos_ctl(hdr);
|
||||
|
||||
padding ^= NET_IP_ALIGN;
|
||||
|
||||
/* Input might be invalid, avoid accessing memory outside
|
||||
* the buffer.
|
||||
*/
|
||||
if ((unsigned long)qc - (unsigned long)hdr < len &&
|
||||
*qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT)
|
||||
padding ^= NET_IP_ALIGN;
|
||||
}
|
||||
|
||||
if (ieee80211_has_a4(hdr->frame_control))
|
||||
padding ^= NET_IP_ALIGN;
|
||||
|
||||
return padding;
|
||||
}
|
||||
|
||||
#define __RADIO_TAP_SIZE_RSV 32
|
||||
|
||||
static void _rtl_rx_completed(struct urb *_urb)
|
||||
{
|
||||
struct sk_buff *skb = (struct sk_buff *)_urb->context;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct rtl_usb *rtlusb = (struct rtl_usb *)info->rate_driver_data[0];
|
||||
struct rtl_usb *rtlusb = (struct rtl_usb *)_urb->context;
|
||||
struct ieee80211_hw *hw = usb_get_intfdata(rtlusb->intf);
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
int err = 0;
|
||||
@@ -571,28 +613,50 @@ static void _rtl_rx_completed(struct urb *_urb)
|
||||
goto free;
|
||||
|
||||
if (likely(0 == _urb->status)) {
|
||||
/* If this code were moved to work queue, would CPU
|
||||
* utilization be improved? NOTE: We shall allocate another skb
|
||||
* and reuse the original one.
|
||||
*/
|
||||
skb_put(skb, _urb->actual_length);
|
||||
unsigned int padding;
|
||||
struct sk_buff *skb;
|
||||
unsigned int qlen;
|
||||
unsigned int size = _urb->actual_length;
|
||||
struct ieee80211_hdr *hdr;
|
||||
|
||||
if (likely(!rtlusb->usb_rx_segregate_hdl)) {
|
||||
struct sk_buff *_skb;
|
||||
_rtl_usb_rx_process_noagg(hw, skb);
|
||||
_skb = _rtl_prep_rx_urb(hw, rtlusb, _urb, GFP_ATOMIC);
|
||||
if (IS_ERR(_skb)) {
|
||||
err = PTR_ERR(_skb);
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Can't allocate skb for bulk IN!\n");
|
||||
return;
|
||||
}
|
||||
skb = _skb;
|
||||
} else{
|
||||
/* TO DO */
|
||||
_rtl_rx_pre_process(hw, skb);
|
||||
pr_err("rx agg not supported\n");
|
||||
if (size < RTL_RX_DESC_SIZE + sizeof(struct ieee80211_hdr)) {
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Too short packet from bulk IN! (len: %d)\n",
|
||||
size);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
qlen = skb_queue_len(&rtlusb->rx_queue);
|
||||
if (qlen >= __RX_SKB_MAX_QUEUED) {
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Pending RX skbuff queue full! (qlen: %d)\n",
|
||||
qlen);
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
hdr = (void *)(_urb->transfer_buffer + RTL_RX_DESC_SIZE);
|
||||
padding = _rtl_rx_get_padding(hdr, size - RTL_RX_DESC_SIZE);
|
||||
|
||||
skb = dev_alloc_skb(size + __RADIO_TAP_SIZE_RSV + padding);
|
||||
if (!skb) {
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Can't allocate skb for bulk IN!\n");
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
_rtl_install_trx_info(rtlusb, skb, rtlusb->in_ep);
|
||||
|
||||
/* Make sure the payload data is 4 byte aligned. */
|
||||
skb_reserve(skb, padding);
|
||||
|
||||
/* reserve some space for mac80211's radiotap */
|
||||
skb_reserve(skb, __RADIO_TAP_SIZE_RSV);
|
||||
|
||||
memcpy(skb_put(skb, size), _urb->transfer_buffer, size);
|
||||
|
||||
skb_queue_tail(&rtlusb->rx_queue, skb);
|
||||
tasklet_schedule(&rtlusb->rx_work_tasklet);
|
||||
|
||||
goto resubmit;
|
||||
}
|
||||
|
||||
@@ -608,9 +672,6 @@ static void _rtl_rx_completed(struct urb *_urb)
|
||||
}
|
||||
|
||||
resubmit:
|
||||
skb_reset_tail_pointer(skb);
|
||||
skb_trim(skb, 0);
|
||||
|
||||
usb_anchor_urb(_urb, &rtlusb->rx_submitted);
|
||||
err = usb_submit_urb(_urb, GFP_ATOMIC);
|
||||
if (unlikely(err)) {
|
||||
@@ -620,13 +681,34 @@ resubmit:
|
||||
return;
|
||||
|
||||
free:
|
||||
dev_kfree_skb_irq(skb);
|
||||
/* On some architectures, usb_free_coherent must not be called from
|
||||
* hardirq context. Queue urb to cleanup list.
|
||||
*/
|
||||
usb_anchor_urb(_urb, &rtlusb->rx_cleanup_urbs);
|
||||
}
|
||||
|
||||
#undef __RADIO_TAP_SIZE_RSV
|
||||
|
||||
static void _rtl_usb_cleanup_rx(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
|
||||
struct urb *urb;
|
||||
|
||||
usb_kill_anchored_urbs(&rtlusb->rx_submitted);
|
||||
|
||||
tasklet_kill(&rtlusb->rx_work_tasklet);
|
||||
skb_queue_purge(&rtlusb->rx_queue);
|
||||
|
||||
while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
|
||||
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
|
||||
urb->transfer_buffer, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
}
|
||||
|
||||
static int _rtl_usb_receive(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct urb *urb;
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
int i;
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
@@ -645,11 +727,10 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
skb = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
|
||||
if (IS_ERR(skb)) {
|
||||
err = _rtl_prep_rx_urb(hw, rtlusb, urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
RT_TRACE(rtlpriv, COMP_USB, DBG_EMERG,
|
||||
"Failed to prep_rx_urb!!\n");
|
||||
err = PTR_ERR(skb);
|
||||
usb_free_urb(urb);
|
||||
goto err_out;
|
||||
}
|
||||
@@ -664,6 +745,7 @@ static int _rtl_usb_receive(struct ieee80211_hw *hw)
|
||||
|
||||
err_out:
|
||||
usb_kill_anchored_urbs(&rtlusb->rx_submitted);
|
||||
_rtl_usb_cleanup_rx(hw);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -705,7 +787,7 @@ static void rtl_usb_cleanup(struct ieee80211_hw *hw)
|
||||
SET_USB_STOP(rtlusb);
|
||||
|
||||
/* clean up rx stuff. */
|
||||
usb_kill_anchored_urbs(&rtlusb->rx_submitted);
|
||||
_rtl_usb_cleanup_rx(hw);
|
||||
|
||||
/* clean up tx stuff */
|
||||
for (i = 0; i < RTL_USB_MAX_EP_NUM; i++) {
|
||||
|
@@ -136,11 +136,14 @@ struct rtl_usb {
|
||||
void (*usb_tx_cleanup)(struct ieee80211_hw *, struct sk_buff *);
|
||||
|
||||
/* Rx */
|
||||
u8 in_ep_nums ;
|
||||
u8 in_ep_nums;
|
||||
u32 in_ep; /* Bulk IN endpoint number */
|
||||
u32 rx_max_size; /* Bulk IN max buffer size */
|
||||
u32 rx_urb_num; /* How many Bulk INs are submitted to host. */
|
||||
struct usb_anchor rx_submitted;
|
||||
struct usb_anchor rx_cleanup_urbs;
|
||||
struct tasklet_struct rx_work_tasklet;
|
||||
struct sk_buff_head rx_queue;
|
||||
void (*usb_rx_segregate_hdl)(struct ieee80211_hw *, struct sk_buff *,
|
||||
struct sk_buff_head *);
|
||||
void (*usb_rx_hdl)(struct ieee80211_hw *, struct sk_buff *);
|
||||
|
@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
|
||||
wl->set_power(true);
|
||||
|
||||
ret = pm_runtime_get_sync(&func->dev);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_sync(&func->dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sdio_claim_host(func);
|
||||
sdio_enable_func(func);
|
||||
|
@@ -723,6 +723,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl)
|
||||
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4;
|
||||
wl->sched_scan_templ_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5;
|
||||
wl->max_channels_5 = WL12XX_MAX_CHANNELS_5GHZ;
|
||||
wl->ba_rx_session_count_max = WL12XX_RX_BA_MAX_SESSIONS;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
@@ -63,6 +63,8 @@
|
||||
|
||||
#define WL12XX_NUM_MAC_ADDRESSES 2
|
||||
|
||||
#define WL12XX_RX_BA_MAX_SESSIONS 3
|
||||
|
||||
struct wl127x_rx_mem_pool_addr {
|
||||
u32 addr;
|
||||
u32 addr_extra;
|
||||
|
@@ -678,6 +678,7 @@ static int wl18xx_identify_chip(struct wl1271 *wl)
|
||||
wl->sched_scan_templ_id_2_4 = CMD_TEMPL_PROBE_REQ_2_4_PERIODIC;
|
||||
wl->sched_scan_templ_id_5 = CMD_TEMPL_PROBE_REQ_5_PERIODIC;
|
||||
wl->max_channels_5 = WL18XX_MAX_CHANNELS_5GHZ;
|
||||
wl->ba_rx_session_count_max = WL18XX_RX_BA_MAX_SESSIONS;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -1144,6 +1145,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
|
||||
static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
|
||||
{
|
||||
u32 fuse;
|
||||
s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
|
||||
int ret;
|
||||
|
||||
ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
|
||||
@@ -1154,8 +1156,29 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
|
||||
rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
|
||||
|
||||
if (rom <= 0xE)
|
||||
metal = (fuse & WL18XX_METAL_VER_MASK) >>
|
||||
WL18XX_METAL_VER_OFFSET;
|
||||
else
|
||||
metal = (fuse & WL18XX_NEW_METAL_VER_MASK) >>
|
||||
WL18XX_NEW_METAL_VER_OFFSET;
|
||||
|
||||
ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
|
||||
if (rdl_ver > RDL_MAX)
|
||||
rdl_ver = RDL_NONE;
|
||||
|
||||
wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)",
|
||||
rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom);
|
||||
|
||||
if (ver)
|
||||
*ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
|
||||
*ver = pg_ver;
|
||||
|
||||
ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]);
|
||||
|
||||
|
@@ -131,6 +131,16 @@
|
||||
#define WL18XX_REG_FUSE_DATA_1_3 0xA0260C
|
||||
#define WL18XX_PG_VER_MASK 0x70
|
||||
#define WL18XX_PG_VER_OFFSET 4
|
||||
#define WL18XX_ROM_VER_MASK 0x3
|
||||
#define WL18XX_ROM_VER_OFFSET 0
|
||||
#define WL18XX_METAL_VER_MASK 0xC
|
||||
#define WL18XX_METAL_VER_OFFSET 2
|
||||
#define WL18XX_NEW_METAL_VER_MASK 0x180
|
||||
#define WL18XX_NEW_METAL_VER_OFFSET 7
|
||||
|
||||
#define WL18XX_REG_FUSE_DATA_2_3 0xA02614
|
||||
#define WL18XX_RDL_VER_MASK 0x1f00
|
||||
#define WL18XX_RDL_VER_OFFSET 8
|
||||
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_1 0xA02602
|
||||
#define WL18XX_REG_FUSE_BD_ADDR_2 0xA02606
|
||||
@@ -188,4 +198,23 @@ enum {
|
||||
NUM_BOARD_TYPES,
|
||||
};
|
||||
|
||||
enum {
|
||||
RDL_NONE = 0,
|
||||
RDL_1_HP = 1,
|
||||
RDL_2_SP = 2,
|
||||
RDL_3_HP = 3,
|
||||
RDL_4_SP = 4,
|
||||
|
||||
_RDL_LAST,
|
||||
RDL_MAX = _RDL_LAST - 1,
|
||||
};
|
||||
|
||||
static const char * const rdl_names[] = {
|
||||
[RDL_NONE] = "",
|
||||
[RDL_1_HP] = "1853 SISO",
|
||||
[RDL_2_SP] = "1857 MIMO",
|
||||
[RDL_3_HP] = "1893 SISO",
|
||||
[RDL_4_SP] = "1897 MIMO",
|
||||
};
|
||||
|
||||
#endif /* __REG_H__ */
|
||||
|
@@ -29,7 +29,7 @@
|
||||
#define WL18XX_IFTYPE_VER 5
|
||||
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
|
||||
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
|
||||
#define WL18XX_MINOR_VER 28
|
||||
#define WL18XX_MINOR_VER 39
|
||||
|
||||
#define WL18XX_CMD_MAX_SIZE 740
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
#define WL18XX_NUM_MAC_ADDRESSES 3
|
||||
|
||||
#define WL18XX_RX_BA_MAX_SESSIONS 5
|
||||
|
||||
struct wl18xx_priv {
|
||||
/* buffer for sending commands to FW */
|
||||
u8 cmd_buf[WL18XX_CMD_MAX_SIZE];
|
||||
|
@@ -1736,6 +1736,35 @@ out:
|
||||
|
||||
}
|
||||
|
||||
int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
s8 *avg_rssi)
|
||||
{
|
||||
struct acx_roaming_stats *acx;
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_ACX, "acx roaming statistics");
|
||||
|
||||
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
|
||||
if (!acx) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
acx->role_id = wlvif->role_id;
|
||||
ret = wl1271_cmd_interrogate(wl, ACX_ROAMING_STATISTICS_TBL,
|
||||
acx, sizeof(*acx));
|
||||
if (ret < 0) {
|
||||
wl1271_warning("acx roaming statistics failed: %d", ret);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*avg_rssi = acx->rssi_beacon;
|
||||
out:
|
||||
kfree(acx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/* Set the global behaviour of RX filters - On/Off + default action */
|
||||
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
|
||||
|
@@ -728,8 +728,6 @@ struct wl1271_acx_ht_information {
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
#define RX_BA_MAX_SESSIONS 3
|
||||
|
||||
struct wl1271_acx_ba_initiator_policy {
|
||||
struct acx_header header;
|
||||
|
||||
@@ -955,6 +953,18 @@ struct acx_rx_filter_cfg {
|
||||
u8 fields[0];
|
||||
} __packed;
|
||||
|
||||
struct acx_roaming_stats {
|
||||
struct acx_header header;
|
||||
|
||||
u8 role_id;
|
||||
u8 pad[3];
|
||||
u32 missed_beacons;
|
||||
u8 snr_data;
|
||||
u8 snr_bacon;
|
||||
s8 rssi_data;
|
||||
s8 rssi_beacon;
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
ACX_WAKE_UP_CONDITIONS = 0x0000,
|
||||
ACX_MEM_CFG = 0x0001,
|
||||
@@ -1112,6 +1122,8 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
|
||||
int wl1271_acx_fm_coex(struct wl1271 *wl);
|
||||
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
|
||||
int wl12xx_acx_config_hangover(struct wl1271 *wl);
|
||||
int wlcore_acx_average_rssi(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
s8 *avg_rssi);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
|
||||
|
@@ -327,6 +327,14 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
|
||||
wl->links[link].prev_freed_pkts =
|
||||
wl->fw_status_2->counters.tx_lnk_free_pkts[link];
|
||||
wl->links[link].wlvif = wlvif;
|
||||
|
||||
/*
|
||||
* Take saved value for total freed packets from wlvif, in case this is
|
||||
* recovery/resume
|
||||
*/
|
||||
if (wlvif->bss_type != BSS_TYPE_AP_BSS)
|
||||
wl->links[link].total_freed_pkts = wlvif->total_freed_pkts;
|
||||
|
||||
*hlid = link;
|
||||
|
||||
wl->active_link_count++;
|
||||
@@ -358,6 +366,26 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
|
||||
wl1271_tx_reset_link_queues(wl, *hlid);
|
||||
wl->links[*hlid].wlvif = NULL;
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
|
||||
(wlvif->bss_type == BSS_TYPE_AP_BSS &&
|
||||
*hlid == wlvif->ap.bcast_hlid)) {
|
||||
/*
|
||||
* save the total freed packets in the wlvif, in case this is
|
||||
* recovery or suspend
|
||||
*/
|
||||
wlvif->total_freed_pkts = wl->links[*hlid].total_freed_pkts;
|
||||
|
||||
/*
|
||||
* increment the initial seq number on recovery to account for
|
||||
* transmitted packets that we haven't yet got in the FW status
|
||||
*/
|
||||
if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
|
||||
wlvif->total_freed_pkts +=
|
||||
WL1271_TX_SQN_POST_RECOVERY_PADDING;
|
||||
}
|
||||
|
||||
wl->links[*hlid].total_freed_pkts = 0;
|
||||
|
||||
*hlid = WL12XX_INVALID_LINK_ID;
|
||||
wl->active_link_count--;
|
||||
WARN_ON_ONCE(wl->active_link_count < 0);
|
||||
@@ -609,6 +637,10 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
if (ret < 0)
|
||||
goto out_free_global;
|
||||
|
||||
/* use the previous security seq, if this is a recovery/resume */
|
||||
wl->links[wlvif->ap.bcast_hlid].total_freed_pkts =
|
||||
wlvif->total_freed_pkts;
|
||||
|
||||
cmd->role_id = wlvif->role_id;
|
||||
cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
|
||||
cmd->ap.bss_index = WL1271_AP_BSS_INDEX;
|
||||
|
@@ -89,25 +89,24 @@ extern u32 wl12xx_debug_level;
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* TODO: use pr_debug_hex_dump when it becomes available */
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
#define wl1271_dump(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump_debug(DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
0); \
|
||||
} while (0)
|
||||
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
#define wl1271_dump_ascii(level, prefix, buf, len) \
|
||||
do { \
|
||||
if (level & wl12xx_debug_level) \
|
||||
print_hex_dump_debug(DRIVER_PREFIX prefix, \
|
||||
DUMP_PREFIX_OFFSET, 16, 1, \
|
||||
buf, \
|
||||
min_t(size_t, len, DEBUG_DUMP_LIMIT), \
|
||||
true); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __DEBUG_H__ */
|
||||
|
@@ -598,8 +598,7 @@ static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
|
||||
VIF_STATE_PRINT_INT(last_rssi_event);
|
||||
VIF_STATE_PRINT_INT(ba_support);
|
||||
VIF_STATE_PRINT_INT(ba_allowed);
|
||||
VIF_STATE_PRINT_LLHEX(tx_security_seq);
|
||||
VIF_STATE_PRINT_INT(tx_security_last_seq_lsb);
|
||||
VIF_STATE_PRINT_LLHEX(total_freed_pkts);
|
||||
}
|
||||
|
||||
#undef VIF_STATE_PRINT_INT
|
||||
|
@@ -237,6 +237,14 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
|
||||
!test_bit(wlvif->role_id , &roles_bitmap))
|
||||
continue;
|
||||
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
/* don't attempt roaming in case of p2p */
|
||||
if (wlvif->p2p) {
|
||||
ieee80211_connection_loss(vif);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the work is already queued, it should take place.
|
||||
* We don't want to delay the connection loss
|
||||
@@ -246,7 +254,6 @@ void wlcore_event_beacon_loss(struct wl1271 *wl, unsigned long roles_bitmap)
|
||||
&wlvif->connection_loss_work,
|
||||
msecs_to_jiffies(delay));
|
||||
|
||||
vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
ieee80211_cqm_rssi_notify(
|
||||
vif,
|
||||
NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
|
||||
|
@@ -108,8 +108,7 @@ static void wl1271_reg_notify(struct wiphy *wiphy,
|
||||
|
||||
}
|
||||
|
||||
if (likely(wl->state == WLCORE_STATE_ON))
|
||||
wlcore_regdomain_config(wl);
|
||||
wlcore_regdomain_config(wl);
|
||||
}
|
||||
|
||||
static int wl1271_set_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
@@ -332,10 +331,9 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid, u8 tx_pkts)
|
||||
{
|
||||
bool fw_ps, single_link;
|
||||
bool fw_ps;
|
||||
|
||||
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
||||
single_link = (wl->active_link_count == 1);
|
||||
|
||||
/*
|
||||
* Wake up from high level PS if the STA is asleep with too little
|
||||
@@ -348,8 +346,13 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl,
|
||||
* Start high-level PS if the STA is asleep with enough blocks in FW.
|
||||
* Make an exception if this is the only connected link. In this
|
||||
* case FW-memory congestion is less of a problem.
|
||||
* Note that a single connected STA means 3 active links, since we must
|
||||
* account for the global and broadcast AP links. The "fw_ps" check
|
||||
* assures us the third link is a STA connected to the AP. Otherwise
|
||||
* the FW would not set the PSM bit.
|
||||
*/
|
||||
else if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
else if (wl->active_link_count > 3 && fw_ps &&
|
||||
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
wl12xx_ps_link_start(wl, wlvif, hlid, true);
|
||||
}
|
||||
|
||||
@@ -414,13 +417,21 @@ static int wlcore_fw_status(struct wl1271 *wl,
|
||||
|
||||
|
||||
for_each_set_bit(i, wl->links_map, WL12XX_MAX_LINKS) {
|
||||
u8 diff;
|
||||
lnk = &wl->links[i];
|
||||
/* prevent wrap-around in freed-packets counter */
|
||||
lnk->allocated_pkts -=
|
||||
(status_2->counters.tx_lnk_free_pkts[i] -
|
||||
lnk->prev_freed_pkts) & 0xff;
|
||||
|
||||
/* prevent wrap-around in freed-packets counter */
|
||||
diff = (status_2->counters.tx_lnk_free_pkts[i] -
|
||||
lnk->prev_freed_pkts) & 0xff;
|
||||
|
||||
if (diff == 0)
|
||||
continue;
|
||||
|
||||
lnk->allocated_pkts -= diff;
|
||||
lnk->prev_freed_pkts = status_2->counters.tx_lnk_free_pkts[i];
|
||||
|
||||
/* accumulate the prev_freed_pkts counter */
|
||||
lnk->total_freed_pkts += diff;
|
||||
}
|
||||
|
||||
/* prevent wrap-around in total blocks counter */
|
||||
@@ -640,6 +651,25 @@ static irqreturn_t wlcore_irq(int irq, void *cookie)
|
||||
unsigned long flags;
|
||||
struct wl1271 *wl = cookie;
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
|
||||
if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
|
||||
/* don't enqueue a work right now. mark it as pending */
|
||||
set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
|
||||
wl1271_debug(DEBUG_IRQ, "should not enqueue work");
|
||||
disable_irq_nosync(wl->irq);
|
||||
pm_wakeup_event(wl->dev, 0);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
/* TX might be handled here, avoid redundant work */
|
||||
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
|
||||
cancel_work_sync(&wl->tx_work);
|
||||
@@ -919,18 +949,6 @@ static void wl1271_recovery_work(struct work_struct *work)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance security sequence number to overcome potential progress
|
||||
* in the firmware during recovery. This doens't hurt if the network is
|
||||
* not encrypted.
|
||||
*/
|
||||
wl12xx_for_each_wlvif(wl, wlvif) {
|
||||
if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) ||
|
||||
test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
|
||||
wlvif->tx_security_seq +=
|
||||
WL1271_TX_SQN_POST_RECOVERY_PADDING;
|
||||
}
|
||||
|
||||
/* Prevent spurious TX during FW restart */
|
||||
wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART);
|
||||
|
||||
@@ -2523,6 +2541,8 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl,
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
}
|
||||
deinit:
|
||||
wl12xx_tx_reset_wlvif(wl, wlvif);
|
||||
|
||||
/* clear all hlids (except system_hlid) */
|
||||
wlvif->dev_hlid = WL12XX_INVALID_LINK_ID;
|
||||
|
||||
@@ -2546,7 +2566,6 @@ deinit:
|
||||
|
||||
dev_kfree_skb(wlvif->probereq);
|
||||
wlvif->probereq = NULL;
|
||||
wl12xx_tx_reset_wlvif(wl, wlvif);
|
||||
if (wl->last_wlvif == wlvif)
|
||||
wl->last_wlvif = NULL;
|
||||
list_del(&wlvif->list);
|
||||
@@ -2860,10 +2879,6 @@ static int wlcore_unset_assoc(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
wlvif->sta.klv_template_id,
|
||||
ACX_KEEP_ALIVE_TPL_INVALID);
|
||||
|
||||
/* reset TX security counters on a clean disconnect */
|
||||
wlvif->tx_security_last_seq_lsb = 0;
|
||||
wlvif->tx_security_seq = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3262,6 +3277,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
u32 tx_seq_32 = 0;
|
||||
u16 tx_seq_16 = 0;
|
||||
u8 key_type;
|
||||
u8 hlid;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "mac80211 set key");
|
||||
|
||||
@@ -3271,6 +3287,22 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
key_conf->keylen, key_conf->flags);
|
||||
wl1271_dump(DEBUG_CRYPT, "KEY: ", key_conf->key, key_conf->keylen);
|
||||
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
|
||||
if (sta) {
|
||||
struct wl1271_station *wl_sta = (void *)sta->drv_priv;
|
||||
hlid = wl_sta->hlid;
|
||||
} else {
|
||||
hlid = wlvif->ap.bcast_hlid;
|
||||
}
|
||||
else
|
||||
hlid = wlvif->sta.hlid;
|
||||
|
||||
if (hlid != WL12XX_INVALID_LINK_ID) {
|
||||
u64 tx_seq = wl->links[hlid].total_freed_pkts;
|
||||
tx_seq_32 = WL1271_TX_SECURITY_HI32(tx_seq);
|
||||
tx_seq_16 = WL1271_TX_SECURITY_LO16(tx_seq);
|
||||
}
|
||||
|
||||
switch (key_conf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
@@ -3280,22 +3312,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
key_type = KEY_TKIP;
|
||||
|
||||
key_conf->hw_key_idx = key_conf->keyidx;
|
||||
tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
|
||||
tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
key_type = KEY_AES;
|
||||
|
||||
key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
|
||||
tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
|
||||
break;
|
||||
case WL1271_CIPHER_SUITE_GEM:
|
||||
key_type = KEY_GEM;
|
||||
tx_seq_32 = WL1271_TX_SECURITY_HI32(wlvif->tx_security_seq);
|
||||
tx_seq_16 = WL1271_TX_SECURITY_LO16(wlvif->tx_security_seq);
|
||||
break;
|
||||
default:
|
||||
wl1271_error("Unknown key algo 0x%x", key_conf->cipher);
|
||||
@@ -3358,6 +3382,10 @@ void wlcore_regdomain_config(struct wl1271 *wl)
|
||||
return;
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@@ -4499,6 +4527,9 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* use the previous security seq, if this is a recovery/resume */
|
||||
wl->links[wl_sta->hlid].total_freed_pkts = wl_sta->total_freed_pkts;
|
||||
|
||||
set_bit(wl_sta->hlid, wlvif->ap.sta_hlid_map);
|
||||
memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
|
||||
wl->active_sta_count++;
|
||||
@@ -4507,12 +4538,37 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
|
||||
|
||||
void wl1271_free_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 hlid)
|
||||
{
|
||||
struct wl1271_station *wl_sta;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
|
||||
|
||||
if (!test_bit(hlid, wlvif->ap.sta_hlid_map))
|
||||
return;
|
||||
|
||||
clear_bit(hlid, wlvif->ap.sta_hlid_map);
|
||||
__clear_bit(hlid, &wl->ap_ps_map);
|
||||
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
||||
|
||||
/*
|
||||
* save the last used PN in the private part of iee80211_sta,
|
||||
* in case of recovery/suspend
|
||||
*/
|
||||
rcu_read_lock();
|
||||
sta = ieee80211_find_sta(vif, wl->links[hlid].addr);
|
||||
if (sta) {
|
||||
wl_sta = (void *)sta->drv_priv;
|
||||
wl_sta->total_freed_pkts = wl->links[hlid].total_freed_pkts;
|
||||
|
||||
/*
|
||||
* increment the initial seq number on recovery to account for
|
||||
* transmitted packets that we haven't yet got in the FW status
|
||||
*/
|
||||
if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
|
||||
wl_sta->total_freed_pkts +=
|
||||
WL1271_TX_SQN_POST_RECOVERY_PADDING;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
wl12xx_free_link(wl, wlvif, &hlid);
|
||||
wl->active_sta_count--;
|
||||
|
||||
@@ -4616,13 +4672,11 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
struct wl1271_station *wl_sta;
|
||||
u8 hlid;
|
||||
bool is_ap = wlvif->bss_type == BSS_TYPE_AP_BSS;
|
||||
bool is_sta = wlvif->bss_type == BSS_TYPE_STA_BSS;
|
||||
int ret;
|
||||
|
||||
wl_sta = (struct wl1271_station *)sta->drv_priv;
|
||||
hlid = wl_sta->hlid;
|
||||
|
||||
/* Add station (AP mode) */
|
||||
if (is_ap &&
|
||||
@@ -4648,12 +4702,12 @@ static int wl12xx_update_sta_state(struct wl1271 *wl,
|
||||
/* Authorize station (AP mode) */
|
||||
if (is_ap &&
|
||||
new_state == IEEE80211_STA_AUTHORIZED) {
|
||||
ret = wl12xx_cmd_set_peer_state(wl, wlvif, hlid);
|
||||
ret = wl12xx_cmd_set_peer_state(wl, wlvif, wl_sta->hlid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true,
|
||||
hlid);
|
||||
wl_sta->hlid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -4784,7 +4838,7 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
||||
break;
|
||||
}
|
||||
|
||||
if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) {
|
||||
if (wl->ba_rx_session_count >= wl->ba_rx_session_count_max) {
|
||||
ret = -EBUSY;
|
||||
wl1271_error("exceeded max RX BA sessions");
|
||||
break;
|
||||
@@ -4946,7 +5000,7 @@ out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
}
|
||||
|
||||
static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
|
||||
static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
|
||||
@@ -5092,6 +5146,39 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
|
||||
wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
|
||||
}
|
||||
|
||||
static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta,
|
||||
s8 *rssi_dbm)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret = 0;
|
||||
|
||||
wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
|
||||
|
||||
mutex_lock(&wl->mutex);
|
||||
|
||||
if (unlikely(wl->state != WLCORE_STATE_ON))
|
||||
goto out;
|
||||
|
||||
ret = wl1271_ps_elp_wakeup(wl);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
|
||||
if (ret < 0)
|
||||
goto out_sleep;
|
||||
|
||||
out_sleep:
|
||||
wl1271_ps_elp_sleep(wl);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wl->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
@@ -5291,6 +5378,7 @@ static const struct ieee80211_ops wl1271_ops = {
|
||||
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
|
||||
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
|
||||
.sta_rc_update = wlcore_op_sta_rc_update,
|
||||
.get_rssi = wlcore_op_get_rssi,
|
||||
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
|
||||
};
|
||||
|
||||
@@ -5930,35 +6018,6 @@ int wlcore_free_hw(struct wl1271 *wl)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wlcore_free_hw);
|
||||
|
||||
static irqreturn_t wl12xx_hardirq(int irq, void *cookie)
|
||||
{
|
||||
struct wl1271 *wl = cookie;
|
||||
unsigned long flags;
|
||||
|
||||
wl1271_debug(DEBUG_IRQ, "IRQ");
|
||||
|
||||
/* complete the ELP completion */
|
||||
spin_lock_irqsave(&wl->wl_lock, flags);
|
||||
set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
|
||||
if (wl->elp_compl) {
|
||||
complete(wl->elp_compl);
|
||||
wl->elp_compl = NULL;
|
||||
}
|
||||
|
||||
if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
|
||||
/* don't enqueue a work right now. mark it as pending */
|
||||
set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
|
||||
wl1271_debug(DEBUG_IRQ, "should not enqueue work");
|
||||
disable_irq_nosync(wl->irq);
|
||||
pm_wakeup_event(wl->dev, 0);
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
struct wl1271 *wl = context;
|
||||
@@ -6000,9 +6059,8 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
|
||||
else
|
||||
irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
|
||||
|
||||
ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq,
|
||||
irqflags,
|
||||
pdev->name, wl);
|
||||
ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
|
||||
irqflags, pdev->name, wl);
|
||||
if (ret < 0) {
|
||||
wl1271_error("request_irq() failed: %d", ret);
|
||||
goto out_free_nvs;
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#define WL1271_WAKEUP_TIMEOUT 500
|
||||
|
||||
#define ELP_ENTRY_DELAY 30
|
||||
#define ELP_ENTRY_DELAY_FORCE_PS 5
|
||||
|
||||
void wl1271_elp_work(struct work_struct *work)
|
||||
{
|
||||
@@ -98,7 +99,8 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
|
||||
return;
|
||||
}
|
||||
|
||||
timeout = ELP_ENTRY_DELAY;
|
||||
timeout = wl->conf.conn.forced_ps ?
|
||||
ELP_ENTRY_DELAY_FORCE_PS : ELP_ENTRY_DELAY;
|
||||
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
|
||||
msecs_to_jiffies(timeout));
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "wlcore.h"
|
||||
#include "debug.h"
|
||||
@@ -104,7 +105,7 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
|
||||
struct wl12xx_vif *wlvif,
|
||||
u8 hlid)
|
||||
{
|
||||
bool fw_ps, single_link;
|
||||
bool fw_ps;
|
||||
u8 tx_pkts;
|
||||
|
||||
if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
|
||||
@@ -112,15 +113,19 @@ static void wl1271_tx_regulate_link(struct wl1271 *wl,
|
||||
|
||||
fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
|
||||
tx_pkts = wl->links[hlid].allocated_pkts;
|
||||
single_link = (wl->active_link_count == 1);
|
||||
|
||||
/*
|
||||
* if in FW PS and there is enough data in FW we can put the link
|
||||
* into high-level PS and clean out its TX queues.
|
||||
* Make an exception if this is the only connected link. In this
|
||||
* case FW-memory congestion is less of a problem.
|
||||
* Note that a single connected STA means 3 active links, since we must
|
||||
* account for the global and broadcast AP links. The "fw_ps" check
|
||||
* assures us the third link is a STA connected to the AP. Otherwise
|
||||
* the FW would not set the PSM bit.
|
||||
*/
|
||||
if (!single_link && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
if (wl->active_link_count > 3 && fw_ps &&
|
||||
tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
|
||||
wl12xx_ps_link_start(wl, wlvif, hlid, true);
|
||||
}
|
||||
|
||||
@@ -639,6 +644,7 @@ next:
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
if (!skb &&
|
||||
test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
|
||||
int q;
|
||||
@@ -652,7 +658,6 @@ next:
|
||||
spin_unlock_irqrestore(&wl->wl_lock, flags);
|
||||
}
|
||||
|
||||
out:
|
||||
return skb;
|
||||
}
|
||||
|
||||
@@ -928,25 +933,6 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
|
||||
|
||||
wl->stats.retry_count += result->ack_failures;
|
||||
|
||||
/*
|
||||
* update sequence number only when relevant, i.e. only in
|
||||
* sessions of TKIP, AES and GEM (not in open or WEP sessions)
|
||||
*/
|
||||
if (info->control.hw_key &&
|
||||
(info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP ||
|
||||
info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) {
|
||||
u8 fw_lsb = result->tx_security_sequence_number_lsb;
|
||||
u8 cur_lsb = wlvif->tx_security_last_seq_lsb;
|
||||
|
||||
/*
|
||||
* update security sequence number, taking care of potential
|
||||
* wrap-around
|
||||
*/
|
||||
wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff;
|
||||
wlvif->tx_security_last_seq_lsb = fw_lsb;
|
||||
}
|
||||
|
||||
/* remove private header from packet */
|
||||
skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
|
||||
|
||||
@@ -1061,7 +1047,8 @@ void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
|
||||
/* TX failure */
|
||||
for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS) {
|
||||
if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
|
||||
i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
|
||||
/* this calls wl12xx_free_link */
|
||||
wl1271_free_sta(wl, wlvif, i);
|
||||
} else {
|
||||
@@ -1304,7 +1291,7 @@ bool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
|
||||
{
|
||||
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
|
||||
|
||||
WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
|
||||
assert_spin_locked(&wl->wl_lock);
|
||||
return test_bit(reason, &wl->queue_stop_reasons[hwq]);
|
||||
}
|
||||
|
||||
@@ -1313,6 +1300,6 @@ bool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
|
||||
{
|
||||
int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
|
||||
|
||||
WARN_ON_ONCE(!spin_is_locked(&wl->wl_lock));
|
||||
assert_spin_locked(&wl->wl_lock);
|
||||
return !!wl->queue_stop_reasons[hwq];
|
||||
}
|
||||
|
@@ -390,6 +390,9 @@ struct wl1271 {
|
||||
/* number of currently active RX BA sessions */
|
||||
int ba_rx_session_count;
|
||||
|
||||
/* Maximum number of supported RX BA sessions */
|
||||
int ba_rx_session_count_max;
|
||||
|
||||
/* AP-mode - number of currently connected stations */
|
||||
int active_sta_count;
|
||||
|
||||
|
@@ -274,6 +274,13 @@ struct wl1271_link {
|
||||
|
||||
/* The wlvif this link belongs to. Might be null for global links */
|
||||
struct wl12xx_vif *wlvif;
|
||||
|
||||
/*
|
||||
* total freed FW packets on the link - used for tracking the
|
||||
* AES/TKIP PN across recoveries. Re-initialized each time
|
||||
* from the wl1271_station structure.
|
||||
*/
|
||||
u64 total_freed_pkts;
|
||||
};
|
||||
|
||||
#define WL1271_MAX_RX_FILTERS 5
|
||||
@@ -318,6 +325,13 @@ struct wl12xx_rx_filter {
|
||||
struct wl1271_station {
|
||||
u8 hlid;
|
||||
bool in_connection;
|
||||
|
||||
/*
|
||||
* total freed FW packets on the link to the STA - used for tracking the
|
||||
* AES/TKIP PN across recoveries. Re-initialized each time from the
|
||||
* wl1271_station structure.
|
||||
*/
|
||||
u64 total_freed_pkts;
|
||||
};
|
||||
|
||||
struct wl12xx_vif {
|
||||
@@ -449,16 +463,15 @@ struct wl12xx_vif {
|
||||
*/
|
||||
struct {
|
||||
u8 persistent[0];
|
||||
/*
|
||||
* Security sequence number
|
||||
* bits 0-15: lower 16 bits part of sequence number
|
||||
* bits 16-47: higher 32 bits part of sequence number
|
||||
* bits 48-63: not in use
|
||||
*/
|
||||
u64 tx_security_seq;
|
||||
|
||||
/* 8 bits of the last sequence number in use */
|
||||
u8 tx_security_last_seq_lsb;
|
||||
/*
|
||||
* total freed FW packets on the link - used for
|
||||
* storing the AES/TKIP PN during recovery, as this
|
||||
* structure is not zeroed out.
|
||||
* For STA this holds the PN of the link to the AP.
|
||||
* For AP this holds the PN of the broadcast link.
|
||||
*/
|
||||
u64 total_freed_pkts;
|
||||
};
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user