wireless-drivers-next patches for 4.8
Major changes: iwlwifi * more work on the RX path for the 9000 device series * some more dynamic queue allocation work * SAR BIOS implementation * some work on debugging capabilities * added support for GCMP encryption * data path rework in preparation for new HW * some cleanup to remove transport dependency on mac80211 * support for MSIx in preparation for new HW * lots of work in preparation for HW support (9000 and a000 series) mwifiex * implement get_tx_power and get_antenna cfg80211 operation callbacks wl18xx * add support for 64bit clock rtl8xxxu * aggregation support (optional for now) Also wireless-drivers is merged to fix some conflicts. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQEcBAABAgAGBQJXhmR1AAoJEG4XJFUm622bn+gH/Ar5l/oU76nmXKh0xNiV6bUE 2FuRV9X7ynAOLbFJfqZvN8eL1kTyztXOpxVOt9xLZvNcrJP2mdOH+YdUpSPk/XRw mpFC7RCln/Y1bbX02la7V8iRJlKK1/VmdMABJXsalDcxSPMhhBQtr4/ZC7NcgmeJ zKCZDGr/x4qpmAkYGsf3msJsBotHtt9xuHp4fFswp9Gpm+VeqtdqGEeMxowoILRK QBj6nZIuLI4PMnJhfCJn94t9D/AVUIVJTeuWNDS5Up4gZVFo9SlpnkR520P0IY4Q 1238g5sAdKqONsPO0lyUacUlY2cTafDr4kD6UKnjf659KDd49MDJArpfbvMeweY= =PTV+ -----END PGP SIGNATURE----- Merge tag 'wireless-drivers-next-for-davem-2016-07-13' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next Kalle Valo says: ==================== wireless-drivers-next patches for 4.8 Major changes: iwlwifi * more work on the RX path for the 9000 device series * some more dynamic queue allocation work * SAR BIOS implementation * some work on debugging capabilities * added support for GCMP encryption * data path rework in preparation for new HW * some cleanup to remove transport dependency on mac80211 * support for MSIx in preparation for new HW * lots of work in preparation for HW support (9000 and a000 series) mwifiex * implement get_tx_power and get_antenna cfg80211 operation callbacks wl18xx * add support for 64bit clock rtl8xxxu * aggregation support (optional for now) Also wireless-drivers is merged to fix some conflicts. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
88b3ec5274
|
@ -789,12 +789,48 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
||||
struct net_device *ndev = wdev->netdev;
|
||||
struct brcmf_if *ifp = netdev_priv(ndev);
|
||||
int ret;
|
||||
int err;
|
||||
|
||||
brcmf_cfg80211_arm_vif_event(cfg, ifp->vif);
|
||||
|
||||
err = brcmf_fil_bsscfg_data_set(ifp, "interface_remove", NULL, 0);
|
||||
if (err) {
|
||||
brcmf_err("interface_remove failed %d\n", err);
|
||||
goto err_unarm;
|
||||
}
|
||||
|
||||
/* wait for firmware event */
|
||||
ret = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
|
||||
BRCMF_VIF_EVENT_TIMEOUT);
|
||||
if (!ret) {
|
||||
brcmf_err("timeout occurred\n");
|
||||
err = -EIO;
|
||||
goto err_unarm;
|
||||
}
|
||||
|
||||
brcmf_remove_interface(ifp, true);
|
||||
|
||||
err_unarm:
|
||||
brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
||||
return err;
|
||||
}
|
||||
|
||||
static
|
||||
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
||||
{
|
||||
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
||||
struct net_device *ndev = wdev->netdev;
|
||||
|
||||
if (ndev && ndev == cfg_to_ndev(cfg))
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* vif event pending in firmware */
|
||||
if (brcmf_cfg80211_vif_event_armed(cfg))
|
||||
return -EBUSY;
|
||||
|
@ -811,12 +847,13 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
return -EOPNOTSUPP;
|
||||
case NL80211_IFTYPE_AP:
|
||||
return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_P2P_DEVICE:
|
||||
|
@ -6288,29 +6325,15 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
if (!combo)
|
||||
goto err;
|
||||
|
||||
c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
|
||||
if (!c0_limits)
|
||||
goto err;
|
||||
|
||||
if (p2p) {
|
||||
p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
|
||||
if (!p2p_limits)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mbss) {
|
||||
mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
|
||||
if (!mbss_limits)
|
||||
goto err;
|
||||
}
|
||||
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
BIT(NL80211_IFTYPE_ADHOC) |
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
c = 0;
|
||||
i = 0;
|
||||
combo[c].num_different_channels = 1;
|
||||
c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
|
||||
if (!c0_limits)
|
||||
goto err;
|
||||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
if (p2p) {
|
||||
|
@ -6328,6 +6351,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
c0_limits[i].max = 1;
|
||||
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
||||
}
|
||||
combo[c].num_different_channels = 1;
|
||||
combo[c].max_interfaces = i;
|
||||
combo[c].n_limits = i;
|
||||
combo[c].limits = c0_limits;
|
||||
|
@ -6335,7 +6359,9 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
if (p2p) {
|
||||
c++;
|
||||
i = 0;
|
||||
combo[c].num_different_channels = 1;
|
||||
p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);
|
||||
if (!p2p_limits)
|
||||
goto err;
|
||||
p2p_limits[i].max = 1;
|
||||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
|
||||
p2p_limits[i].max = 1;
|
||||
|
@ -6344,6 +6370,7 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT);
|
||||
p2p_limits[i].max = 1;
|
||||
p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
|
||||
combo[c].num_different_channels = 1;
|
||||
combo[c].max_interfaces = i;
|
||||
combo[c].n_limits = i;
|
||||
combo[c].limits = p2p_limits;
|
||||
|
@ -6351,14 +6378,19 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
|
|||
|
||||
if (mbss) {
|
||||
c++;
|
||||
i = 0;
|
||||
mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
|
||||
if (!mbss_limits)
|
||||
goto err;
|
||||
mbss_limits[i].max = 4;
|
||||
mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
|
||||
combo[c].beacon_int_infra_match = true;
|
||||
combo[c].num_different_channels = 1;
|
||||
mbss_limits[0].max = 4;
|
||||
mbss_limits[0].types = BIT(NL80211_IFTYPE_AP);
|
||||
combo[c].max_interfaces = 4;
|
||||
combo[c].n_limits = 1;
|
||||
combo[c].n_limits = i;
|
||||
combo[c].limits = mbss_limits;
|
||||
}
|
||||
|
||||
wiphy->n_iface_combinations = n_combos;
|
||||
wiphy->iface_combinations = combo;
|
||||
return 0;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
/* for brcmu_d11inf */
|
||||
#include <brcmu_d11.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "fwil_types.h"
|
||||
#include "p2p.h"
|
||||
|
||||
|
|
|
@ -548,12 +548,16 @@ fail:
|
|||
return -EBADE;
|
||||
}
|
||||
|
||||
static void brcmf_net_detach(struct net_device *ndev)
|
||||
static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
|
||||
{
|
||||
if (ndev->reg_state == NETREG_REGISTERED)
|
||||
unregister_netdev(ndev);
|
||||
else
|
||||
if (ndev->reg_state == NETREG_REGISTERED) {
|
||||
if (rtnl_locked)
|
||||
unregister_netdevice(ndev);
|
||||
else
|
||||
unregister_netdev(ndev);
|
||||
} else {
|
||||
brcmf_cfg80211_free_netdev(ndev);
|
||||
}
|
||||
}
|
||||
|
||||
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
|
||||
|
@ -634,7 +638,7 @@ fail:
|
|||
}
|
||||
|
||||
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
||||
bool is_p2pdev, char *name, u8 *mac_addr)
|
||||
bool is_p2pdev, const char *name, u8 *mac_addr)
|
||||
{
|
||||
struct brcmf_if *ifp;
|
||||
struct net_device *ndev;
|
||||
|
@ -651,7 +655,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
|||
brcmf_err("ERROR: netdev:%s already exists\n",
|
||||
ifp->ndev->name);
|
||||
netif_stop_queue(ifp->ndev);
|
||||
brcmf_net_detach(ifp->ndev);
|
||||
brcmf_net_detach(ifp->ndev, false);
|
||||
drvr->iflist[bsscfgidx] = NULL;
|
||||
} else {
|
||||
brcmf_dbg(INFO, "netdev:%s ignore IF event\n",
|
||||
|
@ -699,7 +703,8 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
|||
return ifp;
|
||||
}
|
||||
|
||||
static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
|
||||
static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx,
|
||||
bool rtnl_locked)
|
||||
{
|
||||
struct brcmf_if *ifp;
|
||||
|
||||
|
@ -729,7 +734,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
|
|||
cancel_work_sync(&ifp->multicast_work);
|
||||
cancel_work_sync(&ifp->ndoffload_work);
|
||||
}
|
||||
brcmf_net_detach(ifp->ndev);
|
||||
brcmf_net_detach(ifp->ndev, rtnl_locked);
|
||||
} else {
|
||||
/* Only p2p device interfaces which get dynamically created
|
||||
* end up here. In this case the p2p module should be informed
|
||||
|
@ -743,14 +748,14 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
|
|||
}
|
||||
}
|
||||
|
||||
void brcmf_remove_interface(struct brcmf_if *ifp)
|
||||
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
|
||||
{
|
||||
if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
|
||||
return;
|
||||
brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
|
||||
ifp->ifidx);
|
||||
brcmf_fws_del_interface(ifp);
|
||||
brcmf_del_if(ifp->drvr, ifp->bsscfgidx);
|
||||
brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INET
|
||||
|
@ -1057,9 +1062,9 @@ fail:
|
|||
brcmf_fws_deinit(drvr);
|
||||
}
|
||||
if (ifp)
|
||||
brcmf_net_detach(ifp->ndev);
|
||||
brcmf_net_detach(ifp->ndev, false);
|
||||
if (p2p_ifp)
|
||||
brcmf_net_detach(p2p_ifp->ndev);
|
||||
brcmf_net_detach(p2p_ifp->ndev, false);
|
||||
drvr->iflist[0] = NULL;
|
||||
drvr->iflist[1] = NULL;
|
||||
if (drvr->settings->ignore_probe_fail)
|
||||
|
@ -1128,7 +1133,7 @@ void brcmf_detach(struct device *dev)
|
|||
|
||||
/* make sure primary interface removed last */
|
||||
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
|
||||
brcmf_remove_interface(drvr->iflist[i]);
|
||||
brcmf_remove_interface(drvr->iflist[i], false);
|
||||
|
||||
brcmf_cfg80211_detach(drvr->config);
|
||||
|
||||
|
|
|
@ -215,8 +215,8 @@ char *brcmf_ifname(struct brcmf_if *ifp);
|
|||
struct brcmf_if *brcmf_get_ifp(struct brcmf_pub *drvr, int ifidx);
|
||||
int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);
|
||||
struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bsscfgidx, s32 ifidx,
|
||||
bool is_p2pdev, char *name, u8 *mac_addr);
|
||||
void brcmf_remove_interface(struct brcmf_if *ifp);
|
||||
bool is_p2pdev, const char *name, u8 *mac_addr);
|
||||
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked);
|
||||
void brcmf_txflowblock_if(struct brcmf_if *ifp,
|
||||
enum brcmf_netif_stop_reason reason, bool state);
|
||||
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "brcmu_wifi.h"
|
||||
#include "brcmu_utils.h"
|
||||
|
||||
#include "cfg80211.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "tracepoint.h"
|
||||
|
@ -182,8 +183,13 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
|
|||
|
||||
err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
|
||||
|
||||
if (ifp && ifevent->action == BRCMF_E_IF_DEL)
|
||||
brcmf_remove_interface(ifp);
|
||||
if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
|
||||
bool armed = brcmf_cfg80211_vif_event_armed(drvr->config);
|
||||
|
||||
/* Default handling in case no-one waits for this event */
|
||||
if (!armed)
|
||||
brcmf_remove_interface(ifp, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2261,6 +2261,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
return 0;
|
||||
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
|
||||
brcmf_p2p_deinit_discovery(p2p);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
@ -2286,8 +2288,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|||
else
|
||||
err = 0;
|
||||
}
|
||||
if (err)
|
||||
brcmf_remove_interface(vif->ifp);
|
||||
brcmf_remove_interface(vif->ifp, true);
|
||||
|
||||
brcmf_cfg80211_arm_vif_event(cfg, NULL);
|
||||
if (vif->wdev.iftype != NL80211_IFTYPE_P2P_DEVICE)
|
||||
|
@ -2393,7 +2394,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
|
|||
if (vif != NULL) {
|
||||
brcmf_p2p_cancel_remain_on_channel(vif->ifp);
|
||||
brcmf_p2p_deinit_discovery(p2p);
|
||||
brcmf_remove_interface(vif->ifp);
|
||||
brcmf_remove_interface(vif->ifp, false);
|
||||
}
|
||||
/* just set it all to zero */
|
||||
memset(p2p, 0, sizeof(*p2p));
|
||||
|
|
|
@ -3349,8 +3349,8 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
|
|||
dma_rxfill(wlc_hw->di[RX_FIFO]);
|
||||
}
|
||||
|
||||
void
|
||||
static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
|
||||
static void brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec)
|
||||
{
|
||||
u32 macintmask;
|
||||
bool fastclk;
|
||||
struct brcms_c_info *wlc = wlc_hw->wlc;
|
||||
|
|
|
@ -1102,8 +1102,8 @@ static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
|
|||
struct airo_info;
|
||||
|
||||
static int get_dec_u16( char *buffer, int *start, int limit );
|
||||
static void OUT4500( struct airo_info *, u16 register, u16 value );
|
||||
static unsigned short IN4500( struct airo_info *, u16 register );
|
||||
static void OUT4500( struct airo_info *, u16 reg, u16 value );
|
||||
static unsigned short IN4500( struct airo_info *, u16 reg );
|
||||
static u16 setup_card(struct airo_info*, u8 *mac, int lock);
|
||||
static int enable_MAC(struct airo_info *ai, int lock);
|
||||
static void disable_MAC(struct airo_info *ai, int lock);
|
||||
|
|
|
@ -4093,7 +4093,7 @@ static const char *ipw_get_status_code(u16 status)
|
|||
return "Unknown status value.";
|
||||
}
|
||||
|
||||
static void inline average_init(struct average *avg)
|
||||
static inline void average_init(struct average *avg)
|
||||
{
|
||||
memset(avg, 0, sizeof(*avg));
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ iwlwifi-objs += iwl-eeprom-read.o iwl-eeprom-parse.o
|
|||
iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
|
||||
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
|
||||
iwlwifi-$(CONFIG_IWLDVM) += iwl-1000.o iwl-2000.o iwl-5000.o iwl-6000.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o
|
||||
iwlwifi-$(CONFIG_IWLMVM) += iwl-7000.o iwl-8000.o iwl-9000.o iwl-a000.o
|
||||
iwlwifi-objs += iwl-trans.o
|
||||
|
||||
iwlwifi-objs += $(iwlwifi-m)
|
||||
|
|
|
@ -205,23 +205,6 @@ static const __le32 iwlagn_def_3w_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
|
|||
cpu_to_le32(0xf0005000),
|
||||
};
|
||||
|
||||
|
||||
/* Loose Coex */
|
||||
static const __le32 iwlagn_loose_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xaeaaaaaa),
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
cpu_to_le32(0xcc00ff28),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0xcc00aaaa),
|
||||
cpu_to_le32(0x0000aaaa),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0x00000000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
cpu_to_le32(0xf0005000),
|
||||
};
|
||||
|
||||
/* Full concurrency */
|
||||
static const __le32 iwlagn_concurrent_lookup[IWLAGN_BT_DECISION_LUT_SIZE] = {
|
||||
cpu_to_le32(0xaaaaaaaa),
|
||||
|
|
|
@ -1317,6 +1317,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
|||
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||
|
||||
switch (iwlwifi_mod_params.amsdu_size) {
|
||||
case IWL_AMSDU_DEF:
|
||||
case IWL_AMSDU_4K:
|
||||
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
|
||||
break;
|
||||
|
@ -1336,6 +1337,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
|||
trans_cfg.command_groups_size = ARRAY_SIZE(iwl_dvm_groups);
|
||||
|
||||
trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM;
|
||||
trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info,
|
||||
driver_data[2]);
|
||||
|
||||
WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE <
|
||||
priv->cfg->base_params->num_of_queues);
|
||||
|
|
|
@ -523,11 +523,6 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION &&
|
||||
priv->cfg->ht_params && priv->cfg->ht_params->smps_mode)
|
||||
ieee80211_request_smps(ctx->vif,
|
||||
priv->cfg->ht_params->smps_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -178,6 +178,7 @@ const struct iwl_cfg iwl5165_2ac_cfg = {
|
|||
.nvm_ver = IWL9000_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL9000_TX_POWER_VERSION,
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
|
||||
.integrated = true,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL9000_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2015-2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2015-2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/stringify.h>
|
||||
#include "iwl-config.h"
|
||||
#include "iwl-agn-hw.h"
|
||||
|
||||
/* Highest firmware API version supported */
|
||||
#define IWL_A000_UCODE_API_MAX 24
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_A000_UCODE_API_MIN 24
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL_A000_NVM_VERSION 0x0a1d
|
||||
#define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */
|
||||
|
||||
/* Memory offsets and lengths */
|
||||
#define IWL_A000_DCCM_OFFSET 0x800000
|
||||
#define IWL_A000_DCCM_LEN 0x18000
|
||||
#define IWL_A000_DCCM2_OFFSET 0x880000
|
||||
#define IWL_A000_DCCM2_LEN 0x8000
|
||||
#define IWL_A000_SMEM_OFFSET 0x400000
|
||||
#define IWL_A000_SMEM_LEN 0x68000
|
||||
|
||||
#define IWL_A000_FW_PRE "iwlwifi-Qu-a0-jf-b0-"
|
||||
#define IWL_A000_MODULE_FIRMWARE(api) \
|
||||
IWL_A000_FW_PRE "-" __stringify(api) ".ucode"
|
||||
|
||||
#define NVM_HW_SECTION_NUM_FAMILY_A000 10
|
||||
|
||||
static const struct iwl_base_params iwl_a000_base_params = {
|
||||
.eeprom_size = OTP_LOW_IMAGE_SIZE_FAMILY_A000,
|
||||
.num_of_queues = 31,
|
||||
.shadow_ram_support = true,
|
||||
.led_compensation = 57,
|
||||
.wd_timeout = IWL_LONG_WD_TIMEOUT,
|
||||
.max_event_log_size = 512,
|
||||
.shadow_reg_enable = true,
|
||||
.pcie_l1_allowed = true,
|
||||
};
|
||||
|
||||
static const struct iwl_ht_params iwl_a000_ht_params = {
|
||||
.stbc = true,
|
||||
.ldpc = true,
|
||||
.ht40_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ),
|
||||
};
|
||||
|
||||
#define IWL_DEVICE_A000 \
|
||||
.ucode_api_max = IWL_A000_UCODE_API_MAX, \
|
||||
.ucode_api_min = IWL_A000_UCODE_API_MIN, \
|
||||
.device_family = IWL_DEVICE_FAMILY_8000, \
|
||||
.max_inst_size = IWL60_RTC_INST_SIZE, \
|
||||
.max_data_size = IWL60_RTC_DATA_SIZE, \
|
||||
.base_params = &iwl_a000_base_params, \
|
||||
.led_mode = IWL_LED_RF_STATE, \
|
||||
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_A000, \
|
||||
.non_shared_ant = ANT_A, \
|
||||
.dccm_offset = IWL_A000_DCCM_OFFSET, \
|
||||
.dccm_len = IWL_A000_DCCM_LEN, \
|
||||
.dccm2_offset = IWL_A000_DCCM2_OFFSET, \
|
||||
.dccm2_len = IWL_A000_DCCM2_LEN, \
|
||||
.smem_offset = IWL_A000_SMEM_OFFSET, \
|
||||
.smem_len = IWL_A000_SMEM_LEN, \
|
||||
.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \
|
||||
.apmg_not_supported = true, \
|
||||
.mq_rx_supported = true, \
|
||||
.vht_mu_mimo_supported = true, \
|
||||
.mac_addr_from_csr = true, \
|
||||
.use_tfh = true
|
||||
|
||||
const struct iwl_cfg iwla000_2ac_cfg = {
|
||||
.name = "Intel(R) Dual Band Wireless AC a000",
|
||||
.fw_name_pre = IWL_A000_FW_PRE,
|
||||
IWL_DEVICE_A000,
|
||||
.ht_params = &iwl_a000_ht_params,
|
||||
.nvm_ver = IWL_A000_NVM_VERSION,
|
||||
.nvm_calib_ver = IWL_A000_TX_POWER_VERSION,
|
||||
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
|
||||
};
|
||||
|
||||
MODULE_FIRMWARE(IWL_A000_MODULE_FIRMWARE(IWL_A000_UCODE_API_MAX));
|
|
@ -66,8 +66,9 @@
|
|||
#define __IWL_CONFIG_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
enum iwl_device_family {
|
||||
IWL_DEVICE_FAMILY_UNDEFINED,
|
||||
|
@ -192,7 +193,6 @@ struct iwl_base_params {
|
|||
* @ht40_bands: bitmap of bands (using %NL80211_BAND_*) that support HT40
|
||||
*/
|
||||
struct iwl_ht_params {
|
||||
enum ieee80211_smps_mode smps_mode;
|
||||
u8 ht_greenfield_support:1,
|
||||
stbc:1,
|
||||
ldpc:1,
|
||||
|
@ -261,6 +261,7 @@ struct iwl_tt_params {
|
|||
#define OTP_LOW_IMAGE_SIZE_FAMILY_7000 (16 * 512 * sizeof(u16)) /* 16 KB */
|
||||
#define OTP_LOW_IMAGE_SIZE_FAMILY_8000 (32 * 512 * sizeof(u16)) /* 32 KB */
|
||||
#define OTP_LOW_IMAGE_SIZE_FAMILY_9000 OTP_LOW_IMAGE_SIZE_FAMILY_8000
|
||||
#define OTP_LOW_IMAGE_SIZE_FAMILY_A000 OTP_LOW_IMAGE_SIZE_FAMILY_9000
|
||||
|
||||
struct iwl_eeprom_params {
|
||||
const u8 regulatory_bands[7];
|
||||
|
@ -319,6 +320,7 @@ struct iwl_pwr_tx_backoff {
|
|||
* @mq_rx_supported: multi-queue rx support
|
||||
* @vht_mu_mimo_supported: VHT MU-MIMO support
|
||||
* @rf_id: need to read rf_id to determine the firmware image
|
||||
* @integrated: discrete or integrated
|
||||
*
|
||||
* We enable the driver to be backward compatible wrt. hardware features.
|
||||
* API differences in uCode shouldn't be handled here but through TLVs
|
||||
|
@ -362,7 +364,9 @@ struct iwl_cfg {
|
|||
apmg_not_supported:1,
|
||||
mq_rx_supported:1,
|
||||
vht_mu_mimo_supported:1,
|
||||
rf_id:1;
|
||||
rf_id:1,
|
||||
integrated:1,
|
||||
use_tfh:1;
|
||||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
u8 non_shared_ant;
|
||||
|
@ -448,6 +452,7 @@ extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
|
|||
extern const struct iwl_cfg iwl9260_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl9260lc_2ac_cfg;
|
||||
extern const struct iwl_cfg iwl5165_2ac_cfg;
|
||||
extern const struct iwl_cfg iwla000_2ac_cfg;
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
#endif /* __IWL_CONFIG_H__ */
|
||||
|
|
|
@ -145,8 +145,10 @@
|
|||
|
||||
#define CSR_LED_REG (CSR_BASE+0x094)
|
||||
#define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0)
|
||||
#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */
|
||||
|
||||
#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE + 0x0A8) /* 6000 and up */
|
||||
#define CSR_MAC_SHADOW_REG_CTRL_RX_WAKE BIT(20)
|
||||
#define CSR_MAC_SHADOW_REG_CTL2 (CSR_BASE + 0x0AC)
|
||||
#define CSR_MAC_SHADOW_REG_CTL2_RX_WAKE 0xFFFF
|
||||
|
||||
/* GIO Chicken Bits (PCI Express bus link power management) */
|
||||
#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
|
||||
|
|
|
@ -41,6 +41,7 @@ static inline bool iwl_have_debug_level(u32 level)
|
|||
#endif
|
||||
}
|
||||
|
||||
struct device;
|
||||
void __iwl_err(struct device *dev, bool rfkill_prefix, bool only_trace,
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
void __iwl_warn(struct device *dev, const char *fmt, ...) __printf(2, 3);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -83,6 +84,23 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
|
|||
__get_str(dev), __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_iowrite64,
|
||||
TP_PROTO(const struct device *dev, u64 offs, u64 val),
|
||||
TP_ARGS(dev, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
DEV_ENTRY
|
||||
__field(u64, offs)
|
||||
__field(u64, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
DEV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%s] write io[%llu] = %llu)",
|
||||
__get_str(dev), __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_iowrite_prph32,
|
||||
TP_PROTO(const struct device *dev, u32 offs, u32 val),
|
||||
TP_ARGS(dev, offs, val),
|
||||
|
@ -100,6 +118,23 @@ TRACE_EVENT(iwlwifi_dev_iowrite_prph32,
|
|||
__get_str(dev), __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_iowrite_prph64,
|
||||
TP_PROTO(const struct device *dev, u64 offs, u64 val),
|
||||
TP_ARGS(dev, offs, val),
|
||||
TP_STRUCT__entry(
|
||||
DEV_ENTRY
|
||||
__field(u64, offs)
|
||||
__field(u64, val)
|
||||
),
|
||||
TP_fast_assign(
|
||||
DEV_ASSIGN;
|
||||
__entry->offs = offs;
|
||||
__entry->val = val;
|
||||
),
|
||||
TP_printk("[%s] write PRPH[%llu] = %llu)",
|
||||
__get_str(dev), __entry->offs, __entry->val)
|
||||
);
|
||||
|
||||
TRACE_EVENT(iwlwifi_dev_ioread_prph32,
|
||||
TP_PROTO(const struct device *dev, u32 offs, u32 val),
|
||||
TP_ARGS(dev, offs, val),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(C) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -33,11 +34,29 @@
|
|||
static inline bool iwl_trace_data(struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
__le16 fc = hdr->frame_control;
|
||||
int offs = 24; /* start with normal header length */
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
if (!ieee80211_is_data(fc))
|
||||
return false;
|
||||
return !(info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO);
|
||||
|
||||
/* Try to determine if the frame is EAPOL. This might have false
|
||||
* positives (if there's no RFC 1042 header and we compare to some
|
||||
* payload instead) but since we're only doing tracing that's not
|
||||
* a problem.
|
||||
*/
|
||||
|
||||
if (ieee80211_has_a4(fc))
|
||||
offs += 6;
|
||||
if (ieee80211_is_data_qos(fc))
|
||||
offs += 2;
|
||||
/* don't account for crypto - these are unencrypted */
|
||||
|
||||
/* also account for the RFC 1042 header, of course */
|
||||
offs += 6;
|
||||
|
||||
return skb->len > offs + 2 &&
|
||||
*(__be16 *)(skb->data + offs) == cpu_to_be16(ETH_P_PAE);
|
||||
}
|
||||
|
||||
static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
|
||||
|
|
|
@ -129,8 +129,8 @@ struct iwl_drv {
|
|||
};
|
||||
|
||||
enum {
|
||||
DVM_OP_MODE = 0,
|
||||
MVM_OP_MODE = 1,
|
||||
DVM_OP_MODE,
|
||||
MVM_OP_MODE,
|
||||
};
|
||||
|
||||
/* Protects the table contents, i.e. the ops pointer & drv list */
|
||||
|
@ -326,8 +326,6 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
|
|||
int i, j;
|
||||
struct iwl_fw_cscheme_list *l = (struct iwl_fw_cscheme_list *)data;
|
||||
struct iwl_fw_cipher_scheme *fwcs;
|
||||
struct ieee80211_cipher_scheme *cs;
|
||||
u32 cipher;
|
||||
|
||||
if (len < sizeof(*l) ||
|
||||
len < sizeof(l->size) + l->size * sizeof(l->cs[0]))
|
||||
|
@ -335,22 +333,12 @@ static int iwl_store_cscheme(struct iwl_fw *fw, const u8 *data, const u32 len)
|
|||
|
||||
for (i = 0, j = 0; i < IWL_UCODE_MAX_CS && i < l->size; i++) {
|
||||
fwcs = &l->cs[j];
|
||||
cipher = le32_to_cpu(fwcs->cipher);
|
||||
|
||||
/* we skip schemes with zero cipher suite selector */
|
||||
if (!cipher)
|
||||
if (!fwcs->cipher)
|
||||
continue;
|
||||
|
||||
cs = &fw->cs[j++];
|
||||
cs->cipher = cipher;
|
||||
cs->iftype = BIT(NL80211_IFTYPE_STATION);
|
||||
cs->hdr_len = fwcs->hdr_len;
|
||||
cs->pn_len = fwcs->pn_len;
|
||||
cs->pn_off = fwcs->pn_off;
|
||||
cs->key_idx_off = fwcs->key_idx_off;
|
||||
cs->key_idx_mask = fwcs->key_idx_mask;
|
||||
cs->key_idx_shift = fwcs->key_idx_shift;
|
||||
cs->mic_len = fwcs->mic_len;
|
||||
fw->cs[j++] = *fwcs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -795,17 +783,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
case IWL_UCODE_TLV_SEC_RT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SEC_INIT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SEC_WOWLAN:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_DEF_CALIB:
|
||||
if (tlv_len != sizeof(struct iwl_tlv_calib_data))
|
||||
|
@ -827,17 +815,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
|||
case IWL_UCODE_TLV_SECURE_SEC_RT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_REGULAR,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_INIT:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_INIT,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_SECURE_SEC_WOWLAN:
|
||||
iwl_store_ucode_sec(pieces, tlv_data, IWL_UCODE_WOWLAN,
|
||||
tlv_len);
|
||||
drv->fw.mvm_fw = true;
|
||||
drv->fw.type = IWL_FW_MVM;
|
||||
break;
|
||||
case IWL_UCODE_TLV_NUM_OF_CPU:
|
||||
if (tlv_len != sizeof(u32))
|
||||
|
@ -1275,7 +1263,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|||
* In mvm uCode there is no difference between data and instructions
|
||||
* sections.
|
||||
*/
|
||||
if (!fw->mvm_fw && validate_sec_sizes(drv, pieces, drv->cfg))
|
||||
if (fw->type == IWL_FW_DVM && validate_sec_sizes(drv, pieces, drv->cfg))
|
||||
goto try_again;
|
||||
|
||||
/* Allocate ucode buffers for card's bus-master loading ... */
|
||||
|
@ -1403,10 +1391,16 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
|
|||
release_firmware(ucode_raw);
|
||||
|
||||
mutex_lock(&iwlwifi_opmode_table_mtx);
|
||||
if (fw->mvm_fw)
|
||||
op = &iwlwifi_opmode_table[MVM_OP_MODE];
|
||||
else
|
||||
switch (fw->type) {
|
||||
case IWL_FW_DVM:
|
||||
op = &iwlwifi_opmode_table[DVM_OP_MODE];
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Invalid fw type %d\n", fw->type);
|
||||
case IWL_FW_MVM:
|
||||
op = &iwlwifi_opmode_table[MVM_OP_MODE];
|
||||
break;
|
||||
}
|
||||
|
||||
IWL_INFO(drv, "loaded firmware version %s op_mode %s\n",
|
||||
drv->fw.fw_version, op->name);
|
||||
|
@ -1658,7 +1652,8 @@ MODULE_PARM_DESC(11n_disable,
|
|||
"disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX");
|
||||
module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size,
|
||||
int, S_IRUGO);
|
||||
MODULE_PARM_DESC(amsdu_size, "amsdu size 0:4K 1:8K 2:12K (default 0)");
|
||||
MODULE_PARM_DESC(amsdu_size,
|
||||
"amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)");
|
||||
module_param_named(fw_restart, iwlwifi_mod_params.restart_fw, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)");
|
||||
|
||||
|
|
|
@ -766,7 +766,9 @@ void iwl_init_ht_hw_capab(const struct iwl_cfg *cfg,
|
|||
if (cfg->ht_params->ldpc)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
|
||||
if (iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K)
|
||||
if ((cfg->mq_rx_supported &&
|
||||
iwlwifi_mod_params.amsdu_size != IWL_AMSDU_4K) ||
|
||||
iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K)
|
||||
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
|
||||
|
||||
ht_info->ampdu_factor = cfg->max_ht_ampdu_exponent;
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "iwl-trans.h"
|
||||
|
||||
struct iwl_nvm_data {
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
*/
|
||||
#define FH_MEM_LOWER_BOUND (0x1000)
|
||||
#define FH_MEM_UPPER_BOUND (0x2000)
|
||||
#define TFH_MEM_LOWER_BOUND (0xA06000)
|
||||
|
||||
/**
|
||||
* Keep-Warm (KW) buffer base address.
|
||||
|
@ -118,10 +119,17 @@
|
|||
#define FH_MEM_CBBC_16_19_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
|
||||
#define FH_MEM_CBBC_20_31_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xB20)
|
||||
#define FH_MEM_CBBC_20_31_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xB80)
|
||||
/* a000 TFD table address, 64 bit */
|
||||
#define TFH_TFDQ_CBB_TABLE (TFH_MEM_LOWER_BOUND + 0x1C00)
|
||||
|
||||
/* Find TFD CB base pointer for given queue */
|
||||
static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
|
||||
static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans,
|
||||
unsigned int chnl)
|
||||
{
|
||||
if (trans->cfg->use_tfh) {
|
||||
WARN_ON_ONCE(chnl >= 64);
|
||||
return TFH_TFDQ_CBB_TABLE + 8 * chnl;
|
||||
}
|
||||
if (chnl < 16)
|
||||
return FH_MEM_CBBC_0_15_LOWER_BOUND + 4 * chnl;
|
||||
if (chnl < 20)
|
||||
|
@ -130,6 +138,65 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
|
|||
return FH_MEM_CBBC_20_31_LOWER_BOUND + 4 * (chnl - 20);
|
||||
}
|
||||
|
||||
/* a000 configuration registers */
|
||||
|
||||
/*
|
||||
* TFH Configuration register.
|
||||
*
|
||||
* BIT fields:
|
||||
*
|
||||
* Bits 3:0:
|
||||
* Define the maximum number of pending read requests.
|
||||
* Maximum configration value allowed is 0xC
|
||||
* Bits 9:8:
|
||||
* Define the maximum transfer size. (64 / 128 / 256)
|
||||
* Bit 10:
|
||||
* When bit is set and transfer size is set to 128B, the TFH will enable
|
||||
* reading chunks of more than 64B only if the read address is aligned to 128B.
|
||||
* In case of DRAM read address which is not aligned to 128B, the TFH will
|
||||
* enable transfer size which doesn't cross 64B DRAM address boundary.
|
||||
*/
|
||||
#define TFH_TRANSFER_MODE (TFH_MEM_LOWER_BOUND + 0x1F40)
|
||||
#define TFH_TRANSFER_MAX_PENDING_REQ 0xc
|
||||
#define TFH_CHUNK_SIZE_128 BIT(8)
|
||||
#define TFH_CHUNK_SPLIT_MODE BIT(10)
|
||||
/*
|
||||
* Defines the offset address in dwords referring from the beginning of the
|
||||
* Tx CMD which will be updated in DRAM.
|
||||
* Note that the TFH offset address for Tx CMD update is always referring to
|
||||
* the start of the TFD first TB.
|
||||
* In case of a DRAM Tx CMD update the TFH will update PN and Key ID
|
||||
*/
|
||||
#define TFH_TXCMD_UPDATE_CFG (TFH_MEM_LOWER_BOUND + 0x1F48)
|
||||
/*
|
||||
* Controls TX DMA operation
|
||||
*
|
||||
* BIT fields:
|
||||
*
|
||||
* Bits 31:30: Enable the SRAM DMA channel.
|
||||
* Turning on bit 31 will kick the SRAM2DRAM DMA.
|
||||
* Note that the sram2dram may be enabled only after configuring the DRAM and
|
||||
* SRAM addresses registers and the byte count register.
|
||||
* Bits 25:24: Defines the interrupt target upon dram2sram transfer done. When
|
||||
* set to 1 - interrupt is sent to the driver
|
||||
* Bit 0: Indicates the snoop configuration
|
||||
*/
|
||||
#define TFH_SRV_DMA_CHNL0_CTRL (TFH_MEM_LOWER_BOUND + 0x1F60)
|
||||
#define TFH_SRV_DMA_SNOOP BIT(0)
|
||||
#define TFH_SRV_DMA_TO_DRIVER BIT(24)
|
||||
#define TFH_SRV_DMA_START BIT(31)
|
||||
|
||||
/* Defines the DMA SRAM write start address to transfer a data block */
|
||||
#define TFH_SRV_DMA_CHNL0_SRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F64)
|
||||
|
||||
/* Defines the 64bits DRAM start address to read the DMA data block from */
|
||||
#define TFH_SRV_DMA_CHNL0_DRAM_ADDR (TFH_MEM_LOWER_BOUND + 0x1F68)
|
||||
|
||||
/*
|
||||
* Defines the number of bytes to transfer from DRAM to SRAM.
|
||||
* Note that this register may be configured with non-dword aligned size.
|
||||
*/
|
||||
#define TFH_SRV_DMA_CHNL0_BC (TFH_MEM_LOWER_BOUND + 0x1F70)
|
||||
|
||||
/**
|
||||
* Rx SRAM Control and Status Registers (RSCSR)
|
||||
|
@ -344,6 +411,32 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
|
|||
#define RFH_RBDBUF_RBD0_LSB 0xA08300
|
||||
#define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8)
|
||||
|
||||
/**
|
||||
* RFH Status Register
|
||||
*
|
||||
* Bit fields:
|
||||
*
|
||||
* Bit 29: RBD_FETCH_IDLE
|
||||
* This status flag is set by the RFH when there is no active RBD fetch from
|
||||
* DRAM.
|
||||
* Once the RFH RBD controller starts fetching (or when there is a pending
|
||||
* RBD read response from DRAM), this flag is immediately turned off.
|
||||
*
|
||||
* Bit 30: SRAM_DMA_IDLE
|
||||
* This status flag is set by the RFH when there is no active transaction from
|
||||
* SRAM to DRAM.
|
||||
* Once the SRAM to DRAM DMA is active, this flag is immediately turned off.
|
||||
*
|
||||
* Bit 31: RXF_DMA_IDLE
|
||||
* This status flag is set by the RFH when there is no active transaction from
|
||||
* RXF to DRAM.
|
||||
* Once the RXF-to-DRAM DMA is active, this flag is immediately turned off.
|
||||
*/
|
||||
#define RFH_GEN_STATUS 0xA09808
|
||||
#define RBD_FETCH_IDLE BIT(29)
|
||||
#define SRAM_DMA_IDLE BIT(30)
|
||||
#define RXF_DMA_IDLE BIT(31)
|
||||
|
||||
/* DMA configuration */
|
||||
#define RFH_RXF_DMA_CFG 0xA09820
|
||||
/* RB size */
|
||||
|
@ -384,7 +477,9 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
|
|||
#define RFH_GEN_CFG 0xA09800
|
||||
#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0)
|
||||
#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1)
|
||||
#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) /* 0 - 64B, 1- 128B */
|
||||
#define RFH_GEN_CFG_RB_CHUNK_SIZE_POS 4
|
||||
#define RFH_GEN_CFG_RB_CHUNK_SIZE_128 1
|
||||
#define RFH_GEN_CFG_RB_CHUNK_SIZE_64 0
|
||||
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
|
||||
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8
|
||||
|
||||
|
|
|
@ -89,6 +89,9 @@
|
|||
* @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were
|
||||
* paged to the DRAM.
|
||||
* @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers.
|
||||
* @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and
|
||||
* for that reason is not in use in any other place in the Linux Wi-Fi
|
||||
* stack.
|
||||
*/
|
||||
enum iwl_fw_error_dump_type {
|
||||
/* 0 is deprecated */
|
||||
|
@ -106,6 +109,7 @@ enum iwl_fw_error_dump_type {
|
|||
IWL_FW_ERROR_DUMP_PAGING = 12,
|
||||
IWL_FW_ERROR_DUMP_RADIO_REG = 13,
|
||||
IWL_FW_ERROR_DUMP_INTERNAL_TXF = 14,
|
||||
IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */
|
||||
|
||||
IWL_FW_ERROR_DUMP_MAX,
|
||||
};
|
||||
|
|
|
@ -301,7 +301,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
|
|||
* @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
|
||||
* @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload
|
||||
* @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
|
||||
* @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD
|
||||
* @IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD: supports U-APSD on p2p interface when it
|
||||
* is standalone or with a BSS station interface in the same binding.
|
||||
* @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
|
||||
* @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
|
||||
* sources for the MCC. This TLV bit is a future replacement to
|
||||
|
@ -312,6 +313,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
|
|||
* @IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE: extended DTS measurement
|
||||
* @IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS: supports short PM timeouts
|
||||
* @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
|
||||
* @IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD: the firmware supports CSA
|
||||
* countdown offloading. Beacon notifications are not sent to the host.
|
||||
* The fw also offloads TBTT alignment.
|
||||
* @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
|
||||
* antenna the beacon should be transmitted
|
||||
* @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
|
||||
|
@ -326,6 +330,9 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
|
|||
* @IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG: support getting more shared
|
||||
* memory addresses from the firmware.
|
||||
* @IWL_UCODE_TLV_CAPA_LQM_SUPPORT: supports Link Quality Measurement
|
||||
* @IWL_UCODE_TLV_CAPA_TX_POWER_ACK: reduced TX power API has larger
|
||||
* command size (command version 4) that supports toggling ACK TX
|
||||
* power reduction.
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
|
||||
*/
|
||||
|
@ -347,7 +354,7 @@ enum iwl_ucode_tlv_capa {
|
|||
IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT = (__force iwl_ucode_tlv_capa_t)19,
|
||||
IWL_UCODE_TLV_CAPA_CSUM_SUPPORT = (__force iwl_ucode_tlv_capa_t)21,
|
||||
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS = (__force iwl_ucode_tlv_capa_t)22,
|
||||
IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD = (__force iwl_ucode_tlv_capa_t)26,
|
||||
IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD = (__force iwl_ucode_tlv_capa_t)26,
|
||||
IWL_UCODE_TLV_CAPA_BT_COEX_PLCR = (__force iwl_ucode_tlv_capa_t)28,
|
||||
IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC = (__force iwl_ucode_tlv_capa_t)29,
|
||||
IWL_UCODE_TLV_CAPA_BT_COEX_RRC = (__force iwl_ucode_tlv_capa_t)30,
|
||||
|
@ -356,6 +363,7 @@ enum iwl_ucode_tlv_capa {
|
|||
IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS = (__force iwl_ucode_tlv_capa_t)65,
|
||||
IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT = (__force iwl_ucode_tlv_capa_t)67,
|
||||
IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT = (__force iwl_ucode_tlv_capa_t)68,
|
||||
IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD = (__force iwl_ucode_tlv_capa_t)70,
|
||||
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
|
||||
IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72,
|
||||
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
|
||||
|
@ -365,6 +373,7 @@ enum iwl_ucode_tlv_capa {
|
|||
IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77,
|
||||
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG = (__force iwl_ucode_tlv_capa_t)80,
|
||||
IWL_UCODE_TLV_CAPA_LQM_SUPPORT = (__force iwl_ucode_tlv_capa_t)81,
|
||||
IWL_UCODE_TLV_CAPA_TX_POWER_ACK = (__force iwl_ucode_tlv_capa_t)84,
|
||||
|
||||
NUM_IWL_UCODE_TLV_CAPA
|
||||
#ifdef __CHECKER__
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
#ifndef __iwl_fw_h__
|
||||
#define __iwl_fw_h__
|
||||
#include <linux/types.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
#include "iwl-fw-file.h"
|
||||
#include "iwl-fw-error-dump.h"
|
||||
|
@ -230,6 +229,16 @@ struct iwl_gscan_capabilities {
|
|||
u32 max_number_of_black_listed_ssid;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_fw_type - iwlwifi firmware type
|
||||
* @IWL_FW_DVM: DVM firmware
|
||||
* @IWL_FW_MVM: MVM firmware
|
||||
*/
|
||||
enum iwl_fw_type {
|
||||
IWL_FW_DVM,
|
||||
IWL_FW_MVM,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_fw - variables associated with the firmware
|
||||
*
|
||||
|
@ -244,7 +253,7 @@ struct iwl_gscan_capabilities {
|
|||
* @inst_evtlog_ptr: event log offset for runtime ucode.
|
||||
* @inst_evtlog_size: event log size for runtime ucode.
|
||||
* @inst_errlog_ptr: error log offfset for runtime ucode.
|
||||
* @mvm_fw: indicates this is MVM firmware
|
||||
* @type: firmware type (&enum iwl_fw_type)
|
||||
* @cipher_scheme: optional external cipher scheme.
|
||||
* @human_readable: human readable version
|
||||
* @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
|
||||
|
@ -275,9 +284,9 @@ struct iwl_fw {
|
|||
u8 valid_tx_ant;
|
||||
u8 valid_rx_ant;
|
||||
|
||||
bool mvm_fw;
|
||||
enum iwl_fw_type type;
|
||||
|
||||
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
|
||||
struct iwl_fw_cipher_scheme cs[IWL_UCODE_MAX_CS];
|
||||
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
|
||||
|
||||
u32 sdio_adma_addr;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* Portions of this file are derived from the ipw3945 project.
|
||||
*
|
||||
|
@ -51,6 +51,14 @@ void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write32);
|
||||
|
||||
void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val)
|
||||
{
|
||||
trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val);
|
||||
iwl_trans_write32(trans, ofs, val & 0xffffffff);
|
||||
iwl_trans_write32(trans, ofs + 4, val >> 32);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write64);
|
||||
|
||||
u32 iwl_read32(struct iwl_trans *trans, u32 ofs)
|
||||
{
|
||||
u32 val = iwl_trans_read32(trans, ofs);
|
||||
|
@ -102,6 +110,17 @@ void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write_direct32);
|
||||
|
||||
void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (iwl_trans_grab_nic_access(trans, &flags)) {
|
||||
iwl_write64(trans, reg, value);
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
}
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write_direct64);
|
||||
|
||||
int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
|
||||
int timeout)
|
||||
{
|
||||
|
@ -133,6 +152,14 @@ void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab);
|
||||
|
||||
void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val)
|
||||
{
|
||||
trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val);
|
||||
iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff);
|
||||
iwl_write_prph_no_grab(trans, ofs + 4, val >> 32);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab);
|
||||
|
||||
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -228,9 +255,117 @@ void iwl_force_nmi(struct iwl_trans *trans)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_force_nmi);
|
||||
|
||||
static const char *get_fh_string(int cmd)
|
||||
static const char *get_rfh_string(int cmd)
|
||||
{
|
||||
#define IWL_CMD(x) case x: return #x
|
||||
#define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; }
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) {
|
||||
IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i);
|
||||
IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i);
|
||||
IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i);
|
||||
IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i);
|
||||
};
|
||||
|
||||
switch (cmd) {
|
||||
IWL_CMD(RFH_RXF_DMA_CFG);
|
||||
IWL_CMD(RFH_GEN_CFG);
|
||||
IWL_CMD(RFH_GEN_STATUS);
|
||||
IWL_CMD(FH_TSSR_TX_STATUS_REG);
|
||||
IWL_CMD(FH_TSSR_TX_ERROR_REG);
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
#undef IWL_CMD_MQ
|
||||
}
|
||||
|
||||
struct reg {
|
||||
u32 addr;
|
||||
bool is64;
|
||||
};
|
||||
|
||||
static int iwl_dump_rfh(struct iwl_trans *trans, char **buf)
|
||||
{
|
||||
int i, q;
|
||||
int num_q = trans->num_rx_queues;
|
||||
static const u32 rfh_tbl[] = {
|
||||
RFH_RXF_DMA_CFG,
|
||||
RFH_GEN_CFG,
|
||||
RFH_GEN_STATUS,
|
||||
FH_TSSR_TX_STATUS_REG,
|
||||
FH_TSSR_TX_ERROR_REG,
|
||||
};
|
||||
static const struct reg rfh_mq_tbl[] = {
|
||||
{ RFH_Q0_FRBDCB_BA_LSB, true },
|
||||
{ RFH_Q0_FRBDCB_WIDX, false },
|
||||
{ RFH_Q0_FRBDCB_RIDX, false },
|
||||
{ RFH_Q0_URBD_STTS_WPTR_LSB, true },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (buf) {
|
||||
int pos = 0;
|
||||
/*
|
||||
* Register (up to 34 for name + 8 blank/q for MQ): 40 chars
|
||||
* Colon + space: 2 characters
|
||||
* 0X%08x: 10 characters
|
||||
* New line: 1 character
|
||||
* Total of 53 characters
|
||||
*/
|
||||
size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 +
|
||||
ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40;
|
||||
|
||||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||||
if (!*buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"RFH register values:\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++)
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"%40s: 0X%08x\n",
|
||||
get_rfh_string(rfh_tbl[i]),
|
||||
iwl_read_prph(trans, rfh_tbl[i]));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++)
|
||||
for (q = 0; q < num_q; q++) {
|
||||
u32 addr = rfh_mq_tbl[i].addr;
|
||||
|
||||
addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4);
|
||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||
"%34s(q %2d): 0X%08x\n",
|
||||
get_rfh_string(addr), q,
|
||||
iwl_read_prph(trans, addr));
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
IWL_ERR(trans, "RFH register values:\n");
|
||||
for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++)
|
||||
IWL_ERR(trans, " %34s: 0X%08x\n",
|
||||
get_rfh_string(rfh_tbl[i]),
|
||||
iwl_read_prph(trans, rfh_tbl[i]));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++)
|
||||
for (q = 0; q < num_q; q++) {
|
||||
u32 addr = rfh_mq_tbl[i].addr;
|
||||
|
||||
addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4);
|
||||
IWL_ERR(trans, " %34s(q %d): 0X%08x\n",
|
||||
get_rfh_string(addr), q,
|
||||
iwl_read_prph(trans, addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *get_fh_string(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
|
||||
IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
|
||||
|
@ -262,6 +397,9 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf)
|
|||
FH_TSSR_TX_ERROR_REG
|
||||
};
|
||||
|
||||
if (trans->cfg->mq_rx_supported)
|
||||
return iwl_dump_rfh(trans, buf);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (buf) {
|
||||
int pos = 0;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val);
|
||||
void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val);
|
||||
void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val);
|
||||
u32 iwl_read32(struct iwl_trans *trans, u32 ofs);
|
||||
|
||||
static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask)
|
||||
|
@ -53,11 +54,13 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask,
|
|||
|
||||
u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg);
|
||||
void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value);
|
||||
void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value);
|
||||
|
||||
|
||||
u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs);
|
||||
u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs);
|
||||
void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val);
|
||||
void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val);
|
||||
void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val);
|
||||
int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
|
||||
u32 bits, u32 mask, int timeout);
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <net/mac80211.h>
|
||||
|
||||
extern struct iwl_mod_params iwlwifi_mod_params;
|
||||
|
||||
|
@ -87,9 +86,10 @@ enum iwl_disable_11n {
|
|||
};
|
||||
|
||||
enum iwl_amsdu_size {
|
||||
IWL_AMSDU_4K = 0,
|
||||
IWL_AMSDU_8K = 1,
|
||||
IWL_AMSDU_12K = 2,
|
||||
IWL_AMSDU_DEF = 0,
|
||||
IWL_AMSDU_4K = 1,
|
||||
IWL_AMSDU_8K = 2,
|
||||
IWL_AMSDU_12K = 3,
|
||||
};
|
||||
|
||||
enum iwl_uapsd_disable {
|
||||
|
@ -105,7 +105,7 @@ enum iwl_uapsd_disable {
|
|||
* @sw_crypto: using hardware encryption, default = 0
|
||||
* @disable_11n: disable 11n capabilities, default = 0,
|
||||
* use IWL_[DIS,EN]ABLE_HT_* constants
|
||||
* @amsdu_size: enable 8K amsdu size, default = 4K. enum iwl_amsdu_size.
|
||||
* @amsdu_size: See &enum iwl_amsdu_size.
|
||||
* @restart_fw: restart firmware, default = 1
|
||||
* @bt_coex_active: enable bt coex, default = true
|
||||
* @led_mode: system default, default = 0
|
||||
|
|
|
@ -397,6 +397,13 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
|
|||
vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
|
||||
|
||||
switch (iwlwifi_mod_params.amsdu_size) {
|
||||
case IWL_AMSDU_DEF:
|
||||
if (cfg->mq_rx_supported)
|
||||
vht_cap->cap |=
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
|
||||
else
|
||||
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
|
||||
break;
|
||||
case IWL_AMSDU_4K:
|
||||
vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895;
|
||||
break;
|
||||
|
|
|
@ -417,5 +417,6 @@ enum {
|
|||
};
|
||||
|
||||
#define UREG_CHICK (0xA05C00)
|
||||
#define UREG_CHICK_MSI_ENABLE BIT(24)
|
||||
#define UREG_CHICK_MSIX_ENABLE BIT(25)
|
||||
#endif /* __iwl_prph_h__ */
|
||||
|
|
|
@ -211,6 +211,9 @@ struct iwl_cmd_header_wide {
|
|||
#define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */
|
||||
#define FH_RSCSR_FRAME_INVALID 0x55550000
|
||||
#define FH_RSCSR_FRAME_ALIGN 0x40
|
||||
#define FH_RSCSR_RPA_EN BIT(25)
|
||||
#define FH_RSCSR_RXQ_POS 16
|
||||
#define FH_RSCSR_RXQ_MASK 0x3F0000
|
||||
|
||||
struct iwl_rx_packet {
|
||||
/*
|
||||
|
@ -220,7 +223,13 @@ struct iwl_rx_packet {
|
|||
* 31: flag flush RB request
|
||||
* 30: flag ignore TC (terminal counter) request
|
||||
* 29: flag fast IRQ request
|
||||
* 28-14: Reserved
|
||||
* 28-26: Reserved
|
||||
* 25: Offload enabled
|
||||
* 24: RPF enabled
|
||||
* 23: RSS enabled
|
||||
* 22: Checksum enabled
|
||||
* 21-16: RX queue
|
||||
* 15-14: Reserved
|
||||
* 13-00: RX frame size
|
||||
*/
|
||||
__le32 len_n_flags;
|
||||
|
@ -383,11 +392,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r)
|
|||
|
||||
#define MAX_NO_RECLAIM_CMDS 6
|
||||
|
||||
/*
|
||||
* The first entry in driver_data array in ieee80211_tx_info
|
||||
* that can be used by the transport.
|
||||
*/
|
||||
#define IWL_TRANS_FIRST_DRIVER_DATA 2
|
||||
#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
|
||||
|
||||
/*
|
||||
|
@ -491,6 +495,8 @@ struct iwl_hcmd_arr {
|
|||
* @command_groups_size: number of command groups, to avoid illegal access
|
||||
* @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
|
||||
* we get the ALIVE from the uCode
|
||||
* @cb_data_offs: offset inside skb->cb to store transport data at, must have
|
||||
* space for at least two pointers
|
||||
*/
|
||||
struct iwl_trans_config {
|
||||
struct iwl_op_mode *op_mode;
|
||||
|
@ -510,6 +516,8 @@ struct iwl_trans_config {
|
|||
int command_groups_size;
|
||||
|
||||
u32 sdio_adma_addr;
|
||||
|
||||
u8 cb_data_offs;
|
||||
};
|
||||
|
||||
struct iwl_trans_dump_data {
|
||||
|
@ -574,6 +582,7 @@ struct iwl_trans_txq_scd_cfg {
|
|||
* configured. May sleep.
|
||||
* @txq_disable: de-configure a Tx queue to send AMPDUs
|
||||
* Must be atomic
|
||||
* @txq_set_shared_mode: change Tx queue shared/unshared marking
|
||||
* @wait_tx_queue_empty: wait until tx queues are empty. May sleep.
|
||||
* @freeze_txq_timer: prevents the timer of the queue from firing until the
|
||||
* queue is set to awake. Must be atomic.
|
||||
|
@ -637,6 +646,9 @@ struct iwl_trans_ops {
|
|||
void (*txq_disable)(struct iwl_trans *trans, int queue,
|
||||
bool configure_scd);
|
||||
|
||||
void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id,
|
||||
bool shared);
|
||||
|
||||
int (*wait_tx_queue_empty)(struct iwl_trans *trans, u32 txq_bm);
|
||||
void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
|
||||
bool freeze);
|
||||
|
@ -749,6 +761,7 @@ enum iwl_plat_pm_mode {
|
|||
* @ops - pointer to iwl_trans_ops
|
||||
* @op_mode - pointer to the op_mode
|
||||
* @cfg - pointer to the configuration
|
||||
* @drv - pointer to iwl_drv
|
||||
* @status: a bit-mask of transport status flags
|
||||
* @dev - pointer to struct device * that represents the device
|
||||
* @max_skb_frags: maximum number of fragments an SKB can have when transmitted.
|
||||
|
@ -792,6 +805,7 @@ struct iwl_trans {
|
|||
const struct iwl_trans_ops *ops;
|
||||
struct iwl_op_mode *op_mode;
|
||||
const struct iwl_cfg *cfg;
|
||||
struct iwl_drv *drv;
|
||||
enum iwl_trans_state state;
|
||||
unsigned long status;
|
||||
|
||||
|
@ -1052,6 +1066,13 @@ iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
|
|||
trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans,
|
||||
int queue, bool shared_mode)
|
||||
{
|
||||
if (trans->ops->txq_set_shared_mode)
|
||||
trans->ops->txq_set_shared_mode(trans, queue, shared_mode);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
|
||||
int fifo, int sta_id, int tid,
|
||||
int frame_limit, u16 ssn,
|
||||
|
|
|
@ -142,7 +142,7 @@ static const __le64 iwl_ci_mask[][3] = {
|
|||
cpu_to_le64(0x0)
|
||||
},
|
||||
{
|
||||
cpu_to_le64(0xFFC0000000ULL),
|
||||
cpu_to_le64(0xFE00000000ULL),
|
||||
cpu_to_le64(0x0ULL),
|
||||
cpu_to_le64(0x0ULL)
|
||||
},
|
||||
|
@ -615,8 +615,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
|
|||
* don't reduce the Tx power if one of these is true:
|
||||
* we are in LOOSE
|
||||
* single share antenna product
|
||||
* BT is active
|
||||
* we are associated
|
||||
* BT is inactive
|
||||
* we are not associated
|
||||
*/
|
||||
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
|
||||
mvm->cfg->bt_shared_single_ant || !vif->bss_conf.assoc ||
|
||||
|
|
|
@ -1020,6 +1020,8 @@ static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
|
|||
int ret;
|
||||
|
||||
ret = kstrtouint(buf, 0, &max_amsdu_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -70,85 +70,6 @@
|
|||
|
||||
#define BITS(nb) (BIT(nb) - 1)
|
||||
|
||||
/**
|
||||
* enum iwl_bt_coex_flags - flags for BT_COEX command
|
||||
* @BT_COEX_MODE_POS:
|
||||
* @BT_COEX_MODE_MSK:
|
||||
* @BT_COEX_DISABLE_OLD:
|
||||
* @BT_COEX_2W_OLD:
|
||||
* @BT_COEX_3W_OLD:
|
||||
* @BT_COEX_NW_OLD:
|
||||
* @BT_COEX_AUTO_OLD:
|
||||
* @BT_COEX_BT_OLD: Antenna is for BT (manufacuring tests)
|
||||
* @BT_COEX_WIFI_OLD: Antenna is for BT (manufacuring tests)
|
||||
* @BT_COEX_SYNC2SCO:
|
||||
* @BT_COEX_CORUNNING:
|
||||
* @BT_COEX_MPLUT:
|
||||
* @BT_COEX_TTC:
|
||||
* @BT_COEX_RRC:
|
||||
*
|
||||
* The COEX_MODE must be set for each command. Even if it is not changed.
|
||||
*/
|
||||
enum iwl_bt_coex_flags {
|
||||
BT_COEX_MODE_POS = 3,
|
||||
BT_COEX_MODE_MSK = BITS(3) << BT_COEX_MODE_POS,
|
||||
BT_COEX_DISABLE_OLD = 0x0 << BT_COEX_MODE_POS,
|
||||
BT_COEX_2W_OLD = 0x1 << BT_COEX_MODE_POS,
|
||||
BT_COEX_3W_OLD = 0x2 << BT_COEX_MODE_POS,
|
||||
BT_COEX_NW_OLD = 0x3 << BT_COEX_MODE_POS,
|
||||
BT_COEX_AUTO_OLD = 0x5 << BT_COEX_MODE_POS,
|
||||
BT_COEX_BT_OLD = 0x6 << BT_COEX_MODE_POS,
|
||||
BT_COEX_WIFI_OLD = 0x7 << BT_COEX_MODE_POS,
|
||||
BT_COEX_SYNC2SCO = BIT(7),
|
||||
BT_COEX_CORUNNING = BIT(8),
|
||||
BT_COEX_MPLUT = BIT(9),
|
||||
BT_COEX_TTC = BIT(20),
|
||||
BT_COEX_RRC = BIT(21),
|
||||
};
|
||||
|
||||
/*
|
||||
* indicates what has changed in the BT_COEX command.
|
||||
* BT_VALID_ENABLE must be set for each command. Commands without this bit will
|
||||
* discarded by the firmware
|
||||
*/
|
||||
enum iwl_bt_coex_valid_bit_msk {
|
||||
BT_VALID_ENABLE = BIT(0),
|
||||
BT_VALID_BT_PRIO_BOOST = BIT(1),
|
||||
BT_VALID_MAX_KILL = BIT(2),
|
||||
BT_VALID_3W_TMRS = BIT(3),
|
||||
BT_VALID_KILL_ACK = BIT(4),
|
||||
BT_VALID_KILL_CTS = BIT(5),
|
||||
BT_VALID_REDUCED_TX_POWER = BIT(6),
|
||||
BT_VALID_LUT = BIT(7),
|
||||
BT_VALID_WIFI_RX_SW_PRIO_BOOST = BIT(8),
|
||||
BT_VALID_WIFI_TX_SW_PRIO_BOOST = BIT(9),
|
||||
BT_VALID_MULTI_PRIO_LUT = BIT(10),
|
||||
BT_VALID_TRM_KICK_FILTER = BIT(11),
|
||||
BT_VALID_CORUN_LUT_20 = BIT(12),
|
||||
BT_VALID_CORUN_LUT_40 = BIT(13),
|
||||
BT_VALID_ANT_ISOLATION = BIT(14),
|
||||
BT_VALID_ANT_ISOLATION_THRS = BIT(15),
|
||||
BT_VALID_TXTX_DELTA_FREQ_THRS = BIT(16),
|
||||
BT_VALID_TXRX_MAX_FREQ_0 = BIT(17),
|
||||
BT_VALID_SYNC_TO_SCO = BIT(18),
|
||||
BT_VALID_TTC = BIT(20),
|
||||
BT_VALID_RRC = BIT(21),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_bt_reduced_tx_power - allows to reduce txpower for WiFi frames.
|
||||
* @BT_REDUCED_TX_POWER_CTL: reduce Tx power for control frames
|
||||
* @BT_REDUCED_TX_POWER_DATA: reduce Tx power for data frames
|
||||
*
|
||||
* This mechanism allows to have BT and WiFi run concurrently. Since WiFi
|
||||
* reduces its Tx power, it can work along with BT, hence reducing the amount
|
||||
* of WiFi frames being killed by BT.
|
||||
*/
|
||||
enum iwl_bt_reduced_tx_power {
|
||||
BT_REDUCED_TX_POWER_CTL = BIT(0),
|
||||
BT_REDUCED_TX_POWER_DATA = BIT(1),
|
||||
};
|
||||
|
||||
enum iwl_bt_coex_lut_type {
|
||||
BT_COEX_TIGHT_LUT = 0,
|
||||
BT_COEX_LOOSE_LUT,
|
||||
|
@ -158,64 +79,9 @@ enum iwl_bt_coex_lut_type {
|
|||
BT_COEX_INVALID_LUT = 0xff,
|
||||
}; /* BT_COEX_DECISION_LUT_INDEX_API_E_VER_1 */
|
||||
|
||||
#define BT_COEX_LUT_SIZE (12)
|
||||
#define BT_COEX_CORUN_LUT_SIZE (32)
|
||||
#define BT_COEX_MULTI_PRIO_LUT_SIZE (2)
|
||||
#define BT_COEX_BOOST_SIZE (4)
|
||||
#define BT_REDUCED_TX_POWER_BIT BIT(7)
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_cmd_old - bt coex configuration command
|
||||
* @flags:&enum iwl_bt_coex_flags
|
||||
* @max_kill:
|
||||
* @bt_reduced_tx_power: enum %iwl_bt_reduced_tx_power
|
||||
* @override_primary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
|
||||
* should be set by default
|
||||
* @override_secondary_lut: enum %iwl_bt_coex_lut_type: BT_COEX_INVALID_LUT
|
||||
* should be set by default
|
||||
* @bt4_antenna_isolation: antenna isolation
|
||||
* @bt4_antenna_isolation_thr: antenna threshold value
|
||||
* @bt4_tx_tx_delta_freq_thr: TxTx delta frequency
|
||||
* @bt4_tx_rx_max_freq0: TxRx max frequency
|
||||
* @bt_prio_boost: BT priority boost registers
|
||||
* @wifi_tx_prio_boost: SW boost of wifi tx priority
|
||||
* @wifi_rx_prio_boost: SW boost of wifi rx priority
|
||||
* @kill_ack_msk: kill ACK mask. 1 - Tx ACK, 0 - kill Tx of ACK.
|
||||
* @kill_cts_msk: kill CTS mask. 1 - Tx CTS, 0 - kill Tx of CTS.
|
||||
* @decision_lut: PTA decision LUT, per Prio-Ch
|
||||
* @bt4_multiprio_lut: multi priority LUT configuration
|
||||
* @bt4_corun_lut20: co-running 20 MHz LUT configuration
|
||||
* @bt4_corun_lut40: co-running 40 MHz LUT configuration
|
||||
* @valid_bit_msk: enum %iwl_bt_coex_valid_bit_msk
|
||||
*
|
||||
* The structure is used for the BT_COEX command.
|
||||
*/
|
||||
struct iwl_bt_coex_cmd_old {
|
||||
__le32 flags;
|
||||
u8 max_kill;
|
||||
u8 bt_reduced_tx_power;
|
||||
u8 override_primary_lut;
|
||||
u8 override_secondary_lut;
|
||||
|
||||
u8 bt4_antenna_isolation;
|
||||
u8 bt4_antenna_isolation_thr;
|
||||
u8 bt4_tx_tx_delta_freq_thr;
|
||||
u8 bt4_tx_rx_max_freq0;
|
||||
|
||||
__le32 bt_prio_boost[BT_COEX_BOOST_SIZE];
|
||||
__le32 wifi_tx_prio_boost;
|
||||
__le32 wifi_rx_prio_boost;
|
||||
__le32 kill_ack_msk;
|
||||
__le32 kill_cts_msk;
|
||||
|
||||
__le32 decision_lut[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE];
|
||||
__le32 bt4_multiprio_lut[BT_COEX_MULTI_PRIO_LUT_SIZE];
|
||||
__le32 bt4_corun_lut20[BT_COEX_CORUN_LUT_SIZE];
|
||||
__le32 bt4_corun_lut40[BT_COEX_CORUN_LUT_SIZE];
|
||||
|
||||
__le32 valid_bit_msk;
|
||||
} __packed; /* BT_COEX_CMD_API_S_VER_5 */
|
||||
|
||||
enum iwl_bt_coex_mode {
|
||||
BT_COEX_DISABLE = 0x0,
|
||||
BT_COEX_NW = 0x1,
|
||||
|
@ -385,92 +251,4 @@ struct iwl_bt_coex_profile_notif {
|
|||
u8 reserved[3];
|
||||
} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */
|
||||
|
||||
enum iwl_bt_coex_prio_table_event {
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB1 = 0,
|
||||
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2 = 1,
|
||||
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW1 = 2,
|
||||
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_LOW2 = 3,
|
||||
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH1 = 4,
|
||||
BT_COEX_PRIO_TBL_EVT_PERIODIC_CALIB_HIGH2 = 5,
|
||||
BT_COEX_PRIO_TBL_EVT_DTIM = 6,
|
||||
BT_COEX_PRIO_TBL_EVT_SCAN52 = 7,
|
||||
BT_COEX_PRIO_TBL_EVT_SCAN24 = 8,
|
||||
BT_COEX_PRIO_TBL_EVT_IDLE = 9,
|
||||
BT_COEX_PRIO_TBL_EVT_MAX = 16,
|
||||
}; /* BT_COEX_PRIO_TABLE_EVENTS_API_E_VER_1 */
|
||||
|
||||
enum iwl_bt_coex_prio_table_prio {
|
||||
BT_COEX_PRIO_TBL_DISABLED = 0,
|
||||
BT_COEX_PRIO_TBL_PRIO_LOW = 1,
|
||||
BT_COEX_PRIO_TBL_PRIO_HIGH = 2,
|
||||
BT_COEX_PRIO_TBL_PRIO_BYPASS = 3,
|
||||
BT_COEX_PRIO_TBL_PRIO_COEX_OFF = 4,
|
||||
BT_COEX_PRIO_TBL_PRIO_COEX_ON = 5,
|
||||
BT_COEX_PRIO_TBL_PRIO_COEX_IDLE = 6,
|
||||
BT_COEX_PRIO_TBL_MAX = 8,
|
||||
}; /* BT_COEX_PRIO_TABLE_PRIORITIES_API_E_VER_1 */
|
||||
|
||||
#define BT_COEX_PRIO_TBL_SHRD_ANT_POS (0)
|
||||
#define BT_COEX_PRIO_TBL_PRIO_POS (1)
|
||||
#define BT_COEX_PRIO_TBL_RESERVED_POS (4)
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_prio_tbl_cmd - priority table for BT coex
|
||||
* @prio_tbl:
|
||||
*/
|
||||
struct iwl_bt_coex_prio_tbl_cmd {
|
||||
u8 prio_tbl[BT_COEX_PRIO_TBL_EVT_MAX];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_ci_cmd_old - bt coex channel inhibition command
|
||||
* @bt_primary_ci:
|
||||
* @bt_secondary_ci:
|
||||
* @co_run_bw_primary:
|
||||
* @co_run_bw_secondary:
|
||||
* @primary_ch_phy_id:
|
||||
* @secondary_ch_phy_id:
|
||||
*
|
||||
* Used for BT_COEX_CI command
|
||||
*/
|
||||
struct iwl_bt_coex_ci_cmd_old {
|
||||
__le64 bt_primary_ci;
|
||||
__le64 bt_secondary_ci;
|
||||
|
||||
u8 co_run_bw_primary;
|
||||
u8 co_run_bw_secondary;
|
||||
u8 primary_ch_phy_id;
|
||||
u8 secondary_ch_phy_id;
|
||||
} __packed; /* BT_CI_MSG_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_bt_coex_profile_notif_old - notification about BT coex
|
||||
* @mbox_msg: message from BT to WiFi
|
||||
* @msg_idx: the index of the message
|
||||
* @bt_status: 0 - off, 1 - on
|
||||
* @bt_open_conn: number of BT connections open
|
||||
* @bt_traffic_load: load of BT traffic
|
||||
* @bt_agg_traffic_load: aggregated load of BT traffic
|
||||
* @bt_ci_compliance: 0 - no CI compliance, 1 - CI compliant
|
||||
* @primary_ch_lut: LUT used for primary channel
|
||||
* @secondary_ch_lut: LUT used for secondary channel
|
||||
* @bt_activity_grading: the activity of BT enum %iwl_bt_activity_grading
|
||||
*/
|
||||
struct iwl_bt_coex_profile_notif_old {
|
||||
__le32 mbox_msg[4];
|
||||
__le32 msg_idx;
|
||||
u8 bt_status;
|
||||
u8 bt_open_conn;
|
||||
u8 bt_traffic_load;
|
||||
u8 bt_agg_traffic_load;
|
||||
u8 bt_ci_compliance;
|
||||
u8 ttc_enabled;
|
||||
u8 rrc_enabled;
|
||||
u8 reserved;
|
||||
|
||||
__le32 primary_ch_lut;
|
||||
__le32 secondary_ch_lut;
|
||||
__le32 bt_activity_grading;
|
||||
} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_3 */
|
||||
|
||||
#endif /* __fw_api_bt_coex_h__ */
|
||||
|
|
|
@ -72,6 +72,9 @@
|
|||
#define NUM_MAC_INDEX_DRIVER MAC_INDEX_AUX
|
||||
#define NUM_MAC_INDEX (MAC_INDEX_AUX + 1)
|
||||
|
||||
#define IWL_MVM_STATION_COUNT 16
|
||||
#define IWL_MVM_TDLS_STA_COUNT 4
|
||||
|
||||
enum iwl_ac {
|
||||
AC_BK,
|
||||
AC_BE,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -34,7 +34,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -310,7 +310,8 @@ enum iwl_dev_tx_power_cmd_mode {
|
|||
IWL_TX_POWER_MODE_SET_MAC = 0,
|
||||
IWL_TX_POWER_MODE_SET_DEVICE = 1,
|
||||
IWL_TX_POWER_MODE_SET_CHAINS = 2,
|
||||
}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */;
|
||||
IWL_TX_POWER_MODE_SET_ACK = 3,
|
||||
}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_4 */;
|
||||
|
||||
/**
|
||||
* struct iwl_dev_tx_power_cmd_v2 - TX power reduction command
|
||||
|
@ -338,7 +339,7 @@ struct iwl_dev_tx_power_cmd_v2 {
|
|||
* @v2: version 2 of the command, embedded here for easier software handling
|
||||
* @per_chain_restriction: per chain restrictions
|
||||
*/
|
||||
struct iwl_dev_tx_power_cmd {
|
||||
struct iwl_dev_tx_power_cmd_v3 {
|
||||
/* v3 is just an extension of v2 - keep this here */
|
||||
struct iwl_dev_tx_power_cmd_v2 v2;
|
||||
__le16 per_chain_restriction[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS];
|
||||
|
@ -346,6 +347,19 @@ struct iwl_dev_tx_power_cmd {
|
|||
|
||||
#define IWL_DEV_MAX_TX_POWER 0x7FFF
|
||||
|
||||
/**
|
||||
* struct iwl_dev_tx_power_cmd - TX power reduction command
|
||||
* @v3: version 3 of the command, embedded here for easier software handling
|
||||
* @enable_ack_reduction: enable or disable close range ack TX power
|
||||
* reduction.
|
||||
*/
|
||||
struct iwl_dev_tx_power_cmd {
|
||||
/* v4 is just an extension of v3 - keep this here */
|
||||
struct iwl_dev_tx_power_cmd_v3 v3;
|
||||
u8 enable_ack_reduction;
|
||||
u8 reserved[3];
|
||||
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
|
||||
|
||||
/**
|
||||
* struct iwl_beacon_filter_cmd
|
||||
* REPLY_BEACON_FILTERING_CMD = 0xd2 (command)
|
||||
|
|
|
@ -296,7 +296,7 @@ enum iwl_rx_mpdu_status {
|
|||
IWL_RX_MPDU_STATUS_OVERRUN_OK = BIT(1),
|
||||
IWL_RX_MPDU_STATUS_SRC_STA_FOUND = BIT(2),
|
||||
IWL_RX_MPDU_STATUS_KEY_VALID = BIT(3),
|
||||
IWL_RX_MPDU_STATUS_KEY_ERROR = BIT(4),
|
||||
IWL_RX_MPDU_STATUS_KEY_PARAM_OK = BIT(4),
|
||||
IWL_RX_MPDU_STATUS_ICV_OK = BIT(5),
|
||||
IWL_RX_MPDU_STATUS_MIC_OK = BIT(6),
|
||||
IWL_RX_MPDU_RES_STATUS_TTAK_OK = BIT(7),
|
||||
|
@ -311,7 +311,7 @@ enum iwl_rx_mpdu_status {
|
|||
IWL_RX_MPDU_STATUS_WEP_MATCH = BIT(12),
|
||||
IWL_RX_MPDU_STATUS_EXT_IV_MATCH = BIT(13),
|
||||
IWL_RX_MPDU_STATUS_KEY_ID_MATCH = BIT(14),
|
||||
IWL_RX_MPDU_STATUS_KEY_COLOR = BIT(15),
|
||||
IWL_RX_MPDU_STATUS_ROBUST_MNG_FRAME = BIT(15),
|
||||
};
|
||||
|
||||
enum iwl_rx_mpdu_hash_filter {
|
||||
|
@ -336,6 +336,18 @@ enum iwl_rx_mpdu_reorder_data {
|
|||
IWL_RX_MPDU_REORDER_BA_OLD_SN = 0x80000000,
|
||||
};
|
||||
|
||||
enum iwl_rx_mpdu_phy_info {
|
||||
IWL_RX_MPDU_PHY_AMPDU = BIT(5),
|
||||
IWL_RX_MPDU_PHY_AMPDU_TOGGLE = BIT(6),
|
||||
IWL_RX_MPDU_PHY_SHORT_PREAMBLE = BIT(7),
|
||||
IWL_RX_MPDU_PHY_TSF_OVERLOAD = BIT(8),
|
||||
};
|
||||
|
||||
enum iwl_rx_mpdu_mac_info {
|
||||
IWL_RX_MPDU_PHY_MAC_INDEX_MASK = 0x0f,
|
||||
IWL_RX_MPDU_PHY_PHY_INDEX_MASK = 0xf0,
|
||||
};
|
||||
|
||||
struct iwl_rx_mpdu_desc {
|
||||
/* DW2 */
|
||||
__le16 mpdu_len;
|
||||
|
@ -343,9 +355,9 @@ struct iwl_rx_mpdu_desc {
|
|||
u8 mac_flags2;
|
||||
/* DW3 */
|
||||
u8 amsdu_info;
|
||||
__le16 reserved_for_software;
|
||||
__le16 phy_info;
|
||||
u8 mac_phy_idx;
|
||||
/* DW4 */
|
||||
/* DW4 - carries csum data only when rpa_en == 1 */
|
||||
__le16 raw_csum; /* alledgedly unreliable */
|
||||
__le16 l3l4_flags;
|
||||
/* DW5 */
|
||||
|
@ -354,17 +366,17 @@ struct iwl_rx_mpdu_desc {
|
|||
u8 sta_id_flags;
|
||||
/* DW6 */
|
||||
__le32 reorder_data;
|
||||
/* DW7 */
|
||||
/* DW7 - carries rss_hash only when rpa_en == 1 */
|
||||
__le32 rss_hash;
|
||||
/* DW8 */
|
||||
/* DW8 - carries filter_match only when rpa_en == 1 */
|
||||
__le32 filter_match;
|
||||
/* DW9 */
|
||||
__le32 rate_n_flags;
|
||||
/* DW10 */
|
||||
u8 energy_a, energy_b, channel, reserved;
|
||||
u8 energy_a, energy_b, channel, mac_context;
|
||||
/* DW11 */
|
||||
__le32 gp2_on_air_rise;
|
||||
/* DW12 & DW13 */
|
||||
/* DW12 & DW13 - carries TSF only TSF_OVERLOAD bit == 0 */
|
||||
__le64 tsf_on_air_rise;
|
||||
} __packed;
|
||||
|
||||
|
@ -435,26 +447,26 @@ struct iwl_rxq_sync_notification {
|
|||
} __packed; /* MULTI_QUEUE_DRV_SYNC_HDR_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* Internal message identifier
|
||||
*
|
||||
* @IWL_MVM_RXQ_EMPTY: empty sync notification
|
||||
* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
|
||||
*/
|
||||
* Internal message identifier
|
||||
*
|
||||
* @IWL_MVM_RXQ_EMPTY: empty sync notification
|
||||
* @IWL_MVM_RXQ_NOTIF_DEL_BA: notify RSS queues of delBA
|
||||
*/
|
||||
enum iwl_mvm_rxq_notif_type {
|
||||
IWL_MVM_RXQ_EMPTY,
|
||||
IWL_MVM_RXQ_NOTIF_DEL_BA,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
|
||||
* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
|
||||
* FW is agnostic to the payload, so there are no endianity requirements.
|
||||
*
|
||||
* @type: value from &iwl_mvm_rxq_notif_type
|
||||
* @sync: ctrl path is waiting for all notifications to be received
|
||||
* @cookie: internal cookie to identify old notifications
|
||||
* @data: payload
|
||||
*/
|
||||
* struct iwl_mvm_internal_rxq_notif - Internal representation of the data sent
|
||||
* in &iwl_rxq_sync_cmd. Should be DWORD aligned.
|
||||
* FW is agnostic to the payload, so there are no endianity requirements.
|
||||
*
|
||||
* @type: value from &iwl_mvm_rxq_notif_type
|
||||
* @sync: ctrl path is waiting for all notifications to be received
|
||||
* @cookie: internal cookie to identify old notifications
|
||||
* @data: payload
|
||||
*/
|
||||
struct iwl_mvm_internal_rxq_notif {
|
||||
u16 type;
|
||||
u16 sync;
|
||||
|
|
|
@ -141,6 +141,7 @@ enum iwl_sta_flags {
|
|||
* @STA_KEY_FLG_CCM: CCMP encryption algorithm
|
||||
* @STA_KEY_FLG_TKIP: TKIP encryption algorithm
|
||||
* @STA_KEY_FLG_EXT: extended cipher algorithm (depends on the FW support)
|
||||
* @STA_KEY_FLG_GCMP: GCMP encryption algorithm
|
||||
* @STA_KEY_FLG_CMAC: CMAC encryption algorithm
|
||||
* @STA_KEY_FLG_ENC_UNKNOWN: unknown encryption algorithm
|
||||
* @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value
|
||||
|
@ -149,6 +150,7 @@ enum iwl_sta_flags {
|
|||
* @STA_KEY_FLG_KEYID_MSK: the index of the key
|
||||
* @STA_KEY_NOT_VALID: key is invalid
|
||||
* @STA_KEY_FLG_WEP_13BYTES: set for 13 bytes WEP key
|
||||
* @STA_KEY_FLG_KEY_32BYTES for non-wep key set for 32 bytes key
|
||||
* @STA_KEY_MULTICAST: set for multical key
|
||||
* @STA_KEY_MFP: key is used for Management Frame Protection
|
||||
*/
|
||||
|
@ -158,6 +160,7 @@ enum iwl_sta_key_flag {
|
|||
STA_KEY_FLG_CCM = (2 << 0),
|
||||
STA_KEY_FLG_TKIP = (3 << 0),
|
||||
STA_KEY_FLG_EXT = (4 << 0),
|
||||
STA_KEY_FLG_GCMP = (5 << 0),
|
||||
STA_KEY_FLG_CMAC = (6 << 0),
|
||||
STA_KEY_FLG_ENC_UNKNOWN = (7 << 0),
|
||||
STA_KEY_FLG_EN_MSK = (7 << 0),
|
||||
|
@ -167,6 +170,7 @@ enum iwl_sta_key_flag {
|
|||
STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS),
|
||||
STA_KEY_NOT_VALID = BIT(11),
|
||||
STA_KEY_FLG_WEP_13BYTES = BIT(12),
|
||||
STA_KEY_FLG_KEY_32BYTES = BIT(12),
|
||||
STA_KEY_MULTICAST = BIT(14),
|
||||
STA_KEY_MFP = BIT(15),
|
||||
};
|
||||
|
@ -388,7 +392,6 @@ struct iwl_mvm_add_sta_cmd {
|
|||
* @key_offset: key offset in key storage
|
||||
* @key_flags: type %iwl_sta_key_flag
|
||||
* @key: key material data
|
||||
* @key2: key material data
|
||||
* @rx_secur_seq_cnt: RX security sequence counter for the key
|
||||
* @tkip_rx_tsc_byte2: TSC[2] for key mix ph1 detection
|
||||
* @tkip_rx_ttak: 10-byte unicast TKIP TTAK for Rx
|
||||
|
@ -397,8 +400,7 @@ struct iwl_mvm_add_sta_key_cmd {
|
|||
u8 sta_id;
|
||||
u8 key_offset;
|
||||
__le16 key_flags;
|
||||
u8 key[16];
|
||||
u8 key2[16];
|
||||
u8 key[32];
|
||||
u8 rx_secur_seq_cnt[16];
|
||||
u8 tkip_rx_tsc_byte2;
|
||||
u8 reserved;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*
|
||||
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
|
||||
* Copyright(c) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
|
@ -252,6 +253,20 @@ struct mvm_statistics_general_v8 {
|
|||
u8 reserved[4 - (NUM_MAC_INDEX % 4)];
|
||||
} __packed; /* STATISTICS_GENERAL_API_S_VER_8 */
|
||||
|
||||
/**
|
||||
* struct mvm_statistics_load - RX statistics for multi-queue devices
|
||||
* @air_time: accumulated air time, per mac
|
||||
* @byte_count: accumulated byte count, per mac
|
||||
* @pkt_count: accumulated packet count, per mac
|
||||
* @avg_energy: average RSSI, per station
|
||||
*/
|
||||
struct mvm_statistics_load {
|
||||
__le32 air_time[NUM_MAC_INDEX];
|
||||
__le32 byte_count[NUM_MAC_INDEX];
|
||||
__le32 pkt_count[NUM_MAC_INDEX];
|
||||
u8 avg_energy[IWL_MVM_STATION_COUNT];
|
||||
} __packed; /* STATISTICS_RX_MAC_STATION_S_VER_1 */
|
||||
|
||||
struct mvm_statistics_rx {
|
||||
struct mvm_statistics_rx_phy ofdm;
|
||||
struct mvm_statistics_rx_phy cck;
|
||||
|
@ -266,7 +281,6 @@ struct mvm_statistics_rx {
|
|||
* while associated. To disable this behavior, set DISABLE_NOTIF flag in the
|
||||
* STATISTICS_CMD (0x9c), below.
|
||||
*/
|
||||
|
||||
struct iwl_notif_statistics_v10 {
|
||||
__le32 flag;
|
||||
struct mvm_statistics_rx rx;
|
||||
|
@ -274,6 +288,14 @@ struct iwl_notif_statistics_v10 {
|
|||
struct mvm_statistics_general_v8 general;
|
||||
} __packed; /* STATISTICS_NTFY_API_S_VER_10 */
|
||||
|
||||
struct iwl_notif_statistics_v11 {
|
||||
__le32 flag;
|
||||
struct mvm_statistics_rx rx;
|
||||
struct mvm_statistics_tx tx;
|
||||
struct mvm_statistics_general_v8 general;
|
||||
struct mvm_statistics_load load_stats;
|
||||
} __packed; /* STATISTICS_NTFY_API_S_VER_11 */
|
||||
|
||||
#define IWL_STATISTICS_FLG_CLEAR 0x1
|
||||
#define IWL_STATISTICS_FLG_DISABLE_NOTIF 0x2
|
||||
|
||||
|
|
|
@ -137,17 +137,32 @@ enum iwl_tx_pm_timeouts {
|
|||
PM_FRAME_ASSOC = 3,
|
||||
};
|
||||
|
||||
/*
|
||||
* TX command security control
|
||||
*/
|
||||
#define TX_CMD_SEC_WEP 0x01
|
||||
#define TX_CMD_SEC_CCM 0x02
|
||||
#define TX_CMD_SEC_TKIP 0x03
|
||||
#define TX_CMD_SEC_EXT 0x04
|
||||
#define TX_CMD_SEC_MSK 0x07
|
||||
#define TX_CMD_SEC_WEP_KEY_IDX_POS 6
|
||||
#define TX_CMD_SEC_WEP_KEY_IDX_MSK 0xc0
|
||||
#define TX_CMD_SEC_KEY128 0x08
|
||||
|
||||
/**
|
||||
* enum iwl_tx_cmd_sec_ctrl - bitmasks for security control in TX command
|
||||
* @TX_CMD_SEC_WEP: WEP encryption algorithm.
|
||||
* @TX_CMD_SEC_CCM: CCM encryption algorithm.
|
||||
* @TX_CMD_SEC_TKIP: TKIP encryption algorithm.
|
||||
* @TX_CMD_SEC_EXT: extended cipher algorithm.
|
||||
* @TX_CMD_SEC_GCMP: GCMP encryption algorithm.
|
||||
* @TX_CMD_SEC_KEY128: set for 104 bits WEP key.
|
||||
* @TC_CMD_SEC_KEY_FROM_TABLE: for a non-WEP key, set if the key should be taken
|
||||
* from the table instead of from the TX command.
|
||||
* If the key is taken from the key table its index should be given by the
|
||||
* first byte of the TX command key field.
|
||||
*/
|
||||
enum iwl_tx_cmd_sec_ctrl {
|
||||
TX_CMD_SEC_WEP = 0x01,
|
||||
TX_CMD_SEC_CCM = 0x02,
|
||||
TX_CMD_SEC_TKIP = 0x03,
|
||||
TX_CMD_SEC_EXT = 0x04,
|
||||
TX_CMD_SEC_GCMP = 0x05,
|
||||
TX_CMD_SEC_KEY128 = 0x08,
|
||||
TC_CMD_SEC_KEY_FROM_TABLE = 0x08,
|
||||
};
|
||||
|
||||
/* TODO: how does these values are OK with only 16 bit variable??? */
|
||||
/*
|
||||
|
@ -562,8 +577,8 @@ struct iwl_mvm_ba_notif {
|
|||
u8 reserved1;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* struct iwl_mac_beacon_cmd - beacon template command
|
||||
/**
|
||||
* struct iwl_mac_beacon_cmd_v6 - beacon template command
|
||||
* @tx: the tx commands associated with the beacon frame
|
||||
* @template_id: currently equal to the mac context id of the coresponding
|
||||
* mac.
|
||||
|
@ -571,13 +586,34 @@ struct iwl_mvm_ba_notif {
|
|||
* @tim_size: the length of the tim IE
|
||||
* @frame: the template of the beacon frame
|
||||
*/
|
||||
struct iwl_mac_beacon_cmd {
|
||||
struct iwl_mac_beacon_cmd_v6 {
|
||||
struct iwl_tx_cmd tx;
|
||||
__le32 template_id;
|
||||
__le32 tim_idx;
|
||||
__le32 tim_size;
|
||||
struct ieee80211_hdr frame[0];
|
||||
} __packed;
|
||||
} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_6 */
|
||||
|
||||
/**
|
||||
* struct iwl_mac_beacon_cmd - beacon template command with offloaded CSA
|
||||
* @tx: the tx commands associated with the beacon frame
|
||||
* @template_id: currently equal to the mac context id of the coresponding
|
||||
* mac.
|
||||
* @tim_idx: the offset of the tim IE in the beacon
|
||||
* @tim_size: the length of the tim IE
|
||||
* @ecsa_offset: offset to the ECSA IE if present
|
||||
* @csa_offset: offset to the CSA IE if present
|
||||
* @frame: the template of the beacon frame
|
||||
*/
|
||||
struct iwl_mac_beacon_cmd {
|
||||
struct iwl_tx_cmd tx;
|
||||
__le32 template_id;
|
||||
__le32 tim_idx;
|
||||
__le32 tim_size;
|
||||
__le32 ecsa_offset;
|
||||
__le32 csa_offset;
|
||||
struct ieee80211_hdr frame[0];
|
||||
} __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_7 */
|
||||
|
||||
struct iwl_beacon_notif {
|
||||
struct iwl_mvm_tx_resp beacon_notify_hdr;
|
||||
|
|
|
@ -90,6 +90,7 @@ enum {
|
|||
* DQA queue numbers
|
||||
*
|
||||
* @IWL_MVM_DQA_CMD_QUEUE: a queue reserved for sending HCMDs to the FW
|
||||
* @IWL_MVM_DQA_AUX_QUEUE: a queue reserved for aux frames
|
||||
* @IWL_MVM_DQA_P2P_DEVICE_QUEUE: a queue reserved for P2P device frames
|
||||
* @IWL_MVM_DQA_GCAST_QUEUE: a queue reserved for P2P GO/SoftAP GCAST frames
|
||||
* @IWL_MVM_DQA_BSS_CLIENT_QUEUE: a queue reserved for BSS activity, to ensure
|
||||
|
@ -108,6 +109,7 @@ enum {
|
|||
*/
|
||||
enum iwl_mvm_dqa_txq {
|
||||
IWL_MVM_DQA_CMD_QUEUE = 0,
|
||||
IWL_MVM_DQA_AUX_QUEUE = 1,
|
||||
IWL_MVM_DQA_P2P_DEVICE_QUEUE = 2,
|
||||
IWL_MVM_DQA_GCAST_QUEUE = 3,
|
||||
IWL_MVM_DQA_BSS_CLIENT_QUEUE = 4,
|
||||
|
@ -127,9 +129,6 @@ enum iwl_mvm_tx_fifo {
|
|||
IWL_MVM_TX_FIFO_CMD = 7,
|
||||
};
|
||||
|
||||
#define IWL_MVM_STATION_COUNT 16
|
||||
|
||||
#define IWL_MVM_TDLS_STA_COUNT 4
|
||||
|
||||
/* commands */
|
||||
enum {
|
||||
|
@ -314,6 +313,7 @@ enum {
|
|||
enum iwl_mac_conf_subcmd_ids {
|
||||
LINK_QUALITY_MEASUREMENT_CMD = 0x1,
|
||||
LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF = 0xFE,
|
||||
CHANNEL_SWITCH_NOA_NOTIF = 0xFF,
|
||||
};
|
||||
|
||||
enum iwl_phy_ops_subcmd_ids {
|
||||
|
@ -329,6 +329,7 @@ enum iwl_system_subcmd_ids {
|
|||
};
|
||||
|
||||
enum iwl_data_path_subcmd_ids {
|
||||
DQA_ENABLE_CMD = 0x0,
|
||||
UPDATE_MU_GROUPS_CMD = 0x1,
|
||||
TRIGGER_RX_QUEUES_NOTIF_CMD = 0x2,
|
||||
MU_GROUP_MGMT_NOTIF = 0xFE,
|
||||
|
@ -358,6 +359,14 @@ struct iwl_cmd_response {
|
|||
__le32 status;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct iwl_dqa_enable_cmd
|
||||
* @cmd_queue: the TXQ number of the command queue
|
||||
*/
|
||||
struct iwl_dqa_enable_cmd {
|
||||
__le32 cmd_queue;
|
||||
} __packed; /* DQA_CONTROL_CMD_API_S_VER_1 */
|
||||
|
||||
/*
|
||||
* struct iwl_tx_ant_cfg_cmd
|
||||
* @valid: valid antenna configuration
|
||||
|
@ -732,7 +741,7 @@ enum iwl_time_event_type {
|
|||
|
||||
/* P2P GO Events */
|
||||
TE_P2P_GO_ASSOC_PROT,
|
||||
TE_P2P_GO_REPETITIVE_NOA,
|
||||
TE_P2P_GO_REPETITIVET_NOA,
|
||||
TE_P2P_GO_CT_WINDOW,
|
||||
|
||||
/* WiDi Sync Events */
|
||||
|
@ -2111,4 +2120,13 @@ struct iwl_link_qual_msrmnt_notif {
|
|||
__le32 reserved[3];
|
||||
} __packed; /* LQM_MEASUREMENT_COMPLETE_NTF_API_S_VER1 */
|
||||
|
||||
/**
|
||||
* Channel switch NOA notification
|
||||
*
|
||||
* @id_and_color: ID and color of the MAC
|
||||
*/
|
||||
struct iwl_channel_switch_noa_notif {
|
||||
__le32 id_and_color;
|
||||
} __packed; /* CHANNEL_SWITCH_START_NTFY_API_S_VER_1 */
|
||||
|
||||
#endif /* __fw_api_h__ */
|
||||
|
|
|
@ -288,7 +288,8 @@ static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
|
|||
fifo_hdr->fifo_num = cpu_to_le32(i);
|
||||
|
||||
/* Mark the number of TXF we're pulling now */
|
||||
iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i);
|
||||
iwl_trans_write_prph(mvm->trans, TXF_CPU2_NUM, i +
|
||||
ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size));
|
||||
|
||||
fifo_hdr->available_bytes =
|
||||
cpu_to_le32(iwl_trans_read_prph(mvm->trans,
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
*****************************************************************************/
|
||||
#include <net/mac80211.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-op-mode.h"
|
||||
|
@ -122,6 +123,9 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
|
|||
IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
|
||||
};
|
||||
|
||||
if (mvm->trans->num_rx_queues == 1)
|
||||
return 0;
|
||||
|
||||
/* Do not direct RSS traffic to Q 0 which is our fallback queue */
|
||||
for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++)
|
||||
cmd.indirection_table[i] =
|
||||
|
@ -131,6 +135,23 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
|
|||
return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
static int iwl_mvm_send_dqa_cmd(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_dqa_enable_cmd dqa_cmd = {
|
||||
.cmd_queue = cpu_to_le32(IWL_MVM_DQA_CMD_QUEUE),
|
||||
};
|
||||
u32 cmd_id = iwl_cmd_id(DQA_ENABLE_CMD, DATA_PATH_GROUP, 0);
|
||||
int ret;
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(dqa_cmd), &dqa_cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed to send DQA enabling command: %d\n", ret);
|
||||
else
|
||||
IWL_DEBUG_FW(mvm, "Working in DQA mode\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iwl_free_fw_paging(struct iwl_mvm *mvm)
|
||||
{
|
||||
int i;
|
||||
|
@ -139,17 +160,21 @@ void iwl_free_fw_paging(struct iwl_mvm *mvm)
|
|||
return;
|
||||
|
||||
for (i = 0; i < NUM_OF_FW_PAGING_BLOCKS; i++) {
|
||||
if (!mvm->fw_paging_db[i].fw_paging_block) {
|
||||
struct iwl_fw_paging *paging = &mvm->fw_paging_db[i];
|
||||
|
||||
if (!paging->fw_paging_block) {
|
||||
IWL_DEBUG_FW(mvm,
|
||||
"Paging: block %d already freed, continue to next page\n",
|
||||
i);
|
||||
|
||||
continue;
|
||||
}
|
||||
dma_unmap_page(mvm->trans->dev, paging->fw_paging_phys,
|
||||
paging->fw_paging_size, DMA_BIDIRECTIONAL);
|
||||
|
||||
__free_pages(mvm->fw_paging_db[i].fw_paging_block,
|
||||
get_order(mvm->fw_paging_db[i].fw_paging_size));
|
||||
mvm->fw_paging_db[i].fw_paging_block = NULL;
|
||||
__free_pages(paging->fw_paging_block,
|
||||
get_order(paging->fw_paging_size));
|
||||
paging->fw_paging_block = NULL;
|
||||
}
|
||||
kfree(mvm->trans->paging_download_buf);
|
||||
mvm->trans->paging_download_buf = NULL;
|
||||
|
@ -882,6 +907,177 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
|
|||
sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
#define ACPI_WRDS_METHOD "WRDS"
|
||||
#define ACPI_WRDS_WIFI (0x07)
|
||||
#define ACPI_WRDS_TABLE_SIZE 10
|
||||
|
||||
struct iwl_mvm_sar_table {
|
||||
bool enabled;
|
||||
u8 values[ACPI_WRDS_TABLE_SIZE];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static int iwl_mvm_sar_get_wrds(struct iwl_mvm *mvm, union acpi_object *wrds,
|
||||
struct iwl_mvm_sar_table *sar_table)
|
||||
{
|
||||
union acpi_object *data_pkg;
|
||||
u32 i;
|
||||
|
||||
/* We need at least two packages, one for the revision and one
|
||||
* for the data itself. Also check that the revision is valid
|
||||
* (i.e. it is an integer set to 0).
|
||||
*/
|
||||
if (wrds->type != ACPI_TYPE_PACKAGE ||
|
||||
wrds->package.count < 2 ||
|
||||
wrds->package.elements[0].type != ACPI_TYPE_INTEGER ||
|
||||
wrds->package.elements[0].integer.value != 0) {
|
||||
IWL_DEBUG_RADIO(mvm, "Unsupported wrds structure\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* loop through all the packages to find the one for WiFi */
|
||||
for (i = 1; i < wrds->package.count; i++) {
|
||||
union acpi_object *domain;
|
||||
|
||||
data_pkg = &wrds->package.elements[i];
|
||||
|
||||
/* Skip anything that is not a package with the right
|
||||
* amount of elements (i.e. domain_type,
|
||||
* enabled/disabled plus the sar table size.
|
||||
*/
|
||||
if (data_pkg->type != ACPI_TYPE_PACKAGE ||
|
||||
data_pkg->package.count != ACPI_WRDS_TABLE_SIZE + 2)
|
||||
continue;
|
||||
|
||||
domain = &data_pkg->package.elements[0];
|
||||
if (domain->type == ACPI_TYPE_INTEGER &&
|
||||
domain->integer.value == ACPI_WRDS_WIFI)
|
||||
break;
|
||||
|
||||
data_pkg = NULL;
|
||||
}
|
||||
|
||||
if (!data_pkg)
|
||||
return -ENOENT;
|
||||
|
||||
if (data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
|
||||
return -EINVAL;
|
||||
|
||||
sar_table->enabled = !!(data_pkg->package.elements[1].integer.value);
|
||||
|
||||
for (i = 0; i < ACPI_WRDS_TABLE_SIZE; i++) {
|
||||
union acpi_object *entry;
|
||||
|
||||
entry = &data_pkg->package.elements[i + 2];
|
||||
if ((entry->type != ACPI_TYPE_INTEGER) ||
|
||||
(entry->integer.value > U8_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
sar_table->values[i] = entry->integer.value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_sar_table *sar_table)
|
||||
{
|
||||
acpi_handle root_handle;
|
||||
acpi_handle handle;
|
||||
struct acpi_buffer wrds = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
int ret;
|
||||
|
||||
root_handle = ACPI_HANDLE(mvm->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Get the method's handle */
|
||||
status = acpi_get_handle(root_handle, (acpi_string)ACPI_WRDS_METHOD,
|
||||
&handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WRDS method not found\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* Call WRDS with no arguments */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &wrds);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
IWL_DEBUG_RADIO(mvm, "WRDS invocation failed (0x%x)\n", status);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ret = iwl_mvm_sar_get_wrds(mvm, wrds.pointer, sar_table);
|
||||
kfree(wrds.pointer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else /* CONFIG_ACPI */
|
||||
static int iwl_mvm_sar_get_table(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_sar_table *sar_table)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int iwl_mvm_sar_init(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_mvm_sar_table sar_table;
|
||||
struct iwl_dev_tx_power_cmd cmd = {
|
||||
.v3.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),
|
||||
};
|
||||
int ret, i, j, idx;
|
||||
int len = sizeof(cmd);
|
||||
|
||||
/* we can't do anything with the table if the FW doesn't support it */
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_TX_POWER_CHAIN)) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"FW doesn't support per-chain TX power settings.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
|
||||
len = sizeof(cmd.v3);
|
||||
|
||||
ret = iwl_mvm_sar_get_table(mvm, &sar_table);
|
||||
if (ret < 0) {
|
||||
IWL_DEBUG_RADIO(mvm,
|
||||
"SAR BIOS table invalid or unavailable. (%d)\n",
|
||||
ret);
|
||||
/* we don't fail if the table is not available */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sar_table.enabled)
|
||||
return 0;
|
||||
|
||||
IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n");
|
||||
|
||||
BUILD_BUG_ON(IWL_NUM_CHAIN_LIMITS * IWL_NUM_SUB_BANDS !=
|
||||
ACPI_WRDS_TABLE_SIZE);
|
||||
|
||||
for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
|
||||
IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i);
|
||||
for (j = 0; j < IWL_NUM_SUB_BANDS; j++) {
|
||||
idx = (i * IWL_NUM_SUB_BANDS) + j;
|
||||
cmd.v3.per_chain_restriction[i][j] =
|
||||
cpu_to_le16(sar_table.values[idx]);
|
||||
IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n",
|
||||
j, sar_table.values[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to set per-chain TX power: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mvm_up(struct iwl_mvm *mvm)
|
||||
{
|
||||
int ret, i;
|
||||
|
@ -976,6 +1172,15 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
/* reset quota debouncing buffer - 0xff will yield invalid data */
|
||||
memset(&mvm->last_quota_cmd, 0xff, sizeof(mvm->last_quota_cmd));
|
||||
|
||||
/* Enable DQA-mode if required */
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
ret = iwl_mvm_send_dqa_cmd(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
} else {
|
||||
IWL_DEBUG_FW(mvm, "Working in non-DQA mode\n");
|
||||
}
|
||||
|
||||
/* Add auxiliary station for scanning */
|
||||
ret = iwl_mvm_add_aux_sta(mvm);
|
||||
if (ret)
|
||||
|
@ -1048,6 +1253,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
|
|||
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN);
|
||||
|
||||
ret = iwl_mvm_sar_init(mvm);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
|
||||
return 0;
|
||||
error:
|
||||
|
|
|
@ -1006,7 +1006,7 @@ static int iwl_mvm_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
|
||||
struct iwl_mac_beacon_cmd *beacon_cmd,
|
||||
struct iwl_mac_beacon_cmd_v6 *beacon_cmd,
|
||||
u8 *beacon, u32 frame_size)
|
||||
{
|
||||
u32 tim_idx;
|
||||
|
@ -1030,6 +1030,23 @@ static void iwl_mvm_mac_ctxt_set_tim(struct iwl_mvm *mvm,
|
|||
}
|
||||
}
|
||||
|
||||
static u32 iwl_mvm_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
|
||||
{
|
||||
struct ieee80211_mgmt *mgmt = (void *)beacon;
|
||||
const u8 *ie;
|
||||
|
||||
if (WARN_ON_ONCE(frame_size <= (mgmt->u.beacon.variable - beacon)))
|
||||
return 0;
|
||||
|
||||
frame_size -= mgmt->u.beacon.variable - beacon;
|
||||
|
||||
ie = cfg80211_find_ie(eid, mgmt->u.beacon.variable, frame_size);
|
||||
if (!ie)
|
||||
return 0;
|
||||
|
||||
return ie - beacon;
|
||||
}
|
||||
|
||||
static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
struct sk_buff *beacon)
|
||||
|
@ -1039,7 +1056,10 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
.id = BEACON_TEMPLATE_CMD,
|
||||
.flags = CMD_ASYNC,
|
||||
};
|
||||
struct iwl_mac_beacon_cmd beacon_cmd = {};
|
||||
union {
|
||||
struct iwl_mac_beacon_cmd_v6 beacon_cmd_v6;
|
||||
struct iwl_mac_beacon_cmd beacon_cmd;
|
||||
} u = {};
|
||||
struct ieee80211_tx_info *info;
|
||||
u32 beacon_skb_len;
|
||||
u32 rate, tx_flags;
|
||||
|
@ -1051,18 +1071,18 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
|
||||
/* TODO: for now the beacon template id is set to be the mac context id.
|
||||
* Might be better to handle it as another resource ... */
|
||||
beacon_cmd.template_id = cpu_to_le32((u32)mvmvif->id);
|
||||
u.beacon_cmd_v6.template_id = cpu_to_le32((u32)mvmvif->id);
|
||||
info = IEEE80211_SKB_CB(beacon);
|
||||
|
||||
/* Set up TX command fields */
|
||||
beacon_cmd.tx.len = cpu_to_le16((u16)beacon_skb_len);
|
||||
beacon_cmd.tx.sta_id = mvmvif->bcast_sta.sta_id;
|
||||
beacon_cmd.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
||||
u.beacon_cmd_v6.tx.len = cpu_to_le16((u16)beacon_skb_len);
|
||||
u.beacon_cmd_v6.tx.sta_id = mvmvif->bcast_sta.sta_id;
|
||||
u.beacon_cmd_v6.tx.life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
|
||||
tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF;
|
||||
tx_flags |=
|
||||
iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) <<
|
||||
TX_CMD_FLG_BT_PRIO_POS;
|
||||
beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
|
||||
u.beacon_cmd_v6.tx.tx_flags = cpu_to_le32(tx_flags);
|
||||
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) {
|
||||
|
@ -1071,7 +1091,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
mvm->mgmt_last_antenna_idx);
|
||||
}
|
||||
|
||||
beacon_cmd.tx.rate_n_flags =
|
||||
u.beacon_cmd_v6.tx.rate_n_flags =
|
||||
cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) <<
|
||||
RATE_MCS_ANT_POS);
|
||||
|
||||
|
@ -1079,20 +1099,37 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
|
|||
rate = IWL_FIRST_OFDM_RATE;
|
||||
} else {
|
||||
rate = IWL_FIRST_CCK_RATE;
|
||||
beacon_cmd.tx.rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK);
|
||||
u.beacon_cmd_v6.tx.rate_n_flags |=
|
||||
cpu_to_le32(RATE_MCS_CCK_MSK);
|
||||
}
|
||||
beacon_cmd.tx.rate_n_flags |=
|
||||
u.beacon_cmd_v6.tx.rate_n_flags |=
|
||||
cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(rate));
|
||||
|
||||
/* Set up TX beacon command fields */
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
iwl_mvm_mac_ctxt_set_tim(mvm, &beacon_cmd,
|
||||
iwl_mvm_mac_ctxt_set_tim(mvm, &u.beacon_cmd_v6,
|
||||
beacon->data,
|
||||
beacon_skb_len);
|
||||
|
||||
/* Submit command */
|
||||
cmd.len[0] = sizeof(beacon_cmd);
|
||||
cmd.data[0] = &beacon_cmd;
|
||||
|
||||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CSA_AND_TBTT_OFFLOAD)) {
|
||||
u.beacon_cmd.csa_offset =
|
||||
cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data,
|
||||
WLAN_EID_CHANNEL_SWITCH,
|
||||
beacon_skb_len));
|
||||
u.beacon_cmd.ecsa_offset =
|
||||
cpu_to_le32(iwl_mvm_find_ie_offset(beacon->data,
|
||||
WLAN_EID_EXT_CHANSWITCH_ANN,
|
||||
beacon_skb_len));
|
||||
|
||||
cmd.len[0] = sizeof(u.beacon_cmd);
|
||||
} else {
|
||||
cmd.len[0] = sizeof(u.beacon_cmd_v6);
|
||||
}
|
||||
|
||||
cmd.data[0] = &u;
|
||||
cmd.dataflags[0] = 0;
|
||||
cmd.len[1] = beacon_skb_len;
|
||||
cmd.data[1] = beacon->data;
|
||||
|
@ -1538,3 +1575,48 @@ void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
|
|||
/* pass it as regular rx to mac80211 */
|
||||
ieee80211_rx_napi(mvm->hw, NULL, skb, NULL);
|
||||
}
|
||||
|
||||
void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb)
|
||||
{
|
||||
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
||||
struct iwl_channel_switch_noa_notif *notif = (void *)pkt->data;
|
||||
struct ieee80211_vif *csa_vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
int len = iwl_rx_packet_payload_len(pkt);
|
||||
u32 id_n_color;
|
||||
|
||||
if (WARN_ON_ONCE(len < sizeof(*notif)))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
csa_vif = rcu_dereference(mvm->csa_vif);
|
||||
if (WARN_ON(!csa_vif || !csa_vif->csa_active))
|
||||
goto out_unlock;
|
||||
|
||||
id_n_color = le32_to_cpu(notif->id_and_color);
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(csa_vif);
|
||||
if (WARN(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color) != id_n_color,
|
||||
"channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)",
|
||||
FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color), id_n_color))
|
||||
goto out_unlock;
|
||||
|
||||
IWL_DEBUG_INFO(mvm, "Channel Switch Started Notification\n");
|
||||
|
||||
queue_delayed_work(system_wq, &mvm->cs_tx_unblock_dwork,
|
||||
msecs_to_jiffies(IWL_MVM_CS_UNBLOCK_TX_TIMEOUT *
|
||||
csa_vif->bss_conf.beacon_int));
|
||||
|
||||
ieee80211_csa_finish(csa_vif);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
RCU_INIT_POINTER(mvm->csa_vif, NULL);
|
||||
|
||||
return;
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -465,11 +465,20 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
|
||||
hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 2);
|
||||
BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 4);
|
||||
memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
|
||||
hw->wiphy->n_cipher_suites = ARRAY_SIZE(mvm_ciphers);
|
||||
hw->wiphy->cipher_suites = mvm->ciphers;
|
||||
|
||||
if (iwl_mvm_has_new_rx_api(mvm)) {
|
||||
mvm->ciphers[hw->wiphy->n_cipher_suites] =
|
||||
WLAN_CIPHER_SUITE_GCMP;
|
||||
hw->wiphy->n_cipher_suites++;
|
||||
mvm->ciphers[hw->wiphy->n_cipher_suites] =
|
||||
WLAN_CIPHER_SUITE_GCMP_256;
|
||||
hw->wiphy->n_cipher_suites++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable 11w if advertised by firmware and software crypto
|
||||
* is not enabled (as the firmware will interpret some mgmt
|
||||
|
@ -485,10 +494,23 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
|
|||
|
||||
/* currently FW API supports only one optional cipher scheme */
|
||||
if (mvm->fw->cs[0].cipher) {
|
||||
const struct iwl_fw_cipher_scheme *fwcs = &mvm->fw->cs[0];
|
||||
struct ieee80211_cipher_scheme *cs = &mvm->cs[0];
|
||||
|
||||
mvm->hw->n_cipher_schemes = 1;
|
||||
mvm->hw->cipher_schemes = &mvm->fw->cs[0];
|
||||
mvm->ciphers[hw->wiphy->n_cipher_suites] =
|
||||
mvm->fw->cs[0].cipher;
|
||||
|
||||
cs->cipher = le32_to_cpu(fwcs->cipher);
|
||||
cs->iftype = BIT(NL80211_IFTYPE_STATION);
|
||||
cs->hdr_len = fwcs->hdr_len;
|
||||
cs->pn_len = fwcs->pn_len;
|
||||
cs->pn_off = fwcs->pn_off;
|
||||
cs->key_idx_off = fwcs->key_idx_off;
|
||||
cs->key_idx_mask = fwcs->key_idx_mask;
|
||||
cs->key_idx_shift = fwcs->key_idx_shift;
|
||||
cs->mic_len = fwcs->mic_len;
|
||||
|
||||
mvm->hw->cipher_schemes = mvm->cs;
|
||||
mvm->ciphers[hw->wiphy->n_cipher_suites] = cs->cipher;
|
||||
hw->wiphy->n_cipher_suites++;
|
||||
}
|
||||
|
||||
|
@ -1011,11 +1033,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
|||
memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames));
|
||||
memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
|
||||
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
|
||||
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
|
||||
memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
|
||||
memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
|
||||
memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk));
|
||||
memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk));
|
||||
|
||||
ieee80211_wake_queues(mvm->hw);
|
||||
|
||||
|
@ -1199,6 +1217,8 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
|
|||
flush_work(&mvm->async_handlers_wk);
|
||||
flush_work(&mvm->add_stream_wk);
|
||||
cancel_delayed_work_sync(&mvm->fw_dump_wk);
|
||||
cancel_delayed_work_sync(&mvm->cs_tx_unblock_dwork);
|
||||
cancel_delayed_work_sync(&mvm->scan_timeout_dwork);
|
||||
iwl_mvm_free_fw_dump_desc(mvm);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
@ -1230,18 +1250,20 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
s16 tx_power)
|
||||
{
|
||||
struct iwl_dev_tx_power_cmd cmd = {
|
||||
.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
|
||||
.v2.mac_context_id =
|
||||
.v3.v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC),
|
||||
.v3.v2.mac_context_id =
|
||||
cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id),
|
||||
.v2.pwr_restriction = cpu_to_le16(8 * tx_power),
|
||||
.v3.v2.pwr_restriction = cpu_to_le16(8 * tx_power),
|
||||
};
|
||||
int len = sizeof(cmd);
|
||||
|
||||
if (tx_power == IWL_DEFAULT_MAX_TX_POWER)
|
||||
cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
|
||||
cmd.v3.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER);
|
||||
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK))
|
||||
len = sizeof(cmd.v3);
|
||||
if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN))
|
||||
len = sizeof(cmd.v2);
|
||||
len = sizeof(cmd.v3.v2);
|
||||
|
||||
return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd);
|
||||
}
|
||||
|
@ -2360,7 +2382,7 @@ static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
|
||||
return;
|
||||
|
||||
if (vif->p2p && !iwl_mvm_is_p2p_standalone_uapsd_supported(mvm)) {
|
||||
if (vif->p2p && !iwl_mvm_is_p2p_scm_uapsd_supported(mvm)) {
|
||||
vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
|
||||
return;
|
||||
}
|
||||
|
@ -2719,6 +2741,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
|
@ -2780,7 +2804,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
sta && iwl_mvm_has_new_rx_api(mvm) &&
|
||||
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
|
||||
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP ||
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
|
||||
struct ieee80211_key_seq seq;
|
||||
int tid, q;
|
||||
|
||||
|
@ -2834,7 +2859,8 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
|||
if (sta && iwl_mvm_has_new_rx_api(mvm) &&
|
||||
key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&
|
||||
(key->cipher == WLAN_CIPHER_SUITE_CCMP ||
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP)) {
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP ||
|
||||
key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
ptk_pn = rcu_dereference_protected(
|
||||
mvmsta->ptk_pn[keyidx],
|
||||
|
@ -3687,6 +3713,13 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* we still didn't unblock tx. prevent new CS meanwhile */
|
||||
if (rcu_dereference_protected(mvm->csa_tx_blocked_vif,
|
||||
lockdep_is_held(&mvm->mutex))) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(mvm->csa_vif, vif);
|
||||
|
||||
if (WARN_ONCE(mvmvif->csa_countdown,
|
||||
|
@ -3695,6 +3728,8 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
mvmvif->csa_target_freq = chsw->chandef.chan->center_freq;
|
||||
|
||||
break;
|
||||
case NL80211_IFTYPE_STATION:
|
||||
if (mvmvif->lqm_active)
|
||||
|
@ -3898,6 +3933,11 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
|
|||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
if (mvmsta->avg_energy) {
|
||||
sinfo->signal_avg = mvmsta->avg_energy;
|
||||
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
|
||||
}
|
||||
|
||||
if (!fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS))
|
||||
return;
|
||||
|
|
|
@ -452,6 +452,7 @@ struct iwl_mvm_vif {
|
|||
/* Indicates that CSA countdown may be started */
|
||||
bool csa_countdown;
|
||||
bool csa_failed;
|
||||
u16 csa_target_freq;
|
||||
|
||||
/* TCP Checksum Offload */
|
||||
netdev_features_t features;
|
||||
|
@ -686,13 +687,28 @@ struct iwl_mvm_baid_data {
|
|||
* This is the state of a queue that has been fully configured (including
|
||||
* SCD pointers, etc), has a specific RA/TID assigned to it, and can be
|
||||
* used to send traffic.
|
||||
* @IWL_MVM_QUEUE_SHARED: queue is shared, or in a process of becoming shared
|
||||
* This is a state in which a single queue serves more than one TID, all of
|
||||
* which are not aggregated. Note that the queue is only associated to one
|
||||
* RA.
|
||||
* @IWL_MVM_QUEUE_INACTIVE: queue is allocated but no traffic on it
|
||||
* This is a state of a queue that has had traffic on it, but during the
|
||||
* last %IWL_MVM_DQA_QUEUE_TIMEOUT time period there has been no traffic on
|
||||
* it. In this state, when a new queue is needed to be allocated but no
|
||||
* such free queue exists, an inactive queue might be freed and given to
|
||||
* the new RA/TID.
|
||||
*/
|
||||
enum iwl_mvm_queue_status {
|
||||
IWL_MVM_QUEUE_FREE,
|
||||
IWL_MVM_QUEUE_RESERVED,
|
||||
IWL_MVM_QUEUE_READY,
|
||||
IWL_MVM_QUEUE_SHARED,
|
||||
IWL_MVM_QUEUE_INACTIVE,
|
||||
};
|
||||
|
||||
#define IWL_MVM_DQA_QUEUE_TIMEOUT (5 * HZ)
|
||||
#define IWL_MVM_NUM_CIPHERS 8
|
||||
|
||||
struct iwl_mvm {
|
||||
/* for logger access */
|
||||
struct device *dev;
|
||||
|
@ -731,6 +747,7 @@ struct iwl_mvm {
|
|||
struct iwl_sf_region sf_space;
|
||||
|
||||
u32 ampdu_ref;
|
||||
bool ampdu_toggle;
|
||||
|
||||
struct iwl_notif_wait_data notif_wait;
|
||||
|
||||
|
@ -748,11 +765,16 @@ struct iwl_mvm {
|
|||
u32 hw_queue_to_mac80211;
|
||||
u8 hw_queue_refcount;
|
||||
u8 ra_sta_id; /* The RA this queue is mapped to, if exists */
|
||||
bool reserved; /* Is this the TXQ reserved for a STA */
|
||||
u8 mac80211_ac; /* The mac80211 AC this queue is mapped to */
|
||||
u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
|
||||
/* Timestamp for inactivation per TID of this queue */
|
||||
unsigned long last_frame_time[IWL_MAX_TID_COUNT + 1];
|
||||
enum iwl_mvm_queue_status status;
|
||||
} queue_info[IWL_MAX_HW_QUEUES];
|
||||
spinlock_t queue_info_lock; /* For syncing queue mgmt operations */
|
||||
struct work_struct add_stream_wk; /* To add streams to queues */
|
||||
|
||||
atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
|
||||
|
||||
const char *nvm_file_name;
|
||||
|
@ -787,7 +809,7 @@ struct iwl_mvm {
|
|||
struct iwl_mcast_filter_cmd *mcast_filter_cmd;
|
||||
enum iwl_mvm_scan_type scan_type;
|
||||
enum iwl_mvm_sched_scan_pass_all_states sched_scan_pass_all;
|
||||
struct timer_list scan_timer;
|
||||
struct delayed_work scan_timeout_dwork;
|
||||
|
||||
/* max number of simultaneous scans the FW supports */
|
||||
unsigned int max_scans;
|
||||
|
@ -910,11 +932,6 @@ struct iwl_mvm {
|
|||
wait_queue_head_t d0i3_exit_waitq;
|
||||
|
||||
/* BT-Coex */
|
||||
u8 bt_ack_kill_msk[NUM_PHY_CTX];
|
||||
u8 bt_cts_kill_msk[NUM_PHY_CTX];
|
||||
|
||||
struct iwl_bt_coex_profile_notif_old last_bt_notif_old;
|
||||
struct iwl_bt_coex_ci_cmd_old last_bt_ci_cmd_old;
|
||||
struct iwl_bt_coex_profile_notif last_bt_notif;
|
||||
struct iwl_bt_coex_ci_cmd last_bt_ci_cmd;
|
||||
|
||||
|
@ -994,7 +1011,8 @@ struct iwl_mvm {
|
|||
|
||||
struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
|
||||
|
||||
u32 ciphers[6];
|
||||
u32 ciphers[IWL_MVM_NUM_CIPHERS];
|
||||
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
|
||||
struct iwl_mvm_tof_data tof_data;
|
||||
|
||||
struct ieee80211_vif *nan_vif;
|
||||
|
@ -1006,6 +1024,8 @@ struct iwl_mvm {
|
|||
* clients.
|
||||
*/
|
||||
bool drop_bcn_ap_mode;
|
||||
|
||||
struct delayed_work cs_tx_unblock_dwork;
|
||||
};
|
||||
|
||||
/* Extract MVM priv from op_mode and _hw */
|
||||
|
@ -1158,10 +1178,10 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
|
|||
}
|
||||
|
||||
static inline
|
||||
bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm)
|
||||
bool iwl_mvm_is_p2p_scm_uapsd_supported(struct iwl_mvm *mvm)
|
||||
{
|
||||
return fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) &&
|
||||
IWL_UCODE_TLV_CAPA_P2P_SCM_UAPSD) &&
|
||||
!(iwlwifi_mod_params.uapsd_disable &
|
||||
IWL_DISABLE_UAPSD_P2P_CLIENT);
|
||||
}
|
||||
|
@ -1321,7 +1341,6 @@ bool iwl_mvm_bcast_filter_build_cmd(struct iwl_mvm *mvm,
|
|||
void iwl_mvm_rx_rx_phy_cmd(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
|
||||
void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb);
|
||||
void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
|
||||
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
struct iwl_rx_cmd_buffer *rxb, int queue);
|
||||
void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
|
||||
|
@ -1381,6 +1400,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
|
|||
struct ieee80211_vif *vif);
|
||||
unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *exclude_vif);
|
||||
void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb);
|
||||
/* Bindings */
|
||||
int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
|
@ -1397,7 +1418,7 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm);
|
|||
int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify);
|
||||
int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_scan_timeout(unsigned long data);
|
||||
void iwl_mvm_scan_timeout_wk(struct work_struct *work);
|
||||
|
||||
/* Scheduled scan */
|
||||
void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
|
||||
|
@ -1613,7 +1634,7 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
*/
|
||||
void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
||||
u8 tid, u8 flags);
|
||||
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq);
|
||||
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq);
|
||||
|
||||
/* Return a bitmask with all the hw supported queues, except for the
|
||||
* command queue, which can't be flushed.
|
||||
|
@ -1720,6 +1741,8 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
|
|||
void iwl_mvm_reorder_timer_expired(unsigned long data);
|
||||
struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
|
||||
|
||||
void iwl_mvm_inactivity_check(struct iwl_mvm *mvm);
|
||||
|
||||
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
|
||||
unsigned int iwl_mvm_get_wd_timeout(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
*****************************************************************************/
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-csr.h"
|
||||
|
@ -667,8 +666,7 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
.mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]),
|
||||
.source_id = (u8)src_id,
|
||||
};
|
||||
struct iwl_mcc_update_resp *mcc_resp, *resp_cp = NULL;
|
||||
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = NULL;
|
||||
struct iwl_mcc_update_resp *resp_cp;
|
||||
struct iwl_rx_packet *pkt;
|
||||
struct iwl_host_cmd cmd = {
|
||||
.id = MCC_UPDATE_CMD,
|
||||
|
@ -701,34 +699,36 @@ iwl_mvm_update_mcc(struct iwl_mvm *mvm, const char *alpha2,
|
|||
|
||||
/* Extract MCC response */
|
||||
if (resp_v2) {
|
||||
mcc_resp = (void *)pkt->data;
|
||||
struct iwl_mcc_update_resp *mcc_resp = (void *)pkt->data;
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp->n_channels);
|
||||
resp_len = sizeof(struct iwl_mcc_update_resp) +
|
||||
n_channels * sizeof(__le32);
|
||||
resp_cp = kmemdup(mcc_resp, resp_len, GFP_KERNEL);
|
||||
} else {
|
||||
mcc_resp_v1 = (void *)pkt->data;
|
||||
struct iwl_mcc_update_resp_v1 *mcc_resp_v1 = (void *)pkt->data;
|
||||
|
||||
n_channels = __le32_to_cpu(mcc_resp_v1->n_channels);
|
||||
resp_len = sizeof(struct iwl_mcc_update_resp) +
|
||||
n_channels * sizeof(__le32);
|
||||
resp_cp = kzalloc(resp_len, GFP_KERNEL);
|
||||
|
||||
if (resp_cp) {
|
||||
resp_cp->status = mcc_resp_v1->status;
|
||||
resp_cp->mcc = mcc_resp_v1->mcc;
|
||||
resp_cp->cap = mcc_resp_v1->cap;
|
||||
resp_cp->source_id = mcc_resp_v1->source_id;
|
||||
resp_cp->n_channels = mcc_resp_v1->n_channels;
|
||||
memcpy(resp_cp->channels, mcc_resp_v1->channels,
|
||||
n_channels * sizeof(__le32));
|
||||
}
|
||||
}
|
||||
|
||||
resp_len = sizeof(struct iwl_mcc_update_resp) + n_channels *
|
||||
sizeof(__le32);
|
||||
|
||||
resp_cp = kzalloc(resp_len, GFP_KERNEL);
|
||||
if (!resp_cp) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp_v2) {
|
||||
memcpy(resp_cp, mcc_resp, resp_len);
|
||||
} else {
|
||||
resp_cp->status = mcc_resp_v1->status;
|
||||
resp_cp->mcc = mcc_resp_v1->mcc;
|
||||
resp_cp->cap = mcc_resp_v1->cap;
|
||||
resp_cp->source_id = mcc_resp_v1->source_id;
|
||||
resp_cp->n_channels = mcc_resp_v1->n_channels;
|
||||
memcpy(resp_cp->channels, mcc_resp_v1->channels,
|
||||
n_channels * sizeof(__le32));
|
||||
}
|
||||
|
||||
status = le32_to_cpu(resp_cp->status);
|
||||
|
||||
mcc = le16_to_cpu(resp_cp->mcc);
|
||||
|
@ -802,9 +802,8 @@ static int iwl_mvm_get_bios_mcc(struct iwl_mvm *mvm, char *mcc)
|
|||
struct acpi_buffer wrdd = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
acpi_status status;
|
||||
u32 mcc_val;
|
||||
struct pci_dev *pdev = to_pci_dev(mvm->dev);
|
||||
|
||||
root_handle = ACPI_HANDLE(&pdev->dev);
|
||||
root_handle = ACPI_HANDLE(mvm->dev);
|
||||
if (!root_handle) {
|
||||
IWL_DEBUG_LAR(mvm,
|
||||
"Could not retrieve root port ACPI handle\n");
|
||||
|
|
|
@ -431,6 +431,7 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = {
|
|||
static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = {
|
||||
HCMD_NAME(LINK_QUALITY_MEASUREMENT_CMD),
|
||||
HCMD_NAME(LINK_QUALITY_MEASUREMENT_COMPLETE_NOTIF),
|
||||
HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF),
|
||||
};
|
||||
|
||||
/* Please keep this array *SORTED* by hex value.
|
||||
|
@ -494,6 +495,29 @@ static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg)
|
|||
|
||||
static void iwl_mvm_fw_error_dump_wk(struct work_struct *work);
|
||||
|
||||
static void iwl_mvm_tx_unblock_dwork(struct work_struct *work)
|
||||
{
|
||||
struct iwl_mvm *mvm =
|
||||
container_of(work, struct iwl_mvm, cs_tx_unblock_dwork.work);
|
||||
struct ieee80211_vif *tx_blocked_vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
tx_blocked_vif =
|
||||
rcu_dereference_protected(mvm->csa_tx_blocked_vif,
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
|
||||
if (!tx_blocked_vif)
|
||||
goto unlock;
|
||||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
||||
iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, false);
|
||||
RCU_INIT_POINTER(mvm->csa_tx_blocked_vif, NULL);
|
||||
unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static struct iwl_op_mode *
|
||||
iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
||||
const struct iwl_fw *fw, struct dentry *dbgfs_dir)
|
||||
|
@ -553,18 +577,21 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
mvm->restart_fw = iwlwifi_mod_params.restart_fw ? -1 : 0;
|
||||
|
||||
mvm->aux_queue = 15;
|
||||
if (!iwl_mvm_is_dqa_supported(mvm)) {
|
||||
mvm->first_agg_queue = 16;
|
||||
mvm->last_agg_queue = mvm->cfg->base_params->num_of_queues - 1;
|
||||
|
||||
if (mvm->cfg->base_params->num_of_queues == 16) {
|
||||
mvm->aux_queue = 11;
|
||||
mvm->first_agg_queue = 12;
|
||||
} else {
|
||||
mvm->aux_queue = 15;
|
||||
mvm->first_agg_queue = 16;
|
||||
}
|
||||
} else {
|
||||
mvm->aux_queue = IWL_MVM_DQA_AUX_QUEUE;
|
||||
mvm->first_agg_queue = IWL_MVM_DQA_MIN_DATA_QUEUE;
|
||||
mvm->last_agg_queue = IWL_MVM_DQA_MAX_DATA_QUEUE;
|
||||
}
|
||||
if (mvm->cfg->base_params->num_of_queues == 16) {
|
||||
mvm->aux_queue = 11;
|
||||
mvm->first_agg_queue = 12;
|
||||
}
|
||||
mvm->sf_state = SF_UNINIT;
|
||||
mvm->cur_ucode = IWL_UCODE_INIT;
|
||||
mvm->drop_bcn_ap_mode = true;
|
||||
|
@ -584,6 +611,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
|
||||
INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk);
|
||||
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
|
||||
INIT_DELAYED_WORK(&mvm->scan_timeout_dwork, iwl_mvm_scan_timeout_wk);
|
||||
INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk);
|
||||
|
||||
spin_lock_init(&mvm->d0i3_tx_lock);
|
||||
|
@ -595,6 +623,8 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev);
|
||||
|
||||
INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork);
|
||||
|
||||
/*
|
||||
* Populate the state variables that the transport layer needs
|
||||
* to know about.
|
||||
|
@ -603,6 +633,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
|
||||
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||
switch (iwlwifi_mod_params.amsdu_size) {
|
||||
case IWL_AMSDU_DEF:
|
||||
case IWL_AMSDU_4K:
|
||||
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
|
||||
break;
|
||||
|
@ -617,6 +648,10 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
iwlwifi_mod_params.amsdu_size);
|
||||
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
|
||||
}
|
||||
|
||||
/* the hardware splits the A-MSDU */
|
||||
if (mvm->cfg->mq_rx_supported)
|
||||
trans_cfg.rx_buf_size = IWL_AMSDU_4K;
|
||||
trans_cfg.wide_cmd_header = fw_has_api(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_API_WIDE_CMD_HDR);
|
||||
|
||||
|
@ -633,6 +668,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
|
||||
trans_cfg.scd_set_active = true;
|
||||
|
||||
trans_cfg.cb_data_offs = offsetof(struct ieee80211_tx_info,
|
||||
driver_data[2]);
|
||||
|
||||
trans_cfg.sdio_adma_addr = fw->sdio_adma_addr;
|
||||
trans_cfg.sw_csum_tx = IWL_MVM_SW_TX_CSUM_OFFLOAD;
|
||||
|
||||
|
@ -735,9 +773,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
|
|||
|
||||
iwl_mvm_tof_init(mvm);
|
||||
|
||||
setup_timer(&mvm->scan_timer, iwl_mvm_scan_timeout,
|
||||
(unsigned long)mvm);
|
||||
|
||||
return op_mode;
|
||||
|
||||
out_unregister:
|
||||
|
@ -791,8 +826,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
|
|||
|
||||
iwl_mvm_tof_clean(mvm);
|
||||
|
||||
del_timer_sync(&mvm->scan_timer);
|
||||
|
||||
mutex_destroy(&mvm->mutex);
|
||||
mutex_destroy(&mvm->d0i3_suspend_mutex);
|
||||
|
||||
|
@ -936,8 +969,6 @@ static void iwl_mvm_rx(struct iwl_op_mode *op_mode,
|
|||
|
||||
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
|
||||
iwl_mvm_rx_rx_mpdu(mvm, napi, rxb);
|
||||
else if (pkt->hdr.cmd == FRAME_RELEASE)
|
||||
iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
|
||||
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
|
||||
iwl_mvm_rx_rx_phy_cmd(mvm, rxb);
|
||||
else
|
||||
|
@ -953,11 +984,11 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
|
|||
|
||||
if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD))
|
||||
iwl_mvm_rx_mpdu_mq(mvm, napi, rxb, 0);
|
||||
else if (pkt->hdr.cmd == REPLY_RX_PHY_CMD)
|
||||
iwl_mvm_rx_phy_cmd_mq(mvm, rxb);
|
||||
else if (unlikely(pkt->hdr.group_id == DATA_PATH_GROUP &&
|
||||
pkt->hdr.cmd == RX_QUEUES_NOTIFICATION))
|
||||
iwl_mvm_rx_queue_notif(mvm, rxb, 0);
|
||||
else if (pkt->hdr.cmd == FRAME_RELEASE)
|
||||
iwl_mvm_rx_frame_release(mvm, napi, rxb, 0);
|
||||
else
|
||||
iwl_mvm_rx_common(mvm, rxb, pkt);
|
||||
}
|
||||
|
|
|
@ -308,7 +308,7 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
|
|||
/* Allow U-APSD only if p2p is stand alone */
|
||||
bool is_p2p_standalone = true;
|
||||
|
||||
if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm))
|
||||
if (!iwl_mvm_is_p2p_scm_uapsd_supported(mvm))
|
||||
return false;
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
|
||||
|
|
|
@ -211,6 +211,9 @@ static bool rs_sgi_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
if (is_ht80(rate) && (vht_cap->cap &
|
||||
IEEE80211_VHT_CAP_SHORT_GI_80))
|
||||
return true;
|
||||
if (is_ht160(rate) && (vht_cap->cap &
|
||||
IEEE80211_VHT_CAP_SHORT_GI_160))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -399,7 +402,7 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
|
|||
static void rs_rate_scale_perform(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
int tid);
|
||||
int tid, bool ndp);
|
||||
static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
|
@ -445,6 +448,13 @@ static const u16 expected_tpt_siso_80MHz[4][IWL_RATE_COUNT] = {
|
|||
{0, 0, 0, 0, 241, 0, 475, 701, 921, 1343, 1741, 1931, 2117, 2468, 2691},
|
||||
};
|
||||
|
||||
static const u16 expected_tpt_siso_160MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 191, 0, 244, 288, 298, 308, 313, 318, 323, 328, 330},
|
||||
{0, 0, 0, 0, 200, 0, 251, 293, 302, 312, 317, 322, 327, 332, 334},
|
||||
{0, 0, 0, 0, 439, 0, 875, 1307, 1736, 2584, 3419, 3831, 4240, 5049, 5581},
|
||||
{0, 0, 0, 0, 488, 0, 972, 1451, 1925, 2864, 3785, 4240, 4691, 5581, 6165},
|
||||
};
|
||||
|
||||
static const u16 expected_tpt_mimo2_20MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 74, 0, 123, 155, 179, 213, 235, 243, 250, 261, 0},
|
||||
{0, 0, 0, 0, 81, 0, 131, 164, 187, 221, 242, 250, 256, 267, 0},
|
||||
|
@ -466,6 +476,13 @@ static const u16 expected_tpt_mimo2_80MHz[4][IWL_RATE_COUNT] = {
|
|||
{0, 0, 0, 0, 474, 0, 920, 1338, 1732, 2464, 3116, 3418, 3705, 4225, 4545},
|
||||
};
|
||||
|
||||
static const u16 expected_tpt_mimo2_160MHz[4][IWL_RATE_COUNT] = {
|
||||
{0, 0, 0, 0, 240, 0, 278, 308, 313, 319, 322, 324, 328, 330, 334},
|
||||
{0, 0, 0, 0, 247, 0, 282, 310, 315, 320, 323, 325, 329, 332, 338},
|
||||
{0, 0, 0, 0, 875, 0, 1735, 2582, 3414, 5043, 6619, 7389, 8147, 9629, 10592},
|
||||
{0, 0, 0, 0, 971, 0, 1925, 2861, 3779, 5574, 7304, 8147, 8976, 10592, 11640},
|
||||
};
|
||||
|
||||
/* mbps, mcs */
|
||||
static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
|
||||
{ "1", "BPSK DSSS"},
|
||||
|
@ -901,7 +918,6 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
|
|||
}
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_160);
|
||||
WARN_ON_ONCE(rate->bw == RATE_MCS_CHAN_WIDTH_80 &&
|
||||
!is_vht(rate));
|
||||
|
||||
|
@ -1161,7 +1177,7 @@ static u8 rs_get_tid(struct ieee80211_hdr *hdr)
|
|||
}
|
||||
|
||||
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, struct ieee80211_tx_info *info)
|
||||
int tid, struct ieee80211_tx_info *info, bool ndp)
|
||||
{
|
||||
int legacy_success;
|
||||
int retries;
|
||||
|
@ -1384,7 +1400,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
done:
|
||||
/* See if there's a better rate or modulation mode to try. */
|
||||
if (sta->supp_rates[info->band])
|
||||
rs_rate_scale_perform(mvm, sta, lq_sta, tid);
|
||||
rs_rate_scale_perform(mvm, sta, lq_sta, tid, ndp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1407,7 +1423,8 @@ static void rs_mac80211_tx_status(void *mvm_r,
|
|||
info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
return;
|
||||
|
||||
iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info);
|
||||
iwl_mvm_rs_tx_status(mvm, sta, rs_get_tid(hdr), info,
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1494,6 +1511,9 @@ static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
ht_tbl_pointer = expected_tpt_siso_80MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
ht_tbl_pointer = expected_tpt_siso_160MHz;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
@ -1508,6 +1528,9 @@ static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta,
|
|||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
ht_tbl_pointer = expected_tpt_mimo2_80MHz;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
ht_tbl_pointer = expected_tpt_mimo2_160MHz;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
@ -1582,12 +1605,17 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
|
|||
|
||||
static u32 rs_bw_from_sta_bw(struct ieee80211_sta *sta)
|
||||
{
|
||||
if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
|
||||
switch (sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
return RATE_MCS_CHAN_WIDTH_160;
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
return RATE_MCS_CHAN_WIDTH_80;
|
||||
else if (sta->bandwidth >= IEEE80211_STA_RX_BW_40)
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
return RATE_MCS_CHAN_WIDTH_40;
|
||||
|
||||
return RATE_MCS_CHAN_WIDTH_20;
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
default:
|
||||
return RATE_MCS_CHAN_WIDTH_20;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2213,7 +2241,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm,
|
|||
static void rs_rate_scale_perform(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta,
|
||||
struct iwl_lq_sta *lq_sta,
|
||||
int tid)
|
||||
int tid, bool ndp)
|
||||
{
|
||||
int low = IWL_RATE_INVALID;
|
||||
int high = IWL_RATE_INVALID;
|
||||
|
@ -2512,7 +2540,7 @@ lq_update:
|
|||
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
|
||||
(tid != IWL_MAX_TID_COUNT)) {
|
||||
tid_data = &sta_priv->tid_data[tid];
|
||||
if (tid_data->state == IWL_AGG_OFF) {
|
||||
if (tid_data->state == IWL_AGG_OFF && !ndp) {
|
||||
IWL_DEBUG_RATE(mvm,
|
||||
"try to aggregate tid %d\n",
|
||||
tid);
|
||||
|
@ -2565,6 +2593,9 @@ static const struct rs_init_rate_info rs_optimal_rates_ht[] = {
|
|||
{ S8_MIN, IWL_RATE_MCS_0_INDEX},
|
||||
};
|
||||
|
||||
/* MCS index 9 is not valid for 20MHz VHT channel width,
|
||||
* but is ok for 40, 80 and 160MHz channels.
|
||||
*/
|
||||
static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = {
|
||||
{ -60, IWL_RATE_MCS_8_INDEX },
|
||||
{ -64, IWL_RATE_MCS_7_INDEX },
|
||||
|
@ -2577,7 +2608,7 @@ static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = {
|
|||
{ S8_MIN, IWL_RATE_MCS_0_INDEX},
|
||||
};
|
||||
|
||||
static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = {
|
||||
static const struct rs_init_rate_info rs_optimal_rates_vht[] = {
|
||||
{ -60, IWL_RATE_MCS_9_INDEX },
|
||||
{ -64, IWL_RATE_MCS_8_INDEX },
|
||||
{ -68, IWL_RATE_MCS_7_INDEX },
|
||||
|
@ -2640,9 +2671,9 @@ static void rs_init_optimal_rate(struct iwl_mvm *mvm,
|
|||
lq_sta->optimal_nentries =
|
||||
ARRAY_SIZE(rs_optimal_rates_vht_20mhz);
|
||||
} else {
|
||||
lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz;
|
||||
lq_sta->optimal_rates = rs_optimal_rates_vht;
|
||||
lq_sta->optimal_nentries =
|
||||
ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz);
|
||||
ARRAY_SIZE(rs_optimal_rates_vht);
|
||||
}
|
||||
} else if (is_ht(rate)) {
|
||||
lq_sta->optimal_rates = rs_optimal_rates_ht;
|
||||
|
@ -2734,23 +2765,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
|
|||
*/
|
||||
if (sta->vht_cap.vht_supported &&
|
||||
best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
|
||||
if (sta->bandwidth >= IEEE80211_STA_RX_BW_40) {
|
||||
initial_rates = rs_optimal_rates_vht_40_80mhz;
|
||||
nentries = ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz);
|
||||
if (sta->bandwidth >= IEEE80211_STA_RX_BW_80)
|
||||
rate->bw = RATE_MCS_CHAN_WIDTH_80;
|
||||
else
|
||||
rate->bw = RATE_MCS_CHAN_WIDTH_40;
|
||||
} else if (sta->bandwidth == IEEE80211_STA_RX_BW_20) {
|
||||
switch (sta->bandwidth) {
|
||||
case IEEE80211_STA_RX_BW_160:
|
||||
case IEEE80211_STA_RX_BW_80:
|
||||
case IEEE80211_STA_RX_BW_40:
|
||||
initial_rates = rs_optimal_rates_vht;
|
||||
nentries = ARRAY_SIZE(rs_optimal_rates_vht);
|
||||
break;
|
||||
case IEEE80211_STA_RX_BW_20:
|
||||
initial_rates = rs_optimal_rates_vht_20mhz;
|
||||
nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz);
|
||||
rate->bw = RATE_MCS_CHAN_WIDTH_20;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
IWL_ERR(mvm, "Invalid BW %d\n", sta->bandwidth);
|
||||
goto out;
|
||||
}
|
||||
|
||||
active_rate = lq_sta->active_siso_rate;
|
||||
rate->type = LQ_VHT_SISO;
|
||||
rate->bw = rs_bw_from_sta_bw(sta);
|
||||
} else if (sta->ht_cap.ht_supported &&
|
||||
best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
|
||||
initial_rates = rs_optimal_rates_ht;
|
||||
|
@ -3057,6 +3090,9 @@ void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
|
|||
case RATE_MCS_CHAN_WIDTH_80:
|
||||
mvm->drv_rx_stats.bw_80_frames++;
|
||||
break;
|
||||
case RATE_MCS_CHAN_WIDTH_160:
|
||||
mvm->drv_rx_stats.bw_160_frames++;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "bad BW. rate 0x%x", rate);
|
||||
}
|
||||
|
@ -3705,7 +3741,8 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
|
|||
desc += sprintf(buff + desc, " %s",
|
||||
(is_ht20(rate)) ? "20MHz" :
|
||||
(is_ht40(rate)) ? "40MHz" :
|
||||
(is_ht80(rate)) ? "80Mhz" : "BAD BW");
|
||||
(is_ht80(rate)) ? "80MHz" :
|
||||
(is_ht160(rate)) ? "160MHz" : "BAD BW");
|
||||
desc += sprintf(buff + desc, " %s %s %s %s\n",
|
||||
(rate->sgi) ? "SGI" : "NGI",
|
||||
(rate->ldpc) ? "LDPC" : "BCC",
|
||||
|
@ -3787,9 +3824,10 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
|
|||
lq_sta->active_tbl == i ? "*" : "x",
|
||||
rate->type,
|
||||
rate->sgi,
|
||||
is_ht20(rate) ? "20Mhz" :
|
||||
is_ht40(rate) ? "40Mhz" :
|
||||
is_ht80(rate) ? "80Mhz" : "ERR",
|
||||
is_ht20(rate) ? "20MHz" :
|
||||
is_ht40(rate) ? "40MHz" :
|
||||
is_ht80(rate) ? "80MHz" :
|
||||
is_ht160(rate) ? "160MHz" : "ERR",
|
||||
rate->index);
|
||||
for (j = 0; j < IWL_RATE_COUNT; j++) {
|
||||
desc += sprintf(buff+desc,
|
||||
|
|
|
@ -205,6 +205,7 @@ struct rs_rate {
|
|||
#define is_ht20(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_20)
|
||||
#define is_ht40(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_40)
|
||||
#define is_ht80(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_80)
|
||||
#define is_ht160(rate) ((rate)->bw == RATE_MCS_CHAN_WIDTH_160)
|
||||
|
||||
#define IWL_MAX_MCS_DISPLAY_SIZE 12
|
||||
|
||||
|
@ -362,7 +363,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
|
||||
/* Notify RS about Tx status */
|
||||
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, struct ieee80211_tx_info *info);
|
||||
int tid, struct ieee80211_tx_info *info, bool ndp);
|
||||
|
||||
/**
|
||||
* iwl_rate_control_register - Register the rate control algorithm callbacks
|
||||
|
|
|
@ -101,7 +101,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
|
|||
struct napi_struct *napi,
|
||||
struct sk_buff *skb,
|
||||
struct ieee80211_hdr *hdr, u16 len,
|
||||
u32 ampdu_status, u8 crypt_len,
|
||||
u8 crypt_len,
|
||||
struct iwl_rx_cmd_buffer *rxb)
|
||||
{
|
||||
unsigned int hdrlen, fraglen;
|
||||
|
@ -268,7 +268,6 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
struct ieee80211_sta *sta = NULL;
|
||||
struct sk_buff *skb;
|
||||
u32 len;
|
||||
u32 ampdu_status;
|
||||
u32 rate_n_flags;
|
||||
u32 rx_pkt_status;
|
||||
u8 crypt_len = 0;
|
||||
|
@ -354,13 +353,22 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
if (sta) {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct ieee80211_vif *tx_blocked_vif =
|
||||
rcu_dereference(mvm->csa_tx_blocked_vif);
|
||||
|
||||
/* We have tx blocked stations (with CS bit). If we heard
|
||||
* frames from a blocked station on a new channel we can
|
||||
* TX to it again.
|
||||
*/
|
||||
if (unlikely(mvm->csa_tx_block_bcn_timeout))
|
||||
iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
|
||||
if (unlikely(tx_blocked_vif) &&
|
||||
mvmsta->vif == tx_blocked_vif) {
|
||||
struct iwl_mvm_vif *mvmvif =
|
||||
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
||||
|
||||
if (mvmvif->csa_target_freq == rx_status->freq)
|
||||
iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
|
||||
false);
|
||||
}
|
||||
|
||||
rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
|
||||
|
||||
|
@ -471,7 +479,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
iwl_mvm_ref(mvm, IWL_MVM_REF_RX);
|
||||
|
||||
iwl_mvm_pass_packet_to_mac80211(mvm, sta, napi, skb, hdr, len,
|
||||
ampdu_status, crypt_len, rxb);
|
||||
crypt_len, rxb);
|
||||
|
||||
if (take_ref)
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_RX);
|
||||
|
@ -490,6 +498,7 @@ struct iwl_mvm_stat_data {
|
|||
__le32 mac_id;
|
||||
u8 beacon_filter_average_energy;
|
||||
struct mvm_statistics_general_v8 *general;
|
||||
struct mvm_statistics_load *load;
|
||||
};
|
||||
|
||||
static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
|
||||
|
@ -606,13 +615,15 @@ iwl_mvm_rx_stats_check_trigger(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt)
|
|||
void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_notif_statistics_v10 *stats = (void *)&pkt->data;
|
||||
struct iwl_notif_statistics_v11 *stats = (void *)&pkt->data;
|
||||
struct iwl_mvm_stat_data data = {
|
||||
.mvm = mvm,
|
||||
};
|
||||
int expected_size = iwl_mvm_has_new_rx_api(mvm) ? sizeof(*stats) :
|
||||
sizeof(struct iwl_notif_statistics_v10);
|
||||
u32 temperature;
|
||||
|
||||
if (iwl_rx_packet_payload_len(pkt) != sizeof(*stats))
|
||||
if (iwl_rx_packet_payload_len(pkt) != expected_size)
|
||||
goto invalid;
|
||||
|
||||
temperature = le32_to_cpu(stats->general.radio_temperature);
|
||||
|
@ -630,6 +641,25 @@ void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
|
|||
le64_to_cpu(stats->general.on_time_scan);
|
||||
|
||||
data.general = &stats->general;
|
||||
if (iwl_mvm_has_new_rx_api(mvm)) {
|
||||
int i;
|
||||
|
||||
data.load = &stats->load_stats;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
|
||||
struct iwl_mvm_sta *sta;
|
||||
|
||||
if (!data.load->avg_energy[i])
|
||||
continue;
|
||||
|
||||
sta = iwl_mvm_sta_from_staid_rcu(mvm, i);
|
||||
if (!sta)
|
||||
continue;
|
||||
sta->avg_energy = data.load->avg_energy[i];
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
iwl_mvm_rx_stats_check_trigger(mvm, pkt);
|
||||
|
||||
|
|
|
@ -65,19 +65,6 @@
|
|||
#include "fw-api.h"
|
||||
#include "fw-dbg.h"
|
||||
|
||||
void iwl_mvm_rx_phy_cmd_mq(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
||||
{
|
||||
mvm->ampdu_ref++;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
if (mvm->last_phy_info.phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
|
||||
spin_lock(&mvm->drv_stats_lock);
|
||||
mvm->drv_rx_stats.ampdu_count++;
|
||||
spin_unlock(&mvm->drv_stats_lock);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
|
||||
int queue, struct ieee80211_sta *sta)
|
||||
{
|
||||
|
@ -489,6 +476,9 @@ void iwl_mvm_reorder_timer_expired(unsigned long data)
|
|||
rcu_read_lock();
|
||||
sta = rcu_dereference(buf->mvm->fw_id_to_mac_id[buf->sta_id]);
|
||||
/* SN is set to the last expired frame + 1 */
|
||||
IWL_DEBUG_HT(buf->mvm,
|
||||
"Releasing expired frames for sta %u, sn %d\n",
|
||||
buf->sta_id, sn);
|
||||
iwl_mvm_release_frames(buf->mvm, sta, NULL, buf, sn);
|
||||
rcu_read_unlock();
|
||||
} else if (buf->num_stored) {
|
||||
|
@ -587,6 +577,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|||
struct sk_buff *tail;
|
||||
u32 reorder = le32_to_cpu(desc->reorder_data);
|
||||
bool amsdu = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU;
|
||||
bool last_subframe =
|
||||
desc->amsdu_info & IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
|
||||
u8 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
u8 sub_frame_idx = desc->amsdu_info &
|
||||
IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
|
||||
|
@ -653,7 +645,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|||
/* release immediately if allowed by nssn and no stored frames */
|
||||
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
|
||||
if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
|
||||
buffer->buf_size))
|
||||
buffer->buf_size) &&
|
||||
(!amsdu || last_subframe))
|
||||
buffer->head_sn = nssn;
|
||||
/* No need to update AMSDU last SN - we are moving the head */
|
||||
spin_unlock_bh(&buffer->lock);
|
||||
|
@ -687,7 +680,20 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
|
|||
buffer->last_sub_index = sub_frame_idx;
|
||||
}
|
||||
|
||||
iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
|
||||
/*
|
||||
* We cannot trust NSSN for AMSDU sub-frames that are not the last.
|
||||
* The reason is that NSSN advances on the first sub-frame, and may
|
||||
* cause the reorder buffer to advance before all the sub-frames arrive.
|
||||
* Example: reorder buffer contains SN 0 & 2, and we receive AMSDU with
|
||||
* SN 1. NSSN for first sub frame will be 3 with the result of driver
|
||||
* releasing SN 0,1, 2. When sub-frame 1 arrives - reorder buffer is
|
||||
* already ahead and it will be dropped.
|
||||
* If the last sub-frame is not on this queue - we will get frame
|
||||
* release notification with up to date NSSN.
|
||||
*/
|
||||
if (!amsdu || last_subframe)
|
||||
iwl_mvm_release_frames(mvm, sta, napi, buffer, nssn);
|
||||
|
||||
spin_unlock_bh(&buffer->lock);
|
||||
return true;
|
||||
|
||||
|
@ -736,6 +742,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc));
|
||||
u32 len = le16_to_cpu(desc->mpdu_len);
|
||||
u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
|
||||
u16 phy_info = le16_to_cpu(desc->phy_info);
|
||||
struct ieee80211_sta *sta = NULL;
|
||||
struct sk_buff *skb;
|
||||
u8 crypt_len = 0;
|
||||
|
@ -766,16 +773,34 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
le16_to_cpu(desc->status));
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
}
|
||||
/* set the preamble flag if appropriate */
|
||||
if (phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE)
|
||||
rx_status->flag |= RX_FLAG_SHORTPRE;
|
||||
|
||||
rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
|
||||
if (likely(!(phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD))) {
|
||||
rx_status->mactime = le64_to_cpu(desc->tsf_on_air_rise);
|
||||
/* TSF as indicated by the firmware is at INA time */
|
||||
rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
|
||||
}
|
||||
rx_status->device_timestamp = le32_to_cpu(desc->gp2_on_air_rise);
|
||||
rx_status->band = desc->channel > 14 ? NL80211_BAND_5GHZ :
|
||||
NL80211_BAND_2GHZ;
|
||||
rx_status->freq = ieee80211_channel_to_frequency(desc->channel,
|
||||
rx_status->band);
|
||||
iwl_mvm_get_signal_strength(mvm, desc, rx_status);
|
||||
/* TSF as indicated by the firmware is at INA time */
|
||||
rx_status->flag |= RX_FLAG_MACTIME_PLCP_START;
|
||||
|
||||
/* update aggregation data for monitor sake on default queue */
|
||||
if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
|
||||
bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE;
|
||||
|
||||
rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
rx_status->ampdu_reference = mvm->ampdu_ref;
|
||||
/* toggle is switched whenever new aggregation starts */
|
||||
if (toggle_bit != mvm->ampdu_toggle) {
|
||||
mvm->ampdu_ref++;
|
||||
mvm->ampdu_toggle = toggle_bit;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
@ -797,6 +822,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
if (sta) {
|
||||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct ieee80211_vif *tx_blocked_vif =
|
||||
rcu_dereference(mvm->csa_tx_blocked_vif);
|
||||
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
|
||||
IWL_RX_MPDU_REORDER_BAID_MASK) >>
|
||||
IWL_RX_MPDU_REORDER_BAID_SHIFT);
|
||||
|
@ -806,8 +833,15 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
* frames from a blocked station on a new channel we can
|
||||
* TX to it again.
|
||||
*/
|
||||
if (unlikely(mvm->csa_tx_block_bcn_timeout))
|
||||
iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
|
||||
if (unlikely(tx_blocked_vif) &&
|
||||
tx_blocked_vif == mvmsta->vif) {
|
||||
struct iwl_mvm_vif *mvmvif =
|
||||
iwl_mvm_vif_from_mac80211(tx_blocked_vif);
|
||||
|
||||
if (mvmvif->csa_target_freq == rx_status->freq)
|
||||
iwl_mvm_sta_modify_disable_tx_ap(mvm, sta,
|
||||
false);
|
||||
}
|
||||
|
||||
rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);
|
||||
|
||||
|
@ -830,8 +864,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL);
|
||||
}
|
||||
|
||||
/* TODO: multi queue TCM */
|
||||
|
||||
if (ieee80211_is_data(hdr->frame_control))
|
||||
iwl_mvm_rx_csum(sta, skb, desc);
|
||||
|
||||
|
@ -856,14 +888,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
iwl_mvm_agg_rx_received(mvm, baid);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: PHY info.
|
||||
* Verify we don't have the information in the MPDU descriptor and
|
||||
* that it is not needed.
|
||||
* Make sure for monitor mode that we are on default queue, update
|
||||
* ampdu_ref and the rest of phy info then
|
||||
*/
|
||||
|
||||
/* Set up the HT phy flags */
|
||||
switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
|
||||
case RATE_MCS_CHAN_WIDTH_20:
|
||||
|
@ -907,8 +931,18 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
rx_status->band);
|
||||
}
|
||||
|
||||
/* TODO: PHY info - update ampdu queue statistics (for debugfs) */
|
||||
/* TODO: PHY info - gscan */
|
||||
/* management stuff on default queue */
|
||||
if (!queue) {
|
||||
if (unlikely((ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control)) &&
|
||||
mvm->sched_scan_pass_all ==
|
||||
SCHED_SCAN_PASS_ALL_ENABLED))
|
||||
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_FOUND;
|
||||
|
||||
if (unlikely(ieee80211_is_beacon(hdr->frame_control) ||
|
||||
ieee80211_is_probe_resp(hdr->frame_control)))
|
||||
rx_status->boottime_ns = ktime_get_boot_ns();
|
||||
}
|
||||
|
||||
iwl_mvm_create_skb(skb, hdr, len, crypt_len, rxb);
|
||||
if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc))
|
||||
|
@ -927,6 +961,9 @@ void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
|
||||
int baid = release->baid;
|
||||
|
||||
IWL_DEBUG_HT(mvm, "Frame release notification for BAID %u, NSSN %d\n",
|
||||
release->baid, le16_to_cpu(release->nssn));
|
||||
|
||||
if (WARN_ON_ONCE(baid == IWL_RX_REORDER_DATA_INVALID_BAID))
|
||||
return;
|
||||
|
||||
|
|
|
@ -402,7 +402,7 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm,
|
|||
mvm->scan_status &= ~IWL_MVM_SCAN_REGULAR;
|
||||
ieee80211_scan_completed(mvm->hw, &info);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
del_timer(&mvm->scan_timer);
|
||||
cancel_delayed_work(&mvm->scan_timeout_dwork);
|
||||
} else {
|
||||
IWL_ERR(mvm,
|
||||
"got scan complete notification but no scan is running\n");
|
||||
|
@ -1225,15 +1225,16 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
#define SCAN_TIMEOUT (20 * HZ)
|
||||
#define SCAN_TIMEOUT 20000
|
||||
|
||||
void iwl_mvm_scan_timeout(unsigned long data)
|
||||
void iwl_mvm_scan_timeout_wk(struct work_struct *work)
|
||||
{
|
||||
struct iwl_mvm *mvm = (struct iwl_mvm *)data;
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct iwl_mvm *mvm = container_of(delayed_work, struct iwl_mvm,
|
||||
scan_timeout_dwork);
|
||||
|
||||
IWL_ERR(mvm, "regular scan timed out\n");
|
||||
|
||||
del_timer(&mvm->scan_timer);
|
||||
iwl_force_nmi(mvm->trans);
|
||||
}
|
||||
|
||||
|
@ -1316,7 +1317,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
mvm->scan_status |= IWL_MVM_SCAN_REGULAR;
|
||||
iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
|
||||
|
||||
mod_timer(&mvm->scan_timer, jiffies + SCAN_TIMEOUT);
|
||||
queue_delayed_work(system_wq, &mvm->scan_timeout_dwork,
|
||||
msecs_to_jiffies(SCAN_TIMEOUT));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1439,7 +1441,7 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
|
|||
|
||||
ieee80211_scan_completed(mvm->hw, &info);
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
del_timer(&mvm->scan_timer);
|
||||
cancel_delayed_work(&mvm->scan_timeout_dwork);
|
||||
} else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) {
|
||||
ieee80211_sched_scan_stopped(mvm->hw);
|
||||
mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;
|
||||
|
@ -1644,7 +1646,7 @@ out:
|
|||
* to release the scan reference here.
|
||||
*/
|
||||
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
||||
del_timer(&mvm->scan_timer);
|
||||
cancel_delayed_work(&mvm->scan_timeout_dwork);
|
||||
if (notify) {
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
|
|
|
@ -215,7 +215,7 @@ static int iwl_mvm_sf_config(struct iwl_mvm *mvm, u8 sta_id,
|
|||
enum iwl_sf_state new_state)
|
||||
{
|
||||
struct iwl_sf_cfg_cmd sf_cmd = {
|
||||
.state = cpu_to_le32(SF_FULL_ON),
|
||||
.state = cpu_to_le32(new_state),
|
||||
};
|
||||
struct ieee80211_sta *sta;
|
||||
int ret = 0;
|
||||
|
|
|
@ -310,6 +310,304 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
|
|||
iwl_mvm_disable_txq(mvm, i, i, IWL_MAX_TID_COUNT, 0);
|
||||
}
|
||||
|
||||
/* Disable aggregations for a bitmap of TIDs for a given station */
|
||||
static int iwl_mvm_invalidate_sta_queue(struct iwl_mvm *mvm, int queue,
|
||||
unsigned long disable_agg_tids,
|
||||
bool remove_queue)
|
||||
{
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
u32 status;
|
||||
u8 sta_id;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
sta_id = mvm->queue_info[queue].ra_sta_id;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
mvmsta->tid_disable_agg |= disable_agg_tids;
|
||||
|
||||
cmd.mac_id_n_color = cpu_to_le32(mvmsta->mac_id_n_color);
|
||||
cmd.sta_id = mvmsta->sta_id;
|
||||
cmd.add_modify = STA_MODE_MODIFY;
|
||||
cmd.modify_mask = STA_MODIFY_QUEUES;
|
||||
if (disable_agg_tids)
|
||||
cmd.modify_mask |= STA_MODIFY_TID_DISABLE_TX;
|
||||
if (remove_queue)
|
||||
cmd.modify_mask |= STA_MODIFY_QUEUE_REMOVAL;
|
||||
cmd.tfd_queue_msk = cpu_to_le32(mvmsta->tfd_queue_msk);
|
||||
cmd.tid_disable_tx = cpu_to_le16(mvmsta->tid_disable_agg);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
/* Notify FW of queue removal from the STA queues */
|
||||
status = ADD_STA_SUCCESS;
|
||||
ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
|
||||
iwl_mvm_add_sta_cmd_size(mvm),
|
||||
&cmd, &status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_get_queue_agg_tids(struct iwl_mvm *mvm, int queue)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
unsigned long tid_bitmap;
|
||||
unsigned long agg_tids = 0;
|
||||
s8 sta_id;
|
||||
int tid;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
sta_id = mvm->queue_info[queue].ra_sta_id;
|
||||
tid_bitmap = mvm->queue_info[queue].tid_bitmap;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta)))
|
||||
return -EINVAL;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
|
||||
if (mvmsta->tid_data[tid].state == IWL_AGG_ON)
|
||||
agg_tids |= BIT(tid);
|
||||
}
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
return agg_tids;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a queue from a station's resources.
|
||||
* Note that this only marks as free. It DOESN'T delete a BA agreement, and
|
||||
* doesn't disable the queue
|
||||
*/
|
||||
static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
unsigned long tid_bitmap;
|
||||
unsigned long disable_agg_tids = 0;
|
||||
u8 sta_id;
|
||||
int tid;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
sta_id = mvm->queue_info[queue].ra_sta_id;
|
||||
tid_bitmap = mvm->queue_info[queue].tid_bitmap;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
|
||||
if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
/* Unmap MAC queues and TIDs from this queue */
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
|
||||
if (mvmsta->tid_data[tid].state == IWL_AGG_ON)
|
||||
disable_agg_tids |= BIT(tid);
|
||||
mvmsta->tid_data[tid].txq_id = IEEE80211_INVAL_HW_QUEUE;
|
||||
}
|
||||
|
||||
mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
/* Unmap MAC queues and TIDs from this queue */
|
||||
mvm->queue_info[queue].hw_queue_to_mac80211 = 0;
|
||||
mvm->queue_info[queue].hw_queue_refcount = 0;
|
||||
mvm->queue_info[queue].tid_bitmap = 0;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
return disable_agg_tids;
|
||||
}
|
||||
|
||||
static int iwl_mvm_get_shared_queue(struct iwl_mvm *mvm,
|
||||
unsigned long tfd_queue_mask, u8 ac)
|
||||
{
|
||||
int queue = 0;
|
||||
u8 ac_to_queue[IEEE80211_NUM_ACS];
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->queue_info_lock);
|
||||
|
||||
memset(&ac_to_queue, IEEE80211_INVAL_HW_QUEUE, sizeof(ac_to_queue));
|
||||
|
||||
/* See what ACs the existing queues for this STA have */
|
||||
for_each_set_bit(i, &tfd_queue_mask, IWL_MVM_DQA_MAX_DATA_QUEUE) {
|
||||
/* Only DATA queues can be shared */
|
||||
if (i < IWL_MVM_DQA_MIN_DATA_QUEUE &&
|
||||
i != IWL_MVM_DQA_BSS_CLIENT_QUEUE)
|
||||
continue;
|
||||
|
||||
ac_to_queue[mvm->queue_info[i].mac80211_ac] = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* The queue to share is chosen only from DATA queues as follows (in
|
||||
* descending priority):
|
||||
* 1. An AC_BE queue
|
||||
* 2. Same AC queue
|
||||
* 3. Highest AC queue that is lower than new AC
|
||||
* 4. Any existing AC (there always is at least 1 DATA queue)
|
||||
*/
|
||||
|
||||
/* Priority 1: An AC_BE queue */
|
||||
if (ac_to_queue[IEEE80211_AC_BE] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[IEEE80211_AC_BE];
|
||||
/* Priority 2: Same AC queue */
|
||||
else if (ac_to_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[ac];
|
||||
/* Priority 3a: If new AC is VO and VI exists - use VI */
|
||||
else if (ac == IEEE80211_AC_VO &&
|
||||
ac_to_queue[IEEE80211_AC_VI] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[IEEE80211_AC_VI];
|
||||
/* Priority 3b: No BE so only AC less than the new one is BK */
|
||||
else if (ac_to_queue[IEEE80211_AC_BK] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[IEEE80211_AC_BK];
|
||||
/* Priority 4a: No BE nor BK - use VI if exists */
|
||||
else if (ac_to_queue[IEEE80211_AC_VI] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[IEEE80211_AC_VI];
|
||||
/* Priority 4b: No BE, BK nor VI - use VO if exists */
|
||||
else if (ac_to_queue[IEEE80211_AC_VO] != IEEE80211_INVAL_HW_QUEUE)
|
||||
queue = ac_to_queue[IEEE80211_AC_VO];
|
||||
|
||||
/* Make sure queue found (or not) is legal */
|
||||
if (!((queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE &&
|
||||
queue <= IWL_MVM_DQA_MAX_MGMT_QUEUE) ||
|
||||
(queue >= IWL_MVM_DQA_MIN_DATA_QUEUE &&
|
||||
queue <= IWL_MVM_DQA_MAX_DATA_QUEUE) ||
|
||||
(queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE))) {
|
||||
IWL_ERR(mvm, "No DATA queues available to share\n");
|
||||
queue = -ENOSPC;
|
||||
}
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a given queue has a higher AC than the TID stream that is being added to
|
||||
* it, the queue needs to be redirected to the lower AC. This function does that
|
||||
* in such a case, otherwise - if no redirection required - it does nothing,
|
||||
* unless the %force param is true.
|
||||
*/
|
||||
static int iwl_mvm_scd_queue_redirect(struct iwl_mvm *mvm, int queue, int tid,
|
||||
int ac, int ssn, unsigned int wdg_timeout,
|
||||
bool force)
|
||||
{
|
||||
struct iwl_scd_txq_cfg_cmd cmd = {
|
||||
.scd_queue = queue,
|
||||
.enable = 0,
|
||||
};
|
||||
bool shared_queue;
|
||||
unsigned long mq;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If the AC is lower than current one - FIFO needs to be redirected to
|
||||
* the lowest one of the streams in the queue. Check if this is needed
|
||||
* here.
|
||||
* Notice that the enum ieee80211_ac_numbers is "flipped", so BK is with
|
||||
* value 3 and VO with value 0, so to check if ac X is lower than ac Y
|
||||
* we need to check if the numerical value of X is LARGER than of Y.
|
||||
*/
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
if (ac <= mvm->queue_info[queue].mac80211_ac && !force) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"No redirection needed on TXQ #%d\n",
|
||||
queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
|
||||
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[mvm->queue_info[queue].mac80211_ac];
|
||||
mq = mvm->queue_info[queue].hw_queue_to_mac80211;
|
||||
shared_queue = (mvm->queue_info[queue].hw_queue_refcount > 1);
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Redirecting shared TXQ #%d to FIFO #%d\n",
|
||||
queue, iwl_mvm_ac_to_tx_fifo[ac]);
|
||||
|
||||
/* Stop MAC queues and wait for this queue to empty */
|
||||
iwl_mvm_stop_mac_queues(mvm, mq);
|
||||
ret = iwl_trans_wait_tx_queue_empty(mvm->trans, BIT(queue));
|
||||
if (ret) {
|
||||
IWL_ERR(mvm, "Error draining queue %d before reconfig\n",
|
||||
queue);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Before redirecting the queue we need to de-activate it */
|
||||
iwl_trans_txq_disable(mvm->trans, queue, false);
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "Failed SCD disable TXQ %d (ret=%d)\n", queue,
|
||||
ret);
|
||||
|
||||
/* Make sure the SCD wrptr is correctly set before reconfiguring */
|
||||
iwl_trans_txq_enable(mvm->trans, queue, iwl_mvm_ac_to_tx_fifo[ac],
|
||||
cmd.sta_id, tid, LINK_QUAL_AGG_FRAME_LIMIT_DEF,
|
||||
ssn, wdg_timeout);
|
||||
|
||||
/* TODO: Work-around SCD bug when moving back by multiples of 0x40 */
|
||||
|
||||
/* Redirect to lower AC */
|
||||
iwl_mvm_reconfig_scd(mvm, queue, iwl_mvm_ac_to_tx_fifo[ac],
|
||||
cmd.sta_id, tid, LINK_QUAL_AGG_FRAME_LIMIT_DEF,
|
||||
ssn);
|
||||
|
||||
/* Update AC marking of the queue */
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
mvm->queue_info[queue].mac80211_ac = ac;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/*
|
||||
* Mark queue as shared in transport if shared
|
||||
* Note this has to be done after queue enablement because enablement
|
||||
* can also set this value, and there is no indication there to shared
|
||||
* queues
|
||||
*/
|
||||
if (shared_queue)
|
||||
iwl_trans_txq_set_shared_mode(mvm->trans, queue, true);
|
||||
|
||||
out:
|
||||
/* Continue using the MAC queues */
|
||||
iwl_mvm_start_mac_queues(mvm, mq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
||||
struct ieee80211_sta *sta, u8 ac, int tid,
|
||||
struct ieee80211_hdr *hdr)
|
||||
|
@ -325,11 +623,20 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
iwl_mvm_get_wd_timeout(mvm, mvmsta->vif, false, false);
|
||||
u8 mac_queue = mvmsta->vif->hw_queue[ac];
|
||||
int queue = -1;
|
||||
bool using_inactive_queue = false;
|
||||
unsigned long disable_agg_tids = 0;
|
||||
enum iwl_mvm_agg_state queue_state;
|
||||
bool shared_queue = false;
|
||||
int ssn;
|
||||
unsigned long tfd_queue_mask;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
tfd_queue_mask = mvmsta->tfd_queue_msk;
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/*
|
||||
|
@ -338,7 +645,8 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
*/
|
||||
if (!ieee80211_is_data_qos(hdr->frame_control) ||
|
||||
ieee80211_is_qos_nullfunc(hdr->frame_control)) {
|
||||
queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_MGMT_QUEUE,
|
||||
queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
|
||||
IWL_MVM_DQA_MIN_MGMT_QUEUE,
|
||||
IWL_MVM_DQA_MAX_MGMT_QUEUE);
|
||||
if (queue >= IWL_MVM_DQA_MIN_MGMT_QUEUE)
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Found free MGMT queue #%d\n",
|
||||
|
@ -347,29 +655,62 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
/* If no such queue is found, we'll use a DATA queue instead */
|
||||
}
|
||||
|
||||
if (queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {
|
||||
if ((queue < 0 && mvmsta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) &&
|
||||
(mvm->queue_info[mvmsta->reserved_queue].status ==
|
||||
IWL_MVM_QUEUE_RESERVED ||
|
||||
mvm->queue_info[mvmsta->reserved_queue].status ==
|
||||
IWL_MVM_QUEUE_INACTIVE)) {
|
||||
queue = mvmsta->reserved_queue;
|
||||
mvm->queue_info[queue].reserved = true;
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Using reserved queue #%d\n", queue);
|
||||
}
|
||||
|
||||
if (queue < 0)
|
||||
queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
|
||||
IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
IWL_MVM_DQA_MAX_DATA_QUEUE);
|
||||
|
||||
/*
|
||||
* Check if this queue is already allocated but inactive.
|
||||
* In such a case, we'll need to first free this queue before enabling
|
||||
* it again, so we'll mark it as reserved to make sure no new traffic
|
||||
* arrives on it
|
||||
*/
|
||||
if (queue > 0 &&
|
||||
mvm->queue_info[queue].status == IWL_MVM_QUEUE_INACTIVE) {
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_RESERVED;
|
||||
using_inactive_queue = true;
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Re-assigning TXQ %d: sta_id=%d, tid=%d\n",
|
||||
queue, mvmsta->sta_id, tid);
|
||||
}
|
||||
|
||||
/* No free queue - we'll have to share */
|
||||
if (queue <= 0) {
|
||||
queue = iwl_mvm_get_shared_queue(mvm, tfd_queue_mask, ac);
|
||||
if (queue > 0) {
|
||||
shared_queue = true;
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_SHARED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark TXQ as ready, even though it hasn't been fully configured yet,
|
||||
* to make sure no one else takes it.
|
||||
* This will allow avoiding re-acquiring the lock at the end of the
|
||||
* configuration. On error we'll mark it back as free.
|
||||
*/
|
||||
if (queue >= 0)
|
||||
if ((queue > 0) && !shared_queue)
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_READY;
|
||||
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/* TODO: support shared queues for same RA */
|
||||
if (queue < 0)
|
||||
/* This shouldn't happen - out of queues */
|
||||
if (WARN_ON(queue <= 0)) {
|
||||
IWL_ERR(mvm, "No available queues for tid %d on sta_id %d\n",
|
||||
tid, cfg.sta_id);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Actual en/disablement of aggregations is through the ADD_STA HCMD,
|
||||
|
@ -380,24 +721,103 @@ static int iwl_mvm_sta_alloc_queue(struct iwl_mvm *mvm,
|
|||
cfg.aggregate = (queue >= IWL_MVM_DQA_MIN_DATA_QUEUE ||
|
||||
queue == IWL_MVM_DQA_BSS_CLIENT_QUEUE);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Allocating queue #%d to sta %d on tid %d\n",
|
||||
queue, mvmsta->sta_id, tid);
|
||||
/*
|
||||
* If this queue was previously inactive (idle) - we need to free it
|
||||
* first
|
||||
*/
|
||||
if (using_inactive_queue) {
|
||||
struct iwl_scd_txq_cfg_cmd cmd = {
|
||||
.scd_queue = queue,
|
||||
.enable = 0,
|
||||
};
|
||||
u8 ac;
|
||||
|
||||
disable_agg_tids = iwl_mvm_remove_sta_queue_marking(mvm, queue);
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
ac = mvm->queue_info[queue].mac80211_ac;
|
||||
cmd.sta_id = mvm->queue_info[queue].ra_sta_id;
|
||||
cmd.tx_fifo = iwl_mvm_ac_to_tx_fifo[ac];
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/* Disable the queue */
|
||||
iwl_mvm_invalidate_sta_queue(mvm, queue, disable_agg_tids,
|
||||
true);
|
||||
iwl_trans_txq_disable(mvm->trans, queue, false);
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
|
||||
&cmd);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm,
|
||||
"Failed to free inactive queue %d (ret=%d)\n",
|
||||
queue, ret);
|
||||
|
||||
/* Re-mark the inactive queue as inactive */
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE;
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Allocating %squeue #%d to sta %d on tid %d\n",
|
||||
shared_queue ? "shared " : "", queue,
|
||||
mvmsta->sta_id, tid);
|
||||
|
||||
if (shared_queue) {
|
||||
/* Disable any open aggs on this queue */
|
||||
disable_agg_tids = iwl_mvm_get_queue_agg_tids(mvm, queue);
|
||||
|
||||
if (disable_agg_tids) {
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Disabling aggs on queue %d\n",
|
||||
queue);
|
||||
iwl_mvm_invalidate_sta_queue(mvm, queue,
|
||||
disable_agg_tids, false);
|
||||
}
|
||||
}
|
||||
|
||||
ssn = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
|
||||
iwl_mvm_enable_txq(mvm, queue, mac_queue, ssn, &cfg,
|
||||
wdg_timeout);
|
||||
|
||||
/*
|
||||
* Mark queue as shared in transport if shared
|
||||
* Note this has to be done after queue enablement because enablement
|
||||
* can also set this value, and there is no indication there to shared
|
||||
* queues
|
||||
*/
|
||||
if (shared_queue)
|
||||
iwl_trans_txq_set_shared_mode(mvm->trans, queue, true);
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
mvmsta->tid_data[tid].txq_id = queue;
|
||||
mvmsta->tid_data[tid].is_tid_active = true;
|
||||
mvmsta->tfd_queue_msk |= BIT(queue);
|
||||
queue_state = mvmsta->tid_data[tid].state;
|
||||
|
||||
if (mvmsta->reserved_queue == queue)
|
||||
mvmsta->reserved_queue = IEEE80211_INVAL_HW_QUEUE;
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
if (!shared_queue) {
|
||||
ret = iwl_mvm_sta_send_to_fw(mvm, sta, true, STA_MODIFY_QUEUES);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
/* If we need to re-enable aggregations... */
|
||||
if (queue_state == IWL_AGG_ON) {
|
||||
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
/* Redirect queue, if needed */
|
||||
ret = iwl_mvm_scd_queue_redirect(mvm, queue, tid, ac, ssn,
|
||||
wdg_timeout, false);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -476,6 +896,9 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
|
|||
unsigned long deferred_tid_traffic;
|
||||
int sta_id, tid;
|
||||
|
||||
/* Check inactivity of queues */
|
||||
iwl_mvm_inactivity_check(mvm);
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
/* Go over all stations with deferred traffic */
|
||||
|
@ -505,6 +928,12 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
|
|||
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
int queue;
|
||||
|
||||
/*
|
||||
* Check for inactive queues, so we don't reach a situation where we
|
||||
* can't add a STA due to a shortage in queues that doesn't really exist
|
||||
*/
|
||||
iwl_mvm_inactivity_check(mvm);
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/* Make sure we have free resources for this STA */
|
||||
|
@ -514,7 +943,8 @@ static int iwl_mvm_reserve_sta_stream(struct iwl_mvm *mvm,
|
|||
IWL_MVM_QUEUE_FREE))
|
||||
queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
|
||||
else
|
||||
queue = iwl_mvm_find_free_queue(mvm, IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
queue = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
|
||||
IWL_MVM_DQA_MIN_DATA_QUEUE,
|
||||
IWL_MVM_DQA_MAX_DATA_QUEUE);
|
||||
if (queue < 0) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
@ -568,8 +998,11 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
mvm_sta->tid_disable_agg = 0xffff; /* No aggs at first */
|
||||
mvm_sta->tfd_queue_msk = 0;
|
||||
|
||||
/* allocate new queues for a TDLS station */
|
||||
if (sta->tdls) {
|
||||
/*
|
||||
* Allocate new queues for a TDLS station, unless we're in DQA mode,
|
||||
* and then they'll be allocated dynamically
|
||||
*/
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls) {
|
||||
ret = iwl_mvm_tdls_sta_init(mvm, sta);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -633,7 +1066,8 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
|
|||
return 0;
|
||||
|
||||
err:
|
||||
iwl_mvm_tdls_sta_deinit(mvm, sta);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls)
|
||||
iwl_mvm_tdls_sta_deinit(mvm, sta);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -819,8 +1253,9 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
|||
if (iwl_mvm_has_new_rx_api(mvm))
|
||||
kfree(mvm_sta->dup_data);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == mvm_sta->sta_id) {
|
||||
if ((vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == mvm_sta->sta_id) ||
|
||||
iwl_mvm_is_dqa_supported(mvm)){
|
||||
ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -838,16 +1273,19 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
|||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
|
||||
|
||||
/* if we are associated - we can't remove the AP STA now */
|
||||
if (vif->bss_conf.assoc)
|
||||
return ret;
|
||||
if (vif->type == NL80211_IFTYPE_STATION &&
|
||||
mvmvif->ap_sta_id == mvm_sta->sta_id) {
|
||||
/* if associated - we can't remove the AP STA now */
|
||||
if (vif->bss_conf.assoc)
|
||||
return ret;
|
||||
|
||||
/* unassoc - go ahead - remove the AP STA now */
|
||||
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
/* unassoc - go ahead - remove the AP STA now */
|
||||
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
|
||||
/* clear d0i3_ap_sta_id if no longer relevant */
|
||||
if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
|
||||
mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
/* clear d0i3_ap_sta_id if no longer relevant */
|
||||
if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
|
||||
mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -885,7 +1323,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
|
|||
} else {
|
||||
spin_unlock_bh(&mvm_sta->lock);
|
||||
|
||||
if (sta->tdls)
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) && sta->tdls)
|
||||
iwl_mvm_tdls_sta_deinit(mvm, sta);
|
||||
|
||||
ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
|
||||
|
@ -983,8 +1421,9 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
|
|||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
/* Map Aux queue to fifo - needs to happen before adding Aux station */
|
||||
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue,
|
||||
IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
|
||||
if (!iwl_mvm_is_dqa_supported(mvm))
|
||||
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue, mvm->aux_queue,
|
||||
IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
|
||||
|
||||
/* Allocate aux station and assign to it the aux queue */
|
||||
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
|
||||
|
@ -992,6 +1431,19 @@ int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
struct iwl_trans_txq_scd_cfg cfg = {
|
||||
.fifo = IWL_MVM_TX_FIFO_MCAST,
|
||||
.sta_id = mvm->aux_sta.sta_id,
|
||||
.tid = IWL_MAX_TID_COUNT,
|
||||
.aggregate = false,
|
||||
.frame_limit = IWL_FRAME_LIMIT,
|
||||
};
|
||||
|
||||
iwl_mvm_enable_txq(mvm, mvm->aux_queue, mvm->aux_queue, 0, &cfg,
|
||||
wdg_timeout);
|
||||
}
|
||||
|
||||
ret = iwl_mvm_add_int_sta_common(mvm, &mvm->aux_sta, NULL,
|
||||
MAC_INDEX_AUX, 0);
|
||||
|
||||
|
@ -1316,8 +1768,8 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
|
||||
switch (status & IWL_ADD_STA_STATUS_MASK) {
|
||||
case ADD_STA_SUCCESS:
|
||||
IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
|
||||
start ? "start" : "stopp");
|
||||
IWL_DEBUG_HT(mvm, "RX BA Session %sed in fw\n",
|
||||
start ? "start" : "stopp");
|
||||
break;
|
||||
case ADD_STA_IMMEDIATE_BA_FAILURE:
|
||||
IWL_WARN(mvm, "RX BA Session refused by fw\n");
|
||||
|
@ -1372,13 +1824,16 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
* supposed to happen) and we will free the session data while
|
||||
* RX is being processed in parallel
|
||||
*/
|
||||
IWL_DEBUG_HT(mvm, "Sta %d(%d) is assigned to BAID %d\n",
|
||||
mvm_sta->sta_id, tid, baid);
|
||||
WARN_ON(rcu_access_pointer(mvm->baid_map[baid]));
|
||||
rcu_assign_pointer(mvm->baid_map[baid], baid_data);
|
||||
} else if (mvm->rx_ba_sessions > 0) {
|
||||
} else {
|
||||
u8 baid = mvm_sta->tid_to_baid[tid];
|
||||
|
||||
/* check that restart flow didn't zero the counter */
|
||||
mvm->rx_ba_sessions--;
|
||||
if (mvm->rx_ba_sessions > 0)
|
||||
/* check that restart flow didn't zero the counter */
|
||||
mvm->rx_ba_sessions--;
|
||||
if (!iwl_mvm_has_new_rx_api(mvm))
|
||||
return 0;
|
||||
|
||||
|
@ -1394,6 +1849,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
|||
del_timer_sync(&baid_data->session_timer);
|
||||
RCU_INIT_POINTER(mvm->baid_map[baid], NULL);
|
||||
kfree_rcu(baid_data, rcu_head);
|
||||
IWL_DEBUG_HT(mvm, "BAID %d is free\n", baid);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -1402,8 +1858,8 @@ out_free:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, u8 queue, bool start)
|
||||
int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, u8 queue, bool start)
|
||||
{
|
||||
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
struct iwl_mvm_add_sta_cmd cmd = {};
|
||||
|
@ -1458,6 +1914,7 @@ const u8 tid_to_mac80211_ac[] = {
|
|||
IEEE80211_AC_VI,
|
||||
IEEE80211_AC_VO,
|
||||
IEEE80211_AC_VO,
|
||||
IEEE80211_AC_VO, /* We treat MGMT as TID 8, which is set as AC_VO */
|
||||
};
|
||||
|
||||
static const u8 tid_to_ucode_ac[] = {
|
||||
|
@ -1512,7 +1969,8 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
if (!iwl_mvm_is_dqa_supported(mvm) ||
|
||||
mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
|
||||
txq_id = iwl_mvm_find_free_queue(mvm, mvm->first_agg_queue,
|
||||
txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
|
||||
mvm->first_agg_queue,
|
||||
mvm->last_agg_queue);
|
||||
if (txq_id < 0) {
|
||||
ret = txq_id;
|
||||
|
@ -1907,6 +2365,13 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
|
|||
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
|
||||
memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
key_flags |= cpu_to_le16(STA_KEY_FLG_KEY_32BYTES);
|
||||
/* fall through */
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
key_flags |= cpu_to_le16(STA_KEY_FLG_GCMP);
|
||||
memcpy(cmd.key, keyconf->key, keyconf->keylen);
|
||||
break;
|
||||
default:
|
||||
key_flags |= cpu_to_le16(STA_KEY_FLG_EXT);
|
||||
memcpy(cmd.key, keyconf->key, keyconf->keylen);
|
||||
|
@ -2035,6 +2500,8 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
|
|||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
|
||||
0, NULL, 0, key_offset);
|
||||
break;
|
||||
|
|
|
@ -321,6 +321,9 @@ enum iwl_mvm_agg_state {
|
|||
* Basically when next_reclaimed reaches ssn, we can tell mac80211 that
|
||||
* we are ready to finish the Tx AGG stop / start flow.
|
||||
* @tx_time: medium time consumed by this A-MPDU
|
||||
* @is_tid_active: has this TID sent traffic in the last
|
||||
* %IWL_MVM_DQA_QUEUE_TIMEOUT time period. If %txq_id is invalid, this
|
||||
* field should be ignored.
|
||||
*/
|
||||
struct iwl_mvm_tid_data {
|
||||
struct sk_buff_head deferred_tx_frames;
|
||||
|
@ -333,6 +336,7 @@ struct iwl_mvm_tid_data {
|
|||
u16 txq_id;
|
||||
u16 ssn;
|
||||
u16 tx_time;
|
||||
bool is_tid_active;
|
||||
};
|
||||
|
||||
static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
|
||||
|
@ -434,6 +438,7 @@ struct iwl_mvm_sta {
|
|||
bool tlc_amsdu;
|
||||
u8 agg_tids;
|
||||
u8 sleep_tx_count;
|
||||
u8 avg_energy;
|
||||
};
|
||||
|
||||
static inline struct iwl_mvm_sta *
|
||||
|
@ -509,6 +514,9 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, u16 tid);
|
||||
|
||||
int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int tid, u8 queue, bool start);
|
||||
|
||||
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm);
|
||||
void iwl_mvm_del_aux_sta(struct iwl_mvm *mvm);
|
||||
|
||||
|
|
|
@ -138,28 +138,19 @@ static void iwl_mvm_tx_csum(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
|
||||
protocol = ipv6h->nexthdr;
|
||||
while (protocol != NEXTHDR_NONE && ipv6_ext_hdr(protocol)) {
|
||||
struct ipv6_opt_hdr *hp;
|
||||
|
||||
/* only supported extension headers */
|
||||
if (protocol != NEXTHDR_ROUTING &&
|
||||
protocol != NEXTHDR_HOP &&
|
||||
protocol != NEXTHDR_DEST &&
|
||||
protocol != NEXTHDR_FRAGMENT) {
|
||||
protocol != NEXTHDR_DEST) {
|
||||
skb_checksum_help(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (protocol == NEXTHDR_FRAGMENT) {
|
||||
struct frag_hdr *hp =
|
||||
OPT_HDR(struct frag_hdr, skb, off);
|
||||
|
||||
protocol = hp->nexthdr;
|
||||
off += sizeof(struct frag_hdr);
|
||||
} else {
|
||||
struct ipv6_opt_hdr *hp =
|
||||
OPT_HDR(struct ipv6_opt_hdr, skb, off);
|
||||
|
||||
protocol = hp->nexthdr;
|
||||
off += ipv6_optlen(hp);
|
||||
}
|
||||
hp = OPT_HDR(struct ipv6_opt_hdr, skb, off);
|
||||
protocol = hp->nexthdr;
|
||||
off += ipv6_optlen(hp);
|
||||
}
|
||||
/* if we get here - protocol now should be TCP/UDP */
|
||||
#endif
|
||||
|
@ -388,6 +379,23 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
|
|||
tx_cmd->rate_n_flags = cpu_to_le32((u32)rate_plcp | rate_flags);
|
||||
}
|
||||
|
||||
static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info,
|
||||
u8 *crypto_hdr)
|
||||
{
|
||||
struct ieee80211_key_conf *keyconf = info->control.hw_key;
|
||||
u64 pn;
|
||||
|
||||
pn = atomic64_inc_return(&keyconf->tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[2] = 0;
|
||||
crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the fields in the Tx cmd that are crypto related
|
||||
*/
|
||||
|
@ -405,15 +413,7 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
|
|||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||
iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
|
||||
pn = atomic64_inc_return(&keyconf->tx_pn);
|
||||
crypto_hdr[0] = pn;
|
||||
crypto_hdr[2] = 0;
|
||||
crypto_hdr[3] = 0x20 | (keyconf->keyidx << 6);
|
||||
crypto_hdr[1] = pn >> 8;
|
||||
crypto_hdr[4] = pn >> 16;
|
||||
crypto_hdr[5] = pn >> 24;
|
||||
crypto_hdr[6] = pn >> 32;
|
||||
crypto_hdr[7] = pn >> 40;
|
||||
iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
|
||||
break;
|
||||
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
|
@ -433,6 +433,18 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
|
|||
|
||||
memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
/* TODO: Taking the key from the table might introduce a race
|
||||
* when PTK rekeying is done, having an old packets with a PN
|
||||
* based on the old key but the message encrypted with a new
|
||||
* one.
|
||||
* Need to handle this.
|
||||
*/
|
||||
tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TC_CMD_SEC_KEY_FROM_TABLE;
|
||||
tx_cmd->key[0] = keyconf->hw_key_idx;
|
||||
iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
|
||||
break;
|
||||
default:
|
||||
tx_cmd->sec_ctl |= TX_CMD_SEC_EXT;
|
||||
}
|
||||
|
@ -534,6 +546,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
* (this is not possible for unicast packets as a TLDS discovery
|
||||
* response are sent without a station entry); otherwise use the
|
||||
* AUX station.
|
||||
* In DQA mode, if vif is of type STATION and frames are not multicast,
|
||||
* they should be sent from the BSS queue. For example, TDLS setup
|
||||
* frames should be sent on this queue, as they go through the AP.
|
||||
*/
|
||||
sta_id = mvm->aux_sta.sta_id;
|
||||
if (info.control.vif) {
|
||||
|
@ -551,6 +566,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
|
||||
if (ap_sta_id != IWL_MVM_STATION_COUNT)
|
||||
sta_id = ap_sta_id;
|
||||
} else if (iwl_mvm_is_dqa_supported(mvm) &&
|
||||
info.control.vif->type == NL80211_IFTYPE_STATION) {
|
||||
queue = IWL_MVM_DQA_BSS_CLIENT_QUEUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -884,15 +902,17 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
* nullfunc frames should go to the MGMT queue regardless of QOS
|
||||
*/
|
||||
tid = IWL_MAX_TID_COUNT;
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
|
||||
/* Copy MAC header from skb into command buffer */
|
||||
memcpy(tx_cmd->hdr, hdr, hdrlen);
|
||||
|
||||
WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
|
||||
|
||||
if (sta->tdls) {
|
||||
if (sta->tdls && !iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/* default to TID 0 for non-QoS packets */
|
||||
u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid;
|
||||
|
||||
|
@ -905,9 +925,12 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
}
|
||||
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
if (unlikely(mvmsta->tid_data[tid].txq_id ==
|
||||
IEEE80211_INVAL_HW_QUEUE)) {
|
||||
/* Check if TXQ needs to be allocated or re-activated */
|
||||
if (unlikely(txq_id == IEEE80211_INVAL_HW_QUEUE ||
|
||||
!mvmsta->tid_data[tid].is_tid_active) &&
|
||||
iwl_mvm_is_dqa_supported(mvm)) {
|
||||
/* If TXQ needs to be allocated... */
|
||||
if (txq_id == IEEE80211_INVAL_HW_QUEUE) {
|
||||
iwl_mvm_tx_add_stream(mvm, mvmsta, tid, skb);
|
||||
|
||||
/*
|
||||
|
@ -917,11 +940,22 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
|
|||
iwl_trans_free_tx_cmd(mvm->trans, dev_cmd);
|
||||
spin_unlock(&mvmsta->lock);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
txq_id = mvmsta->tid_data[tid].txq_id;
|
||||
/* If we are here - TXQ exists and needs to be re-activated */
|
||||
spin_lock(&mvm->queue_info_lock);
|
||||
mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_READY;
|
||||
mvmsta->tid_data[tid].is_tid_active = true;
|
||||
spin_unlock(&mvm->queue_info_lock);
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Re-activating queue %d for TX\n",
|
||||
txq_id);
|
||||
}
|
||||
|
||||
/* Keep track of the time of the last frame for this RA/TID */
|
||||
mvm->queue_info[txq_id].last_frame_time[tid] = jiffies;
|
||||
|
||||
IWL_DEBUG_TX(mvm, "TX to [%d|%d] Q:%d - seq: 0x%x\n", mvmsta->sta_id,
|
||||
tid, txq_id, IEEE80211_SEQ_TO_SN(seq_number));
|
||||
|
||||
|
@ -1313,7 +1347,15 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
|
|||
bool send_eosp_ndp = false;
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
txq_agg = (mvmsta->tid_data[tid].state == IWL_AGG_ON);
|
||||
if (iwl_mvm_is_dqa_supported(mvm)) {
|
||||
enum iwl_mvm_agg_state state;
|
||||
|
||||
state = mvmsta->tid_data[tid].state;
|
||||
txq_agg = (state == IWL_AGG_ON ||
|
||||
state == IWL_EMPTYING_HW_QUEUE_DELBA);
|
||||
} else {
|
||||
txq_agg = txq_id >= mvm->first_agg_queue;
|
||||
}
|
||||
|
||||
if (!is_ndp) {
|
||||
tid_data->next_reclaimed = next_reclaimed;
|
||||
|
@ -1644,7 +1686,7 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
|
|||
iwl_mvm_tx_info_from_ba_notif(&ba_info, ba_notif, tid_data);
|
||||
|
||||
IWL_DEBUG_TX_REPLY(mvm, "No reclaim. Update rs directly\n");
|
||||
iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info);
|
||||
iwl_mvm_rs_tx_status(mvm, sta, tid, &ba_info, false);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
@ -579,17 +579,29 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
|
|||
iwl_mvm_dump_umac_error_log(mvm);
|
||||
}
|
||||
|
||||
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 minq, u8 maxq)
|
||||
int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq)
|
||||
{
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&mvm->queue_info_lock);
|
||||
|
||||
/* Start by looking for a free queue */
|
||||
for (i = minq; i <= maxq; i++)
|
||||
if (mvm->queue_info[i].hw_queue_refcount == 0 &&
|
||||
mvm->queue_info[i].status == IWL_MVM_QUEUE_FREE)
|
||||
return i;
|
||||
|
||||
/*
|
||||
* If no free queue found - settle for an inactive one to reconfigure
|
||||
* Make sure that the inactive queue either already belongs to this STA,
|
||||
* or that if it belongs to another one - it isn't the reserved queue
|
||||
*/
|
||||
for (i = minq; i <= maxq; i++)
|
||||
if (mvm->queue_info[i].status == IWL_MVM_QUEUE_INACTIVE &&
|
||||
(sta_id == mvm->queue_info[i].ra_sta_id ||
|
||||
!mvm->queue_info[i].reserved))
|
||||
return i;
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
|
@ -643,13 +655,21 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
}
|
||||
|
||||
/* Update mappings and refcounts */
|
||||
if (mvm->queue_info[queue].hw_queue_refcount > 0)
|
||||
enable_queue = false;
|
||||
|
||||
mvm->queue_info[queue].hw_queue_to_mac80211 |= BIT(mac80211_queue);
|
||||
mvm->queue_info[queue].hw_queue_refcount++;
|
||||
if (mvm->queue_info[queue].hw_queue_refcount > 1)
|
||||
enable_queue = false;
|
||||
else
|
||||
mvm->queue_info[queue].ra_sta_id = cfg->sta_id;
|
||||
mvm->queue_info[queue].tid_bitmap |= BIT(cfg->tid);
|
||||
mvm->queue_info[queue].ra_sta_id = cfg->sta_id;
|
||||
|
||||
if (enable_queue) {
|
||||
if (cfg->tid != IWL_MAX_TID_COUNT)
|
||||
mvm->queue_info[queue].mac80211_ac =
|
||||
tid_to_mac80211_ac[cfg->tid];
|
||||
else
|
||||
mvm->queue_info[queue].mac80211_ac = IEEE80211_AC_VO;
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Enabling TXQ #%d refcount=%d (mac80211 map:0x%x)\n",
|
||||
|
@ -671,6 +691,10 @@ void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
.tid = cfg->tid,
|
||||
};
|
||||
|
||||
/* Set sta_id in the command, if it exists */
|
||||
if (iwl_mvm_is_dqa_supported(mvm))
|
||||
cmd.sta_id = cfg->sta_id;
|
||||
|
||||
iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL,
|
||||
wdg_timeout);
|
||||
WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd),
|
||||
|
@ -752,6 +776,9 @@ void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue,
|
|||
mvm->queue_info[queue].tid_bitmap = 0;
|
||||
mvm->queue_info[queue].hw_queue_to_mac80211 = 0;
|
||||
|
||||
/* Regardless if this is a reserved TXQ for a STA - mark it as false */
|
||||
mvm->queue_info[queue].reserved = false;
|
||||
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
iwl_trans_txq_disable(mvm->trans, queue, false);
|
||||
|
@ -1039,6 +1066,155 @@ out:
|
|||
ieee80211_connection_loss(vif);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove inactive TIDs of a given queue.
|
||||
* If all queue TIDs are inactive - mark the queue as inactive
|
||||
* If only some the queue TIDs are inactive - unmap them from the queue
|
||||
*/
|
||||
static void iwl_mvm_remove_inactive_tids(struct iwl_mvm *mvm,
|
||||
struct iwl_mvm_sta *mvmsta, int queue,
|
||||
unsigned long tid_bitmap)
|
||||
{
|
||||
int tid;
|
||||
|
||||
lockdep_assert_held(&mvmsta->lock);
|
||||
lockdep_assert_held(&mvm->queue_info_lock);
|
||||
|
||||
/* Go over all non-active TIDs, incl. IWL_MAX_TID_COUNT (for mgmt) */
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
|
||||
/* If some TFDs are still queued - don't mark TID as inactive */
|
||||
if (iwl_mvm_tid_queued(&mvmsta->tid_data[tid]))
|
||||
tid_bitmap &= ~BIT(tid);
|
||||
}
|
||||
|
||||
/* If all TIDs in the queue are inactive - mark queue as inactive. */
|
||||
if (tid_bitmap == mvm->queue_info[queue].tid_bitmap) {
|
||||
mvm->queue_info[queue].status = IWL_MVM_QUEUE_INACTIVE;
|
||||
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1)
|
||||
mvmsta->tid_data[tid].is_tid_active = false;
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm, "Queue %d marked as inactive\n",
|
||||
queue);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are here, this is a shared queue and not all TIDs timed-out.
|
||||
* Remove the ones that did.
|
||||
*/
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
|
||||
int mac_queue = mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]];
|
||||
|
||||
mvmsta->tid_data[tid].txq_id = IEEE80211_INVAL_HW_QUEUE;
|
||||
mvm->queue_info[queue].hw_queue_to_mac80211 &= ~BIT(mac_queue);
|
||||
mvm->queue_info[queue].hw_queue_refcount--;
|
||||
mvm->queue_info[queue].tid_bitmap &= ~BIT(tid);
|
||||
mvmsta->tid_data[tid].is_tid_active = false;
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"Removing inactive TID %d from shared Q:%d\n",
|
||||
tid, queue);
|
||||
}
|
||||
|
||||
IWL_DEBUG_TX_QUEUES(mvm,
|
||||
"TXQ #%d left with tid bitmap 0x%x\n", queue,
|
||||
mvm->queue_info[queue].tid_bitmap);
|
||||
|
||||
/*
|
||||
* There may be different TIDs with the same mac queues, so make
|
||||
* sure all TIDs have existing corresponding mac queues enabled
|
||||
*/
|
||||
tid_bitmap = mvm->queue_info[queue].tid_bitmap;
|
||||
for_each_set_bit(tid, &tid_bitmap, IWL_MAX_TID_COUNT + 1) {
|
||||
mvm->queue_info[queue].hw_queue_to_mac80211 |=
|
||||
BIT(mvmsta->vif->hw_queue[tid_to_mac80211_ac[tid]]);
|
||||
}
|
||||
|
||||
/* TODO: if queue was shared - need to re-enable AGGs */
|
||||
}
|
||||
|
||||
void iwl_mvm_inactivity_check(struct iwl_mvm *mvm)
|
||||
{
|
||||
unsigned long timeout_queues_map = 0;
|
||||
unsigned long now = jiffies;
|
||||
int i;
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
for (i = 0; i < IWL_MAX_HW_QUEUES; i++)
|
||||
if (mvm->queue_info[i].hw_queue_refcount > 0)
|
||||
timeout_queues_map |= BIT(i);
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/*
|
||||
* If a queue time outs - mark it as INACTIVE (don't remove right away
|
||||
* if we don't have to.) This is an optimization in case traffic comes
|
||||
* later, and we don't HAVE to use a currently-inactive queue
|
||||
*/
|
||||
for_each_set_bit(i, &timeout_queues_map, IWL_MAX_HW_QUEUES) {
|
||||
struct ieee80211_sta *sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
u8 sta_id;
|
||||
int tid;
|
||||
unsigned long inactive_tid_bitmap = 0;
|
||||
unsigned long queue_tid_bitmap;
|
||||
|
||||
spin_lock_bh(&mvm->queue_info_lock);
|
||||
queue_tid_bitmap = mvm->queue_info[i].tid_bitmap;
|
||||
|
||||
/* If TXQ isn't in active use anyway - nothing to do here... */
|
||||
if (mvm->queue_info[i].status != IWL_MVM_QUEUE_READY &&
|
||||
mvm->queue_info[i].status != IWL_MVM_QUEUE_SHARED) {
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check to see if there are inactive TIDs on this queue */
|
||||
for_each_set_bit(tid, &queue_tid_bitmap,
|
||||
IWL_MAX_TID_COUNT + 1) {
|
||||
if (time_after(mvm->queue_info[i].last_frame_time[tid] +
|
||||
IWL_MVM_DQA_QUEUE_TIMEOUT, now))
|
||||
continue;
|
||||
|
||||
inactive_tid_bitmap |= BIT(tid);
|
||||
}
|
||||
spin_unlock_bh(&mvm->queue_info_lock);
|
||||
|
||||
/* If all TIDs are active - finish check on this queue */
|
||||
if (!inactive_tid_bitmap)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we are here - the queue hadn't been served recently and is
|
||||
* in use
|
||||
*/
|
||||
|
||||
sta_id = mvm->queue_info[i].ra_sta_id;
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
|
||||
/*
|
||||
* If the STA doesn't exist anymore, it isn't an error. It could
|
||||
* be that it was removed since getting the queues, and in this
|
||||
* case it should've inactivated its queues anyway.
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(sta))
|
||||
continue;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
|
||||
spin_lock_bh(&mvmsta->lock);
|
||||
spin_lock(&mvm->queue_info_lock);
|
||||
iwl_mvm_remove_inactive_tids(mvm, mvmsta, i,
|
||||
inactive_tid_bitmap);
|
||||
spin_unlock(&mvm->queue_info_lock);
|
||||
spin_unlock_bh(&mvmsta->lock);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
int iwl_mvm_send_lqm_cmd(struct ieee80211_vif *vif,
|
||||
enum iwl_lqm_cmd_operatrions operation,
|
||||
u32 duration, u32 timeout)
|
||||
|
|
|
@ -433,6 +433,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
/* 8000 Series */
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x10B0, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)},
|
||||
|
@ -454,6 +455,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x24F3, 0xD010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xD0B0, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0xB0B0, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)},
|
||||
|
@ -481,6 +484,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0110, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x1110, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x1130, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0130, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x1010, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0050, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0150, iwl8265_2ac_cfg)},
|
||||
|
@ -491,6 +496,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x24FD, 0x0810, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x9110, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x8130, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0910, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0930, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0950, iwl8265_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x24FD, 0x0850, iwl8265_2ac_cfg)},
|
||||
|
||||
/* 9000 Series */
|
||||
{IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)},
|
||||
|
@ -507,6 +516,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
|
|||
{IWL_PCI_DEVICE(0x2526, 0x1420, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl5165_2ac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
|
||||
|
||||
/* a000 Series */
|
||||
{IWL_PCI_DEVICE(0x2720, 0x0A10, iwla000_2ac_cfg)},
|
||||
#endif /* CONFIG_IWLMVM */
|
||||
|
||||
{0}
|
||||
|
@ -598,7 +610,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
const struct iwl_cfg *cfg_7265d __maybe_unused = NULL;
|
||||
const struct iwl_cfg *cfg_9260lc __maybe_unused = NULL;
|
||||
struct iwl_trans *iwl_trans;
|
||||
struct iwl_trans_pcie *trans_pcie;
|
||||
int ret;
|
||||
|
||||
iwl_trans = iwl_trans_pcie_alloc(pdev, ent, cfg);
|
||||
|
@ -636,12 +647,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
#endif
|
||||
|
||||
pci_set_drvdata(pdev, iwl_trans);
|
||||
iwl_trans->drv = iwl_drv_start(iwl_trans, cfg);
|
||||
|
||||
trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
|
||||
trans_pcie->drv = iwl_drv_start(iwl_trans, cfg);
|
||||
|
||||
if (IS_ERR(trans_pcie->drv)) {
|
||||
ret = PTR_ERR(trans_pcie->drv);
|
||||
if (IS_ERR(iwl_trans->drv)) {
|
||||
ret = PTR_ERR(iwl_trans->drv);
|
||||
goto out_free_trans;
|
||||
}
|
||||
|
||||
|
@ -680,7 +689,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
return 0;
|
||||
|
||||
out_free_drv:
|
||||
iwl_drv_stop(trans_pcie->drv);
|
||||
iwl_drv_stop(iwl_trans->drv);
|
||||
out_free_trans:
|
||||
iwl_trans_pcie_free(iwl_trans);
|
||||
return ret;
|
||||
|
@ -689,7 +698,6 @@ out_free_trans:
|
|||
static void iwl_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct iwl_trans *trans = pci_get_drvdata(pdev);
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
/* if RTPM was in use, restore it to the state before probe */
|
||||
if (trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
|
||||
|
@ -700,7 +708,7 @@ static void iwl_pci_remove(struct pci_dev *pdev)
|
|||
pm_runtime_forbid(trans->dev);
|
||||
}
|
||||
|
||||
iwl_drv_stop(trans_pcie->drv);
|
||||
iwl_drv_stop(trans->drv);
|
||||
|
||||
iwl_trans_pcie_free(trans);
|
||||
}
|
||||
|
|
|
@ -68,12 +68,14 @@ struct iwl_host_cmd;
|
|||
* struct iwl_rx_mem_buffer
|
||||
* @page_dma: bus address of rxb page
|
||||
* @page: driver's pointer to the rxb page
|
||||
* @invalid: rxb is in driver ownership - not owned by HW
|
||||
* @vid: index of this rxb in the global table
|
||||
*/
|
||||
struct iwl_rx_mem_buffer {
|
||||
dma_addr_t page_dma;
|
||||
struct page *page;
|
||||
u16 vid;
|
||||
bool invalid;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -230,15 +232,16 @@ struct iwl_queue {
|
|||
#define TFD_CMD_SLOTS 32
|
||||
|
||||
/*
|
||||
* The FH will write back to the first TB only, so we need
|
||||
* to copy some data into the buffer regardless of whether
|
||||
* it should be mapped or not. This indicates how big the
|
||||
* first TB must be to include the scratch buffer. Since
|
||||
* the scratch is 4 bytes at offset 12, it's 16 now. If we
|
||||
* make it bigger then allocations will be bigger and copy
|
||||
* slower, so that's probably not useful.
|
||||
* The FH will write back to the first TB only, so we need to copy some data
|
||||
* into the buffer regardless of whether it should be mapped or not.
|
||||
* This indicates how big the first TB must be to include the scratch buffer
|
||||
* and the assigned PN.
|
||||
* Since PN location is 16 bytes at offset 24, it's 40 now.
|
||||
* If we make it bigger then allocations will be bigger and copy slower, so
|
||||
* that's probably not useful.
|
||||
*/
|
||||
#define IWL_HCMD_SCRATCHBUF_SIZE 16
|
||||
#define IWL_FIRST_TB_SIZE 40
|
||||
#define IWL_FIRST_TB_SIZE_ALIGN ALIGN(IWL_FIRST_TB_SIZE, 64)
|
||||
|
||||
struct iwl_pcie_txq_entry {
|
||||
struct iwl_device_cmd *cmd;
|
||||
|
@ -248,20 +251,18 @@ struct iwl_pcie_txq_entry {
|
|||
struct iwl_cmd_meta meta;
|
||||
};
|
||||
|
||||
struct iwl_pcie_txq_scratch_buf {
|
||||
struct iwl_cmd_header hdr;
|
||||
u8 buf[8];
|
||||
__le32 scratch;
|
||||
struct iwl_pcie_first_tb_buf {
|
||||
u8 buf[IWL_FIRST_TB_SIZE_ALIGN];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_txq - Tx Queue for DMA
|
||||
* @q: generic Rx/Tx queue descriptor
|
||||
* @tfds: transmit frame descriptors (DMA memory)
|
||||
* @scratchbufs: start of command headers, including scratch buffers, for
|
||||
* @first_tb_bufs: start of command headers, including scratch buffers, for
|
||||
* the writeback -- this is DMA memory and an array holding one buffer
|
||||
* for each command on the queue
|
||||
* @scratchbufs_dma: DMA address for the scratchbufs start
|
||||
* @first_tb_dma: DMA address for the first_tb_bufs start
|
||||
* @entries: transmit entries (driver state)
|
||||
* @lock: queue lock
|
||||
* @stuck_timer: timer that fires if queue gets stuck
|
||||
|
@ -279,8 +280,8 @@ struct iwl_pcie_txq_scratch_buf {
|
|||
struct iwl_txq {
|
||||
struct iwl_queue q;
|
||||
struct iwl_tfd *tfds;
|
||||
struct iwl_pcie_txq_scratch_buf *scratchbufs;
|
||||
dma_addr_t scratchbufs_dma;
|
||||
struct iwl_pcie_first_tb_buf *first_tb_bufs;
|
||||
dma_addr_t first_tb_dma;
|
||||
struct iwl_pcie_txq_entry *entries;
|
||||
spinlock_t lock;
|
||||
unsigned long frozen_expiry_remainder;
|
||||
|
@ -296,10 +297,10 @@ struct iwl_txq {
|
|||
};
|
||||
|
||||
static inline dma_addr_t
|
||||
iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
|
||||
iwl_pcie_get_first_tb_dma(struct iwl_txq *txq, int idx)
|
||||
{
|
||||
return txq->scratchbufs_dma +
|
||||
sizeof(struct iwl_pcie_txq_scratch_buf) * idx;
|
||||
return txq->first_tb_dma +
|
||||
sizeof(struct iwl_pcie_first_tb_buf) * idx;
|
||||
}
|
||||
|
||||
struct iwl_tso_hdr_page {
|
||||
|
@ -313,7 +314,6 @@ struct iwl_tso_hdr_page {
|
|||
* @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues
|
||||
* @global_table: table mapping received VID from hw to rxb
|
||||
* @rba: allocator for RX replenishing
|
||||
* @drv - pointer to iwl_drv
|
||||
* @trans: pointer to the generic transport area
|
||||
* @scd_base_addr: scheduler sram base address in SRAM
|
||||
* @scd_bc_tbls: pointer to the byte count table of the scheduler
|
||||
|
@ -351,7 +351,6 @@ struct iwl_trans_pcie {
|
|||
struct iwl_rx_mem_buffer *global_table[RX_POOL_SIZE];
|
||||
struct iwl_rb_allocator rba;
|
||||
struct iwl_trans *trans;
|
||||
struct iwl_drv *drv;
|
||||
|
||||
struct net_device napi_dev;
|
||||
|
||||
|
@ -385,6 +384,8 @@ struct iwl_trans_pcie {
|
|||
wait_queue_head_t wait_command_queue;
|
||||
wait_queue_head_t d0i3_waitq;
|
||||
|
||||
u8 page_offs, dev_cmd_offs;
|
||||
|
||||
u8 cmd_queue;
|
||||
u8 cmd_fifo;
|
||||
unsigned int cmd_q_wdg_timeout;
|
||||
|
@ -471,6 +472,10 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
|
|||
unsigned int wdg_timeout);
|
||||
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
|
||||
bool configure_scd);
|
||||
void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id,
|
||||
bool shared_mode);
|
||||
void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans,
|
||||
struct iwl_txq *txq);
|
||||
int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
||||
struct iwl_device_cmd *dev_cmd, int txq_id);
|
||||
void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans);
|
||||
|
@ -496,7 +501,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans);
|
|||
/*****************************************************
|
||||
* Helpers
|
||||
******************************************************/
|
||||
static inline void iwl_disable_interrupts(struct iwl_trans *trans)
|
||||
static inline void _iwl_disable_interrupts(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
|
@ -519,7 +524,16 @@ static inline void iwl_disable_interrupts(struct iwl_trans *trans)
|
|||
IWL_DEBUG_ISR(trans, "Disabled interrupts\n");
|
||||
}
|
||||
|
||||
static inline void iwl_enable_interrupts(struct iwl_trans *trans)
|
||||
static inline void iwl_disable_interrupts(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
_iwl_disable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
}
|
||||
|
||||
static inline void _iwl_enable_interrupts(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
|
@ -542,6 +556,14 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void iwl_enable_interrupts(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
_iwl_enable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
}
|
||||
static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -673,4 +695,6 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
|
|||
int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans);
|
||||
int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans);
|
||||
|
||||
void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable);
|
||||
|
||||
#endif /* __iwl_trans_int_pcie_h__ */
|
||||
|
|
|
@ -161,21 +161,21 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr)
|
|||
return cpu_to_le32((u32)(dma_addr >> 8));
|
||||
}
|
||||
|
||||
static void iwl_pcie_write_prph_64_no_grab(struct iwl_trans *trans, u64 ofs,
|
||||
u64 val)
|
||||
{
|
||||
iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff);
|
||||
iwl_write_prph_no_grab(trans, ofs + 4, val >> 32);
|
||||
}
|
||||
|
||||
/*
|
||||
* iwl_pcie_rx_stop - stops the Rx DMA
|
||||
*/
|
||||
int iwl_pcie_rx_stop(struct iwl_trans *trans)
|
||||
{
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
|
||||
return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
|
||||
FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
|
||||
if (trans->cfg->mq_rx_supported) {
|
||||
iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0);
|
||||
return iwl_poll_prph_bit(trans, RFH_GEN_STATUS,
|
||||
RXF_DMA_IDLE, RXF_DMA_IDLE, 1000);
|
||||
} else {
|
||||
iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
|
||||
return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
|
||||
FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE,
|
||||
1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -211,12 +211,8 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
|
|||
if (trans->cfg->mq_rx_supported)
|
||||
iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id),
|
||||
rxq->write_actual);
|
||||
/*
|
||||
* write to FH_RSCSR_CHNL0_WPTR register even in MQ as a W/A to
|
||||
* hardware shadow registers bug - writing to RFH_Q_FRBDCB_WIDX will
|
||||
* not wake the NIC.
|
||||
*/
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
|
||||
else
|
||||
iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
|
||||
}
|
||||
|
||||
static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
|
||||
|
@ -237,10 +233,10 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
|
|||
}
|
||||
|
||||
/*
|
||||
* iwl_pcie_rxq_mq_restock - restock implementation for multi-queue rx
|
||||
* iwl_pcie_rxmq_restock - restock implementation for multi-queue rx
|
||||
*/
|
||||
static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
|
||||
struct iwl_rxq *rxq)
|
||||
static void iwl_pcie_rxmq_restock(struct iwl_trans *trans,
|
||||
struct iwl_rxq *rxq)
|
||||
{
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
|
||||
|
@ -263,7 +259,7 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
|
|||
rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
|
||||
list);
|
||||
list_del(&rxb->list);
|
||||
|
||||
rxb->invalid = false;
|
||||
/* 12 first bits are expected to be empty */
|
||||
WARN_ON(rxb->page_dma & DMA_BIT_MASK(12));
|
||||
/* Point to Rx buffer via next RBD in circular buffer */
|
||||
|
@ -285,10 +281,10 @@ static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
|
|||
}
|
||||
|
||||
/*
|
||||
* iwl_pcie_rxq_sq_restock - restock implementation for single queue rx
|
||||
* iwl_pcie_rxsq_restock - restock implementation for single queue rx
|
||||
*/
|
||||
static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans,
|
||||
struct iwl_rxq *rxq)
|
||||
static void iwl_pcie_rxsq_restock(struct iwl_trans *trans,
|
||||
struct iwl_rxq *rxq)
|
||||
{
|
||||
struct iwl_rx_mem_buffer *rxb;
|
||||
|
||||
|
@ -314,6 +310,7 @@ static void iwl_pcie_rxq_sq_restock(struct iwl_trans *trans,
|
|||
rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
|
||||
list);
|
||||
list_del(&rxb->list);
|
||||
rxb->invalid = false;
|
||||
|
||||
/* Point to Rx buffer via next RBD in circular buffer */
|
||||
bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
|
||||
|
@ -347,9 +344,9 @@ static
|
|||
void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
|
||||
{
|
||||
if (trans->cfg->mq_rx_supported)
|
||||
iwl_pcie_rxq_mq_restock(trans, rxq);
|
||||
iwl_pcie_rxmq_restock(trans, rxq);
|
||||
else
|
||||
iwl_pcie_rxq_sq_restock(trans, rxq);
|
||||
iwl_pcie_rxsq_restock(trans, rxq);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -764,6 +761,23 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
|
|||
iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE);
|
||||
}
|
||||
|
||||
void iwl_pcie_enable_rx_wake(struct iwl_trans *trans, bool enable)
|
||||
{
|
||||
/*
|
||||
* Turn on the chicken-bits that cause MAC wakeup for RX-related
|
||||
* values.
|
||||
* This costs some power, but needed for W/A 9000 integrated A-step
|
||||
* bug where shadow registers are not in the retention list and their
|
||||
* value is lost when NIC powers down
|
||||
*/
|
||||
if (trans->cfg->integrated) {
|
||||
iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL,
|
||||
CSR_MAC_SHADOW_REG_CTRL_RX_WAKE);
|
||||
iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTL2,
|
||||
CSR_MAC_SHADOW_REG_CTL2_RX_WAKE);
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -796,17 +810,17 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
|
||||
for (i = 0; i < trans->num_rx_queues; i++) {
|
||||
/* Tell device where to find RBD free table in DRAM */
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_FRBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].bd_dma);
|
||||
iwl_write_prph64_no_grab(trans,
|
||||
RFH_Q_FRBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].bd_dma);
|
||||
/* Tell device where to find RBD used table in DRAM */
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_URBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].used_bd_dma);
|
||||
iwl_write_prph64_no_grab(trans,
|
||||
RFH_Q_URBDCB_BA_LSB(i),
|
||||
trans_pcie->rxq[i].used_bd_dma);
|
||||
/* Tell device where in DRAM to update its Rx status */
|
||||
iwl_pcie_write_prph_64_no_grab(trans,
|
||||
RFH_Q_URBD_STTS_WPTR_LSB(i),
|
||||
trans_pcie->rxq[i].rb_stts_dma);
|
||||
iwl_write_prph64_no_grab(trans,
|
||||
RFH_Q_URBD_STTS_WPTR_LSB(i),
|
||||
trans_pcie->rxq[i].rb_stts_dma);
|
||||
/* Reset device indice tables */
|
||||
iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_WIDX(i), 0);
|
||||
iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_RIDX(i), 0);
|
||||
|
@ -815,33 +829,32 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
enabled |= BIT(i) | BIT(i + 16);
|
||||
}
|
||||
|
||||
/* restock default queue */
|
||||
iwl_pcie_rxq_mq_restock(trans, &trans_pcie->rxq[0]);
|
||||
|
||||
/*
|
||||
* Enable Rx DMA
|
||||
* Single frame mode
|
||||
* Rx buffer size 4 or 8k or 12k
|
||||
* Min RB size 4 or 8
|
||||
* Drop frames that exceed RB size
|
||||
* 512 RBDs
|
||||
*/
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG,
|
||||
RFH_DMA_EN_ENABLE_VAL |
|
||||
rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
|
||||
RFH_DMA_EN_ENABLE_VAL | rb_size |
|
||||
RFH_RXF_DMA_MIN_RB_4_8 |
|
||||
RFH_RXF_DMA_DROP_TOO_LARGE_MASK |
|
||||
RFH_RXF_DMA_RBDCB_SIZE_512);
|
||||
|
||||
/*
|
||||
* Activate DMA snooping.
|
||||
* Set RX DMA chunk size to 64B
|
||||
* Set RX DMA chunk size to 64B for IOSF and 128B for PCIe
|
||||
* Default queue is 0
|
||||
*/
|
||||
iwl_write_prph_no_grab(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
|
||||
(DEFAULT_RXQ_NUM <<
|
||||
RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS) |
|
||||
RFH_GEN_CFG_SERVICE_DMA_SNOOP);
|
||||
RFH_GEN_CFG_SERVICE_DMA_SNOOP |
|
||||
(trans->cfg->integrated ?
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_64 :
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_128) <<
|
||||
RFH_GEN_CFG_RB_CHUNK_SIZE_POS);
|
||||
/* Enable the relevant rx queues */
|
||||
iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled);
|
||||
|
||||
|
@ -849,6 +862,8 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
|
|||
|
||||
/* Set interrupt coalescing timer to default (2048 usecs) */
|
||||
iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
|
||||
|
||||
iwl_pcie_enable_rx_wake(trans, true);
|
||||
}
|
||||
|
||||
static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
|
||||
|
@ -939,16 +954,18 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
|
|||
else
|
||||
list_add(&rxb->list, &def_rxq->rx_used);
|
||||
trans_pcie->global_table[i] = rxb;
|
||||
rxb->vid = (u16)i;
|
||||
rxb->vid = (u16)(i + 1);
|
||||
rxb->invalid = true;
|
||||
}
|
||||
|
||||
iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq);
|
||||
if (trans->cfg->mq_rx_supported) {
|
||||
|
||||
if (trans->cfg->mq_rx_supported)
|
||||
iwl_pcie_rx_mq_hw_init(trans);
|
||||
} else {
|
||||
iwl_pcie_rxq_sq_restock(trans, def_rxq);
|
||||
else
|
||||
iwl_pcie_rx_hw_init(trans, def_rxq);
|
||||
}
|
||||
|
||||
iwl_pcie_rxq_restock(trans, def_rxq);
|
||||
|
||||
spin_lock(&def_rxq->lock);
|
||||
iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq);
|
||||
|
@ -1087,6 +1104,9 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
|
|||
if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
|
||||
break;
|
||||
|
||||
WARN_ON((le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_RXQ_MASK) >>
|
||||
FH_RSCSR_RXQ_POS != rxq->id);
|
||||
|
||||
IWL_DEBUG_RX(trans,
|
||||
"cmd at offset %d: %s (0x%.2x, seq 0x%x)\n",
|
||||
rxcb._offset,
|
||||
|
@ -1224,10 +1244,19 @@ restart:
|
|||
*/
|
||||
u16 vid = le32_to_cpu(rxq->used_bd[i]) & 0x0FFF;
|
||||
|
||||
if (WARN(vid >= ARRAY_SIZE(trans_pcie->global_table),
|
||||
"Invalid rxb index from HW %u\n", (u32)vid))
|
||||
if (WARN(!vid ||
|
||||
vid > ARRAY_SIZE(trans_pcie->global_table),
|
||||
"Invalid rxb index from HW %u\n", (u32)vid)) {
|
||||
iwl_force_nmi(trans);
|
||||
goto out;
|
||||
rxb = trans_pcie->global_table[vid];
|
||||
}
|
||||
rxb = trans_pcie->global_table[vid - 1];
|
||||
if (WARN(rxb->invalid,
|
||||
"Invalid rxb from HW %u\n", (u32)vid)) {
|
||||
iwl_force_nmi(trans);
|
||||
goto out;
|
||||
}
|
||||
rxb->invalid = true;
|
||||
} else {
|
||||
rxb = rxq->queue[i];
|
||||
rxq->queue[i] = NULL;
|
||||
|
@ -1507,7 +1536,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
|||
* have anything to service
|
||||
*/
|
||||
if (test_bit(STATUS_INT_ENABLED, &trans->status))
|
||||
iwl_enable_interrupts(trans);
|
||||
_iwl_enable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
lock_map_release(&trans->sync_cmd_lockdep_map);
|
||||
return IRQ_NONE;
|
||||
|
@ -1699,15 +1728,17 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
|
|||
inta & ~trans_pcie->inta_mask);
|
||||
}
|
||||
|
||||
/* we are loading the firmware, enable FH_TX interrupt only */
|
||||
if (handled & CSR_INT_BIT_FH_TX)
|
||||
iwl_enable_fw_load_int(trans);
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
/* only Re-enable all interrupt if disabled by irq */
|
||||
else if (test_bit(STATUS_INT_ENABLED, &trans->status))
|
||||
iwl_enable_interrupts(trans);
|
||||
if (test_bit(STATUS_INT_ENABLED, &trans->status))
|
||||
_iwl_enable_interrupts(trans);
|
||||
/* we are loading the firmware, enable FH_TX interrupt only */
|
||||
else if (handled & CSR_INT_BIT_FH_TX)
|
||||
iwl_enable_fw_load_int(trans);
|
||||
/* Re-enable RF_KILL if it occurred */
|
||||
else if (handled & CSR_INT_BIT_RF_KILL)
|
||||
iwl_enable_rfkill_int(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
out:
|
||||
lock_map_release(&trans->sync_cmd_lockdep_map);
|
||||
|
@ -1771,7 +1802,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
|
|||
return;
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
iwl_disable_interrupts(trans);
|
||||
_iwl_disable_interrupts(trans);
|
||||
|
||||
memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
|
||||
|
||||
|
@ -1787,7 +1818,7 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
|
|||
trans_pcie->use_ict = true;
|
||||
trans_pcie->ict_index = 0;
|
||||
iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
|
||||
iwl_enable_interrupts(trans);
|
||||
_iwl_enable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -608,18 +608,10 @@ static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
|
|||
/*
|
||||
* ucode
|
||||
*/
|
||||
static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
|
||||
dma_addr_t phy_addr, u32 byte_cnt)
|
||||
static void iwl_pcie_load_firmware_chunk_fh(struct iwl_trans *trans,
|
||||
u32 dst_addr, dma_addr_t phy_addr,
|
||||
u32 byte_cnt)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
trans_pcie->ucode_write_complete = false;
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return -EIO;
|
||||
|
||||
iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
|
||||
|
||||
|
@ -642,7 +634,50 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
|
|||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
|
||||
FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
|
||||
}
|
||||
|
||||
static void iwl_pcie_load_firmware_chunk_tfh(struct iwl_trans *trans,
|
||||
u32 dst_addr, dma_addr_t phy_addr,
|
||||
u32 byte_cnt)
|
||||
{
|
||||
/* Stop DMA channel */
|
||||
iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, 0);
|
||||
|
||||
/* Configure SRAM address */
|
||||
iwl_write32(trans, TFH_SRV_DMA_CHNL0_SRAM_ADDR,
|
||||
dst_addr);
|
||||
|
||||
/* Configure DRAM address - 64 bit */
|
||||
iwl_write64(trans, TFH_SRV_DMA_CHNL0_DRAM_ADDR, phy_addr);
|
||||
|
||||
/* Configure byte count to transfer */
|
||||
iwl_write32(trans, TFH_SRV_DMA_CHNL0_BC, byte_cnt);
|
||||
|
||||
/* Enable the DRAM2SRAM to start */
|
||||
iwl_write32(trans, TFH_SRV_DMA_CHNL0_CTRL, TFH_SRV_DMA_SNOOP |
|
||||
TFH_SRV_DMA_TO_DRIVER |
|
||||
TFH_SRV_DMA_START);
|
||||
}
|
||||
|
||||
static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans,
|
||||
u32 dst_addr, dma_addr_t phy_addr,
|
||||
u32 byte_cnt)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
trans_pcie->ucode_write_complete = false;
|
||||
|
||||
if (!iwl_trans_grab_nic_access(trans, &flags))
|
||||
return -EIO;
|
||||
|
||||
if (trans->cfg->use_tfh)
|
||||
iwl_pcie_load_firmware_chunk_tfh(trans, dst_addr, phy_addr,
|
||||
byte_cnt);
|
||||
else
|
||||
iwl_pcie_load_firmware_chunk_fh(trans, dst_addr, phy_addr,
|
||||
byte_cnt);
|
||||
iwl_trans_release_nic_access(trans, &flags);
|
||||
|
||||
ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
|
||||
|
@ -801,6 +836,8 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans,
|
|||
|
||||
*first_ucode_section = last_read_idx;
|
||||
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
if (cpu == 1)
|
||||
iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF);
|
||||
else
|
||||
|
@ -980,6 +1017,8 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
|
|||
iwl_pcie_apply_destination(trans);
|
||||
}
|
||||
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
/* release CPU reset */
|
||||
iwl_write32(trans, CSR_RESET, 0);
|
||||
|
||||
|
@ -1033,9 +1072,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
|||
was_hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
|
||||
/* tell the device to stop sending interrupts */
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
/* device going down, Stop using ICT table */
|
||||
iwl_pcie_disable_ict(trans);
|
||||
|
@ -1079,9 +1116,7 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power)
|
|||
* the time, unless the interrupt is ACKed even if the interrupt
|
||||
* should be masked. Re-ACK all the interrupts here.
|
||||
*/
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
/* clear all status bits */
|
||||
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
|
||||
|
@ -1215,7 +1250,6 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
|
|||
ret = iwl_pcie_load_given_ucode_8000(trans, fw);
|
||||
else
|
||||
ret = iwl_pcie_load_given_ucode(trans, fw);
|
||||
iwl_enable_interrupts(trans);
|
||||
|
||||
/* re-check RF-Kill state since we may have missed the interrupt */
|
||||
hw_rfkill = iwl_is_rfkill_set(trans);
|
||||
|
@ -1286,6 +1320,8 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test,
|
|||
iwl_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
|
||||
|
||||
iwl_pcie_enable_rx_wake(trans, false);
|
||||
|
||||
if (reset) {
|
||||
/*
|
||||
* reset TX queues -- some of their registers reset during S3
|
||||
|
@ -1311,6 +1347,8 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
|
|||
return 0;
|
||||
}
|
||||
|
||||
iwl_pcie_enable_rx_wake(trans, true);
|
||||
|
||||
/*
|
||||
* Also enables interrupts - none will happen as the device doesn't
|
||||
* know we're waking it up, only when the opmode actually tells it
|
||||
|
@ -1389,8 +1427,12 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie)
|
|||
|
||||
max_rx_vector = trans_pcie->allocated_vector - 1;
|
||||
|
||||
if (!trans_pcie->msix_enabled)
|
||||
if (!trans_pcie->msix_enabled) {
|
||||
if (trans->cfg->mq_rx_supported)
|
||||
iwl_write_prph(trans, UREG_CHICK,
|
||||
UREG_CHICK_MSI_ENABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
iwl_write_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE);
|
||||
|
||||
|
@ -1567,15 +1609,11 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
|
|||
mutex_lock(&trans_pcie->mutex);
|
||||
|
||||
/* disable interrupts - don't enable HW RF kill interrupt */
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
iwl_pcie_apm_stop(trans, true);
|
||||
|
||||
spin_lock(&trans_pcie->irq_lock);
|
||||
iwl_disable_interrupts(trans);
|
||||
spin_unlock(&trans_pcie->irq_lock);
|
||||
|
||||
iwl_pcie_disable_ict(trans);
|
||||
|
||||
|
@ -1639,6 +1677,9 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
|
|||
trans_pcie->scd_set_active = trans_cfg->scd_set_active;
|
||||
trans_pcie->sw_csum_tx = trans_cfg->sw_csum_tx;
|
||||
|
||||
trans_pcie->page_offs = trans_cfg->cb_data_offs;
|
||||
trans_pcie->dev_cmd_offs = trans_cfg->cb_data_offs + sizeof(void *);
|
||||
|
||||
trans->command_groups = trans_cfg->command_groups;
|
||||
trans->command_groups_size = trans_cfg->command_groups_size;
|
||||
|
||||
|
@ -1909,6 +1950,48 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block)
|
|||
|
||||
#define IWL_FLUSH_WAIT_MS 2000
|
||||
|
||||
void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
u32 scd_sram_addr;
|
||||
u8 buf[16];
|
||||
int cnt;
|
||||
|
||||
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
|
||||
txq->q.read_ptr, txq->q.write_ptr);
|
||||
|
||||
scd_sram_addr = trans_pcie->scd_base_addr +
|
||||
SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
|
||||
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
|
||||
|
||||
iwl_print_hex_error(trans, buf, sizeof(buf));
|
||||
|
||||
for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
|
||||
IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
|
||||
iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
|
||||
|
||||
for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
|
||||
u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
|
||||
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
|
||||
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
|
||||
u32 tbl_dw =
|
||||
iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
|
||||
SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
|
||||
|
||||
if (cnt & 0x1)
|
||||
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
|
||||
else
|
||||
tbl_dw = tbl_dw & 0x0000FFFF;
|
||||
|
||||
IWL_ERR(trans,
|
||||
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
|
||||
cnt, active ? "" : "in", fifo, tbl_dw,
|
||||
iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) &
|
||||
(TFD_QUEUE_SIZE_MAX - 1),
|
||||
iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
|
||||
}
|
||||
}
|
||||
|
||||
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
@ -1916,8 +1999,6 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
|
|||
struct iwl_queue *q;
|
||||
int cnt;
|
||||
unsigned long now = jiffies;
|
||||
u32 scd_sram_addr;
|
||||
u8 buf[16];
|
||||
int ret = 0;
|
||||
|
||||
/* waiting for all the tx frames complete might take a while */
|
||||
|
@ -1957,42 +2038,8 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
|
|||
IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
|
||||
txq->q.read_ptr, txq->q.write_ptr);
|
||||
|
||||
scd_sram_addr = trans_pcie->scd_base_addr +
|
||||
SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
|
||||
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
|
||||
|
||||
iwl_print_hex_error(trans, buf, sizeof(buf));
|
||||
|
||||
for (cnt = 0; cnt < FH_TCSR_CHNL_NUM; cnt++)
|
||||
IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", cnt,
|
||||
iwl_read_direct32(trans, FH_TX_TRB_REG(cnt)));
|
||||
|
||||
for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) {
|
||||
u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(cnt));
|
||||
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
|
||||
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
|
||||
u32 tbl_dw =
|
||||
iwl_trans_read_mem32(trans, trans_pcie->scd_base_addr +
|
||||
SCD_TRANS_TBL_OFFSET_QUEUE(cnt));
|
||||
|
||||
if (cnt & 0x1)
|
||||
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
|
||||
else
|
||||
tbl_dw = tbl_dw & 0x0000FFFF;
|
||||
|
||||
IWL_ERR(trans,
|
||||
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
|
||||
cnt, active ? "" : "in", fifo, tbl_dw,
|
||||
iwl_read_prph(trans, SCD_QUEUE_RDPTR(cnt)) &
|
||||
(TFD_QUEUE_SIZE_MAX - 1),
|
||||
iwl_read_prph(trans, SCD_QUEUE_WRPTR(cnt)));
|
||||
}
|
||||
if (ret)
|
||||
iwl_trans_pcie_log_scd_error(trans, txq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -2741,6 +2788,8 @@ static const struct iwl_trans_ops trans_ops_pcie = {
|
|||
.txq_disable = iwl_trans_pcie_txq_disable,
|
||||
.txq_enable = iwl_trans_pcie_txq_enable,
|
||||
|
||||
.txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode,
|
||||
|
||||
.wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty,
|
||||
.freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer,
|
||||
.block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs,
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
* Tx queue resumed.
|
||||
*
|
||||
***************************************************/
|
||||
|
||||
static int iwl_queue_space(const struct iwl_queue *q)
|
||||
{
|
||||
unsigned int max;
|
||||
|
@ -154,10 +155,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
|
|||
struct iwl_txq *txq = (void *)data;
|
||||
struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
|
||||
struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
|
||||
u32 scd_sram_addr = trans_pcie->scd_base_addr +
|
||||
SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
|
||||
u8 buf[16];
|
||||
int i;
|
||||
|
||||
spin_lock(&txq->lock);
|
||||
/* check if triggered erroneously */
|
||||
|
@ -169,38 +166,8 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
|
|||
|
||||
IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
|
||||
jiffies_to_msecs(txq->wd_timeout));
|
||||
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
|
||||
txq->q.read_ptr, txq->q.write_ptr);
|
||||
|
||||
iwl_trans_read_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
|
||||
|
||||
iwl_print_hex_error(trans, buf, sizeof(buf));
|
||||
|
||||
for (i = 0; i < FH_TCSR_CHNL_NUM; i++)
|
||||
IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i,
|
||||
iwl_read_direct32(trans, FH_TX_TRB_REG(i)));
|
||||
|
||||
for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
|
||||
u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i));
|
||||
u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
|
||||
bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
|
||||
u32 tbl_dw =
|
||||
iwl_trans_read_mem32(trans,
|
||||
trans_pcie->scd_base_addr +
|
||||
SCD_TRANS_TBL_OFFSET_QUEUE(i));
|
||||
|
||||
if (i & 0x1)
|
||||
tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
|
||||
else
|
||||
tbl_dw = tbl_dw & 0x0000FFFF;
|
||||
|
||||
IWL_ERR(trans,
|
||||
"Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
|
||||
i, active ? "" : "in", fifo, tbl_dw,
|
||||
iwl_read_prph(trans, SCD_QUEUE_RDPTR(i)) &
|
||||
(TFD_QUEUE_SIZE_MAX - 1),
|
||||
iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
|
||||
}
|
||||
iwl_trans_pcie_log_scd_error(trans, txq);
|
||||
|
||||
iwl_force_nmi(trans);
|
||||
}
|
||||
|
@ -393,7 +360,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
|
|||
return;
|
||||
}
|
||||
|
||||
/* first TB is never freed - it's the scratchbuf data */
|
||||
/* first TB is never freed - it's the bidirectional DMA data */
|
||||
|
||||
for (i = 1; i < num_tbs; i++) {
|
||||
if (meta->flags & BIT(i + CMD_TB_BITMAP_POS))
|
||||
|
@ -491,7 +458,7 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
|
|||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
|
||||
size_t scratchbuf_sz;
|
||||
size_t tb0_buf_sz;
|
||||
int i;
|
||||
|
||||
if (WARN_ON(txq->entries || txq->tfds))
|
||||
|
@ -526,17 +493,14 @@ static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
|
|||
if (!txq->tfds)
|
||||
goto error;
|
||||
|
||||
BUILD_BUG_ON(IWL_HCMD_SCRATCHBUF_SIZE != sizeof(*txq->scratchbufs));
|
||||
BUILD_BUG_ON(offsetof(struct iwl_pcie_txq_scratch_buf, scratch) !=
|
||||
sizeof(struct iwl_cmd_header) +
|
||||
offsetof(struct iwl_tx_cmd, scratch));
|
||||
BUILD_BUG_ON(IWL_FIRST_TB_SIZE_ALIGN != sizeof(*txq->first_tb_bufs));
|
||||
|
||||
scratchbuf_sz = sizeof(*txq->scratchbufs) * slots_num;
|
||||
tb0_buf_sz = sizeof(*txq->first_tb_bufs) * slots_num;
|
||||
|
||||
txq->scratchbufs = dma_alloc_coherent(trans->dev, scratchbuf_sz,
|
||||
&txq->scratchbufs_dma,
|
||||
txq->first_tb_bufs = dma_alloc_coherent(trans->dev, tb0_buf_sz,
|
||||
&txq->first_tb_dma,
|
||||
GFP_KERNEL);
|
||||
if (!txq->scratchbufs)
|
||||
if (!txq->first_tb_bufs)
|
||||
goto err_free_tfds;
|
||||
|
||||
txq->q.id = txq_id;
|
||||
|
@ -578,22 +542,27 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
|
|||
* Tell nic where to find circular buffer of Tx Frame Descriptors for
|
||||
* given Tx queue, and enable the DMA channel used for that queue.
|
||||
* Circular buffer (TFD queue in DRAM) physical base address */
|
||||
iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
|
||||
txq->q.dma_addr >> 8);
|
||||
if (trans->cfg->use_tfh)
|
||||
iwl_write_direct64(trans,
|
||||
FH_MEM_CBBC_QUEUE(trans, txq_id),
|
||||
txq->q.dma_addr);
|
||||
else
|
||||
iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id),
|
||||
txq->q.dma_addr >> 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_pcie_free_tso_page(struct sk_buff *skb)
|
||||
static void iwl_pcie_free_tso_page(struct iwl_trans_pcie *trans_pcie,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct page **page_ptr;
|
||||
|
||||
if (info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA]) {
|
||||
struct page *page =
|
||||
info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA];
|
||||
page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs);
|
||||
|
||||
__free_page(page);
|
||||
info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = NULL;
|
||||
if (*page_ptr) {
|
||||
__free_page(*page_ptr);
|
||||
*page_ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,7 +608,7 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
|
|||
if (WARN_ON_ONCE(!skb))
|
||||
continue;
|
||||
|
||||
iwl_pcie_free_tso_page(skb);
|
||||
iwl_pcie_free_tso_page(trans_pcie, skb);
|
||||
}
|
||||
iwl_pcie_txq_free_tfd(trans, txq);
|
||||
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr);
|
||||
|
@ -708,8 +677,8 @@ static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
|
|||
txq->tfds = NULL;
|
||||
|
||||
dma_free_coherent(dev,
|
||||
sizeof(*txq->scratchbufs) * txq->q.n_window,
|
||||
txq->scratchbufs, txq->scratchbufs_dma);
|
||||
sizeof(*txq->first_tb_bufs) * txq->q.n_window,
|
||||
txq->first_tb_bufs, txq->first_tb_dma);
|
||||
}
|
||||
|
||||
kfree(txq->entries);
|
||||
|
@ -786,9 +755,14 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
|
|||
for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
|
||||
txq_id++) {
|
||||
struct iwl_txq *txq = &trans_pcie->txq[txq_id];
|
||||
|
||||
iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
|
||||
txq->q.dma_addr >> 8);
|
||||
if (trans->cfg->use_tfh)
|
||||
iwl_write_direct64(trans,
|
||||
FH_MEM_CBBC_QUEUE(trans, txq_id),
|
||||
txq->q.dma_addr);
|
||||
else
|
||||
iwl_write_direct32(trans,
|
||||
FH_MEM_CBBC_QUEUE(trans, txq_id),
|
||||
txq->q.dma_addr >> 8);
|
||||
iwl_pcie_txq_unmap(trans, txq_id);
|
||||
txq->q.read_ptr = 0;
|
||||
txq->q.write_ptr = 0;
|
||||
|
@ -996,6 +970,12 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
|
|||
}
|
||||
}
|
||||
|
||||
if (trans->cfg->use_tfh)
|
||||
iwl_write_direct32(trans, TFH_TRANSFER_MODE,
|
||||
TFH_TRANSFER_MAX_PENDING_REQ |
|
||||
TFH_CHUNK_SIZE_128 |
|
||||
TFH_CHUNK_SPLIT_MODE);
|
||||
|
||||
iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE);
|
||||
if (trans->cfg->base_params->num_of_queues > 20)
|
||||
iwl_set_bits_prph(trans, SCD_GP_CTRL,
|
||||
|
@ -1084,7 +1064,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
|||
if (WARN_ON_ONCE(!skb))
|
||||
continue;
|
||||
|
||||
iwl_pcie_free_tso_page(skb);
|
||||
iwl_pcie_free_tso_page(trans_pcie, skb);
|
||||
|
||||
__skb_queue_tail(skbs, skb);
|
||||
|
||||
|
@ -1115,17 +1095,17 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
|
|||
|
||||
while (!skb_queue_empty(&overflow_skbs)) {
|
||||
struct sk_buff *skb = __skb_dequeue(&overflow_skbs);
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1;
|
||||
struct iwl_device_cmd *dev_cmd =
|
||||
info->driver_data[dev_cmd_idx];
|
||||
struct iwl_device_cmd *dev_cmd_ptr;
|
||||
|
||||
dev_cmd_ptr = *(void **)((u8 *)skb->cb +
|
||||
trans_pcie->dev_cmd_offs);
|
||||
|
||||
/*
|
||||
* Note that we can very well be overflowing again.
|
||||
* In that case, iwl_queue_space will be small again
|
||||
* and we won't wake mac80211's queue.
|
||||
*/
|
||||
iwl_trans_pcie_tx(trans, skb, dev_cmd, txq_id);
|
||||
iwl_trans_pcie_tx(trans, skb, dev_cmd_ptr, txq_id);
|
||||
}
|
||||
spin_lock_bh(&txq->lock);
|
||||
|
||||
|
@ -1354,6 +1334,15 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
|
|||
txq->active = true;
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_txq_set_shared_mode(struct iwl_trans *trans, u32 txq_id,
|
||||
bool shared_mode)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct iwl_txq *txq = &trans_pcie->txq[txq_id];
|
||||
|
||||
txq->ampdu = !shared_mode;
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
|
||||
bool configure_scd)
|
||||
{
|
||||
|
@ -1413,7 +1402,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
void *dup_buf = NULL;
|
||||
dma_addr_t phys_addr;
|
||||
int idx;
|
||||
u16 copy_size, cmd_size, scratch_size;
|
||||
u16 copy_size, cmd_size, tb0_size;
|
||||
bool had_nocopy = false;
|
||||
u8 group_id = iwl_cmd_groupid(cmd->id);
|
||||
int i, ret;
|
||||
|
@ -1444,9 +1433,9 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
if (!cmd->len[i])
|
||||
continue;
|
||||
|
||||
/* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
|
||||
if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) {
|
||||
int copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;
|
||||
/* need at least IWL_FIRST_TB_SIZE copied */
|
||||
if (copy_size < IWL_FIRST_TB_SIZE) {
|
||||
int copy = IWL_FIRST_TB_SIZE - copy_size;
|
||||
|
||||
if (copy > cmdlen[i])
|
||||
copy = cmdlen[i];
|
||||
|
@ -1567,8 +1556,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
}
|
||||
|
||||
/*
|
||||
* Otherwise we need at least IWL_HCMD_SCRATCHBUF_SIZE copied
|
||||
* in total (for the scratchbuf handling), but copy up to what
|
||||
* Otherwise we need at least IWL_FIRST_TB_SIZE copied
|
||||
* in total (for bi-directional DMA), but copy up to what
|
||||
* we can fit into the payload for debug dump purposes.
|
||||
*/
|
||||
copy = min_t(int, TFD_MAX_PAYLOAD_SIZE - cmd_pos, cmd->len[i]);
|
||||
|
@ -1577,8 +1566,8 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
cmd_pos += copy;
|
||||
|
||||
/* However, treat copy_size the proper way, we need it below */
|
||||
if (copy_size < IWL_HCMD_SCRATCHBUF_SIZE) {
|
||||
copy = IWL_HCMD_SCRATCHBUF_SIZE - copy_size;
|
||||
if (copy_size < IWL_FIRST_TB_SIZE) {
|
||||
copy = IWL_FIRST_TB_SIZE - copy_size;
|
||||
|
||||
if (copy > cmd->len[i])
|
||||
copy = cmd->len[i];
|
||||
|
@ -1593,18 +1582,18 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
le16_to_cpu(out_cmd->hdr.sequence),
|
||||
cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
|
||||
|
||||
/* start the TFD with the scratchbuf */
|
||||
scratch_size = min_t(int, copy_size, IWL_HCMD_SCRATCHBUF_SIZE);
|
||||
memcpy(&txq->scratchbufs[q->write_ptr], &out_cmd->hdr, scratch_size);
|
||||
/* start the TFD with the minimum copy bytes */
|
||||
tb0_size = min_t(int, copy_size, IWL_FIRST_TB_SIZE);
|
||||
memcpy(&txq->first_tb_bufs[idx], &out_cmd->hdr, tb0_size);
|
||||
iwl_pcie_txq_build_tfd(trans, txq,
|
||||
iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr),
|
||||
scratch_size, true);
|
||||
iwl_pcie_get_first_tb_dma(txq, idx),
|
||||
tb0_size, true);
|
||||
|
||||
/* map first command fragment, if any remains */
|
||||
if (copy_size > scratch_size) {
|
||||
if (copy_size > tb0_size) {
|
||||
phys_addr = dma_map_single(trans->dev,
|
||||
((u8 *)&out_cmd->hdr) + scratch_size,
|
||||
copy_size - scratch_size,
|
||||
((u8 *)&out_cmd->hdr) + tb0_size,
|
||||
copy_size - tb0_size,
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(trans->dev, phys_addr)) {
|
||||
iwl_pcie_tfd_unmap(trans, out_meta,
|
||||
|
@ -1614,7 +1603,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
|
|||
}
|
||||
|
||||
iwl_pcie_txq_build_tfd(trans, txq, phys_addr,
|
||||
copy_size - scratch_size, false);
|
||||
copy_size - tb0_size, false);
|
||||
}
|
||||
|
||||
/* map the remaining (adjusted) nocopy/dup fragments */
|
||||
|
@ -1959,7 +1948,7 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
trace_iwlwifi_dev_tx(trans->dev, skb,
|
||||
&txq->tfds[txq->q.write_ptr],
|
||||
sizeof(struct iwl_tfd),
|
||||
&dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
|
||||
&dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
|
||||
skb->data + hdr_len, tb2_len);
|
||||
trace_iwlwifi_dev_tx_data(trans->dev, skb,
|
||||
hdr_len, skb->len - hdr_len);
|
||||
|
@ -2015,7 +2004,6 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
struct iwl_cmd_meta *out_meta,
|
||||
struct iwl_device_cmd *dev_cmd, u16 tb1_len)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room;
|
||||
|
@ -2024,6 +2012,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
u16 length, iv_len, amsdu_pad;
|
||||
u8 *start_hdr;
|
||||
struct iwl_tso_hdr_page *hdr_page;
|
||||
struct page **page_ptr;
|
||||
int ret;
|
||||
struct tso_t tso;
|
||||
|
||||
|
@ -2035,7 +2024,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
trace_iwlwifi_dev_tx(trans->dev, skb,
|
||||
&txq->tfds[txq->q.write_ptr],
|
||||
sizeof(struct iwl_tfd),
|
||||
&dev_cmd->hdr, IWL_HCMD_SCRATCHBUF_SIZE + tb1_len,
|
||||
&dev_cmd->hdr, IWL_FIRST_TB_SIZE + tb1_len,
|
||||
NULL, 0);
|
||||
|
||||
ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb);
|
||||
|
@ -2054,7 +2043,8 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
|
||||
get_page(hdr_page->page);
|
||||
start_hdr = hdr_page->pos;
|
||||
info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA] = hdr_page->page;
|
||||
page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs);
|
||||
*page_ptr = hdr_page->page;
|
||||
memcpy(hdr_page->pos, skb->data + hdr_len, iv_len);
|
||||
hdr_page->pos += iv_len;
|
||||
|
||||
|
@ -2264,10 +2254,12 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
|
||||
/* don't put the packet on the ring, if there is no room */
|
||||
if (unlikely(iwl_queue_space(q) < 3)) {
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_device_cmd **dev_cmd_ptr;
|
||||
|
||||
info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA + 1] =
|
||||
dev_cmd;
|
||||
dev_cmd_ptr = (void *)((u8 *)skb->cb +
|
||||
trans_pcie->dev_cmd_offs);
|
||||
|
||||
*dev_cmd_ptr = dev_cmd;
|
||||
__skb_queue_tail(&txq->overflow_q, skb);
|
||||
|
||||
spin_unlock(&txq->lock);
|
||||
|
@ -2294,7 +2286,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
|
||||
INDEX_TO_SEQ(q->write_ptr)));
|
||||
|
||||
tb0_phys = iwl_pcie_get_scratchbuf_dma(txq, q->write_ptr);
|
||||
tb0_phys = iwl_pcie_get_first_tb_dma(txq, q->write_ptr);
|
||||
scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) +
|
||||
offsetof(struct iwl_tx_cmd, scratch);
|
||||
|
||||
|
@ -2312,7 +2304,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
* setup of the first TB)
|
||||
*/
|
||||
len = sizeof(struct iwl_tx_cmd) + sizeof(struct iwl_cmd_header) +
|
||||
hdr_len - IWL_HCMD_SCRATCHBUF_SIZE;
|
||||
hdr_len - IWL_FIRST_TB_SIZE;
|
||||
/* do not align A-MSDU to dword as the subframe header aligns it */
|
||||
amsdu = ieee80211_is_data_qos(fc) &&
|
||||
(*ieee80211_get_qos_ctl(hdr) &
|
||||
|
@ -2326,17 +2318,17 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
|
|||
tb1_len = len;
|
||||
}
|
||||
|
||||
/* The first TB points to the scratchbuf data - min_copy bytes */
|
||||
memcpy(&txq->scratchbufs[q->write_ptr], &dev_cmd->hdr,
|
||||
IWL_HCMD_SCRATCHBUF_SIZE);
|
||||
/* The first TB points to bi-directional DMA data */
|
||||
memcpy(&txq->first_tb_bufs[q->write_ptr], &dev_cmd->hdr,
|
||||
IWL_FIRST_TB_SIZE);
|
||||
iwl_pcie_txq_build_tfd(trans, txq, tb0_phys,
|
||||
IWL_HCMD_SCRATCHBUF_SIZE, true);
|
||||
IWL_FIRST_TB_SIZE, true);
|
||||
|
||||
/* there must be data left over for TB1 or this code must be changed */
|
||||
BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_HCMD_SCRATCHBUF_SIZE);
|
||||
BUILD_BUG_ON(sizeof(struct iwl_tx_cmd) < IWL_FIRST_TB_SIZE);
|
||||
|
||||
/* map the data for TB1 */
|
||||
tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_HCMD_SCRATCHBUF_SIZE;
|
||||
tb1_addr = ((u8 *)&dev_cmd->hdr) + IWL_FIRST_TB_SIZE;
|
||||
tb1_phys = dma_map_single(trans->dev, tb1_addr, tb1_len, DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(trans->dev, tb1_phys)))
|
||||
goto out_err;
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
void lbs_mac_event_disconnected(struct lbs_private *priv,
|
||||
bool locally_generated)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (priv->connect_status != LBS_CONNECTED)
|
||||
return;
|
||||
|
||||
|
@ -46,9 +48,11 @@ void lbs_mac_event_disconnected(struct lbs_private *priv,
|
|||
netif_carrier_off(priv->dev);
|
||||
|
||||
/* Free Tx and Rx packets */
|
||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||
kfree_skb(priv->currenttxskb);
|
||||
priv->currenttxskb = NULL;
|
||||
priv->tx_pending_len = 0;
|
||||
spin_unlock_irqrestore(&priv->driver_lock, flags);
|
||||
|
||||
priv->connect_status = LBS_DISCONNECTED;
|
||||
|
||||
|
|
|
@ -735,7 +735,7 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
|
|||
static int __init lbtf_init_module(void)
|
||||
{
|
||||
lbtf_deb_enter(LBTF_DEB_MAIN);
|
||||
lbtf_wq = create_workqueue("libertastf");
|
||||
lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM, 0);
|
||||
if (lbtf_wq == NULL) {
|
||||
printk(KERN_ERR "libertastf: couldn't create workqueue\n");
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -376,6 +376,29 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
|
|||
return mwifiex_set_tx_power(priv, &power_cfg);
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to get Tx power.
|
||||
*/
|
||||
static int
|
||||
mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy,
|
||||
struct wireless_dev *wdev,
|
||||
int *dbm)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
|
||||
struct mwifiex_private *priv = mwifiex_get_priv(adapter,
|
||||
MWIFIEX_BSS_ROLE_ANY);
|
||||
int ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL, true);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* tx_power_level is set in HostCmd_CMD_RF_TX_PWR command handler */
|
||||
*dbm = priv->tx_power_level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CFG802.11 operation handler to set Power Save option.
|
||||
*
|
||||
|
@ -1672,6 +1695,9 @@ static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy,
|
|||
struct cfg80211_beacon_data *data)
|
||||
{
|
||||
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
mwifiex_cancel_scan(adapter);
|
||||
|
||||
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP) {
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
|
@ -1804,6 +1830,21 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
|
|||
HostCmd_ACT_GEN_SET, 0, &ant_cfg, true);
|
||||
}
|
||||
|
||||
static int
|
||||
mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
|
||||
{
|
||||
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
|
||||
struct mwifiex_private *priv = mwifiex_get_priv(adapter,
|
||||
MWIFIEX_BSS_ROLE_ANY);
|
||||
mwifiex_send_cmd(priv, HostCmd_CMD_RF_ANTENNA,
|
||||
HostCmd_ACT_GEN_GET, 0, NULL, true);
|
||||
|
||||
*tx_ant = priv->tx_ant;
|
||||
*rx_ant = priv->rx_ant;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cfg80211 operation handler for stop ap.
|
||||
* Function stops BSS running at uAP interface.
|
||||
*/
|
||||
|
@ -2209,6 +2250,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
|
|||
return -EALREADY;
|
||||
}
|
||||
|
||||
if (priv->scan_block)
|
||||
priv->scan_block = false;
|
||||
|
||||
if (adapter->surprise_removed || adapter->is_cmd_timedout) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"%s: Ignore connection.\t"
|
||||
|
@ -2427,6 +2471,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!priv->wdev.current_bss && priv->scan_block)
|
||||
priv->scan_block = false;
|
||||
|
||||
if (!mwifiex_stop_bg_scan(priv))
|
||||
cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
|
||||
|
||||
|
@ -2734,6 +2781,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||
struct mwifiex_private *priv;
|
||||
struct net_device *dev;
|
||||
void *mdev_priv;
|
||||
int ret;
|
||||
|
||||
if (!adapter)
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
@ -2859,6 +2907,15 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
|
|||
mwifiex_init_priv_params(priv, dev);
|
||||
priv->netdev = dev;
|
||||
|
||||
ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
|
||||
HostCmd_ACT_GEN_SET, 0, NULL, true);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = mwifiex_sta_init_cmd(priv, false, false);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
mwifiex_setup_ht_caps(&wiphy->bands[NL80211_BAND_2GHZ]->ht_cap, priv);
|
||||
if (adapter->is_hw_11ac_capable)
|
||||
mwifiex_setup_vht_caps(
|
||||
|
@ -3262,7 +3319,10 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
|
|||
struct mwifiex_ds_hs_cfg hs_cfg;
|
||||
int i, ret = 0, retry_num = 10;
|
||||
struct mwifiex_private *priv;
|
||||
struct mwifiex_private *sta_priv =
|
||||
mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
|
||||
|
||||
sta_priv->scan_aborting = true;
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
mwifiex_abort_cac(priv);
|
||||
|
@ -3291,21 +3351,21 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
|
|||
if (!wowlan) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"None of the WOWLAN triggers enabled\n");
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
|
||||
|
||||
if (!priv->media_connected && !wowlan->nd_config) {
|
||||
if (!sta_priv->media_connected && !wowlan->nd_config) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Can not configure WOWLAN in disconnected state\n");
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = mwifiex_set_mef_filter(priv, wowlan);
|
||||
ret = mwifiex_set_mef_filter(sta_priv, wowlan);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to set MEF filter\n");
|
||||
return ret;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(&hs_cfg, 0, sizeof(hs_cfg));
|
||||
|
@ -3314,26 +3374,25 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
|
|||
if (wowlan->nd_config) {
|
||||
mwifiex_dbg(adapter, INFO, "Wake on net detect\n");
|
||||
hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
|
||||
mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev,
|
||||
mwifiex_cfg80211_sched_scan_start(wiphy, sta_priv->netdev,
|
||||
wowlan->nd_config);
|
||||
}
|
||||
|
||||
if (wowlan->disconnect) {
|
||||
hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
|
||||
mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n");
|
||||
mwifiex_dbg(sta_priv->adapter, INFO, "Wake on device disconnect\n");
|
||||
}
|
||||
|
||||
hs_cfg.is_invoke_hostcmd = false;
|
||||
hs_cfg.gpio = adapter->hs_cfg.gpio;
|
||||
hs_cfg.gap = adapter->hs_cfg.gap;
|
||||
ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
|
||||
ret = mwifiex_set_hs_params(sta_priv, HostCmd_ACT_GEN_SET,
|
||||
MWIFIEX_SYNC_CMD, &hs_cfg);
|
||||
if (ret) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Failed to set HS params\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
mwifiex_dbg(adapter, ERROR, "Failed to set HS params\n");
|
||||
|
||||
done:
|
||||
sta_priv->scan_aborting = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3940,12 +3999,14 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
|
|||
.set_default_key = mwifiex_cfg80211_set_default_key,
|
||||
.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
|
||||
.set_tx_power = mwifiex_cfg80211_set_tx_power,
|
||||
.get_tx_power = mwifiex_cfg80211_get_tx_power,
|
||||
.set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
|
||||
.start_ap = mwifiex_cfg80211_start_ap,
|
||||
.stop_ap = mwifiex_cfg80211_stop_ap,
|
||||
.change_beacon = mwifiex_cfg80211_change_beacon,
|
||||
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
|
||||
.set_antenna = mwifiex_cfg80211_set_antenna,
|
||||
.get_antenna = mwifiex_cfg80211_get_antenna,
|
||||
.del_station = mwifiex_cfg80211_del_station,
|
||||
.sched_scan_start = mwifiex_cfg80211_sched_scan_start,
|
||||
.sched_scan_stop = mwifiex_cfg80211_sched_scan_stop,
|
||||
|
|
|
@ -1020,8 +1020,6 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
|
|||
{
|
||||
struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
|
||||
unsigned long flags, cmd_flags;
|
||||
struct mwifiex_private *priv;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
/* Cancel current cmd */
|
||||
|
@ -1046,27 +1044,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
|
|||
spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
|
||||
mwifiex_cancel_pending_scan_cmd(adapter);
|
||||
|
||||
if (adapter->scan_processing) {
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
adapter->scan_processing = false;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
if (!priv)
|
||||
continue;
|
||||
if (priv->scan_request) {
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
|
||||
cfg80211_scan_done(priv->scan_request, &info);
|
||||
priv->scan_request = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
mwifiex_cancel_scan(adapter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1084,8 +1062,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
|
|||
{
|
||||
struct cmd_ctrl_node *cmd_node = NULL;
|
||||
unsigned long cmd_flags;
|
||||
struct mwifiex_private *priv;
|
||||
int i;
|
||||
|
||||
if ((adapter->curr_cmd) &&
|
||||
(adapter->curr_cmd->wait_q_enabled)) {
|
||||
|
@ -1105,27 +1081,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
|
|||
mwifiex_recycle_cmd_node(adapter, cmd_node);
|
||||
}
|
||||
|
||||
mwifiex_cancel_pending_scan_cmd(adapter);
|
||||
|
||||
if (adapter->scan_processing) {
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
adapter->scan_processing = false;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
if (!priv)
|
||||
continue;
|
||||
if (priv->scan_request) {
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
mwifiex_dbg(adapter, WARN, "info: aborting scan\n");
|
||||
cfg80211_scan_done(priv->scan_request, &info);
|
||||
priv->scan_request = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
mwifiex_cancel_scan(adapter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -462,6 +462,9 @@ enum P2P_MODES {
|
|||
#define HostCmd_ACT_SET_RX 0x0001
|
||||
#define HostCmd_ACT_SET_TX 0x0002
|
||||
#define HostCmd_ACT_SET_BOTH 0x0003
|
||||
#define HostCmd_ACT_GET_RX 0x0004
|
||||
#define HostCmd_ACT_GET_TX 0x0008
|
||||
#define HostCmd_ACT_GET_BOTH 0x000c
|
||||
|
||||
#define RF_ANTENNA_AUTO 0xFFFF
|
||||
|
||||
|
@ -1958,8 +1961,8 @@ struct mwifiex_ie_types_btcoex_scan_time {
|
|||
struct mwifiex_ie_types_header header;
|
||||
u8 coex_scan;
|
||||
u8 reserved;
|
||||
u16 min_scan_time;
|
||||
u16 max_scan_time;
|
||||
__le16 min_scan_time;
|
||||
__le16 max_scan_time;
|
||||
} __packed;
|
||||
|
||||
struct mwifiex_ie_types_btcoex_aggr_win_size {
|
||||
|
|
|
@ -60,7 +60,7 @@ static void wakeup_timer_fn(unsigned long data)
|
|||
adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
|
||||
mwifiex_cancel_all_pending_cmd(adapter);
|
||||
|
||||
if (adapter->if_ops.card_reset)
|
||||
if (adapter->if_ops.card_reset && !adapter->hs_activated)
|
||||
adapter->if_ops.card_reset(adapter);
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
|
|||
priv->tx_power_level = 0;
|
||||
priv->max_tx_power_level = 0;
|
||||
priv->min_tx_power_level = 0;
|
||||
priv->tx_ant = 0;
|
||||
priv->rx_ant = 0;
|
||||
priv->tx_rate = 0;
|
||||
priv->rxpd_htinfo = 0;
|
||||
priv->rxpd_rate = 0;
|
||||
|
|
|
@ -83,6 +83,8 @@ struct wep_key {
|
|||
#define MWIFIEX_AUTH_MODE_AUTO 0xFF
|
||||
#define BAND_CONFIG_BG 0x00
|
||||
#define BAND_CONFIG_A 0x01
|
||||
#define MWIFIEX_SEC_CHAN_BELOW 0x30
|
||||
#define MWIFIEX_SEC_CHAN_ABOVE 0x10
|
||||
#define MWIFIEX_SUPPORTED_RATES 14
|
||||
#define MWIFIEX_SUPPORTED_RATES_EXT 32
|
||||
#define MWIFIEX_TDLS_SUPPORTED_RATES 8
|
||||
|
|
|
@ -647,6 +647,12 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
|
|||
const u8 *ie_ptr;
|
||||
struct ieee80211_ht_operation *assoc_resp_ht_oper;
|
||||
|
||||
if (!priv->attempted_bss_desc) {
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"ASSOC_RESP: failed, association terminated by host\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
|
||||
|
||||
cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
|
||||
|
@ -1270,6 +1276,12 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
|
|||
u16 cmd = le16_to_cpu(resp->command);
|
||||
u8 result;
|
||||
|
||||
if (!priv->attempted_bss_desc) {
|
||||
mwifiex_dbg(priv->adapter, ERROR,
|
||||
"ADHOC_RESP: failed, association terminated by host\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (cmd == HostCmd_CMD_802_11_AD_HOC_START)
|
||||
result = start_result->result;
|
||||
else
|
||||
|
|
|
@ -533,6 +533,8 @@ struct mwifiex_private {
|
|||
u16 tx_power_level;
|
||||
u8 max_tx_power_level;
|
||||
u8 min_tx_power_level;
|
||||
u32 tx_ant;
|
||||
u32 rx_ant;
|
||||
u8 tx_rate;
|
||||
u8 tx_htinfo;
|
||||
u8 rxpd_htinfo;
|
||||
|
@ -1054,6 +1056,7 @@ int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
|
|||
void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
|
||||
void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
|
||||
void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter);
|
||||
void mwifiex_cancel_scan(struct mwifiex_adapter *adapter);
|
||||
|
||||
void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
|
||||
struct cmd_ctrl_node *cmd_node);
|
||||
|
|
|
@ -440,6 +440,11 @@ static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
WARN_ON(mwifiex_pcie_disable_host_int(adapter));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function enables the host interrupt.
|
||||
*
|
||||
|
@ -2086,6 +2091,13 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
|
|||
unsigned long flags;
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
if (card->msi_enable) {
|
||||
spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
adapter->int_status = 1;
|
||||
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mwifiex_pcie_ok_to_access_hw(adapter))
|
||||
return;
|
||||
|
||||
|
@ -2187,15 +2199,44 @@ exit:
|
|||
static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
int ret;
|
||||
u32 pcie_ireg;
|
||||
u32 pcie_ireg = 0;
|
||||
unsigned long flags;
|
||||
struct pcie_service_card *card = adapter->card;
|
||||
|
||||
spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
/* Clear out unused interrupts */
|
||||
pcie_ireg = adapter->int_status;
|
||||
if (!card->msi_enable) {
|
||||
/* Clear out unused interrupts */
|
||||
pcie_ireg = adapter->int_status;
|
||||
}
|
||||
adapter->int_status = 0;
|
||||
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
|
||||
if (card->msi_enable) {
|
||||
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
|
||||
&pcie_ireg)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Read register failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
||||
if (mwifiex_write_reg(adapter,
|
||||
PCIE_HOST_INT_STATUS,
|
||||
~pcie_ireg)) {
|
||||
mwifiex_dbg(adapter, ERROR,
|
||||
"Write register failed\n");
|
||||
return -1;
|
||||
}
|
||||
if (!adapter->pps_uapsd_mode &&
|
||||
adapter->ps_state == PS_STATE_SLEEP) {
|
||||
adapter->ps_state = PS_STATE_AWAKE;
|
||||
adapter->pm_wakeup_fw_try = false;
|
||||
del_timer(&adapter->wakeup_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (pcie_ireg & HOST_INTR_MASK) {
|
||||
if (pcie_ireg & HOST_INTR_DNLD_DONE) {
|
||||
pcie_ireg &= ~HOST_INTR_DNLD_DONE;
|
||||
|
@ -2235,6 +2276,12 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (card->msi_enable) {
|
||||
spin_lock_irqsave(&adapter->int_lock, flags);
|
||||
adapter->int_status = 0;
|
||||
spin_unlock_irqrestore(&adapter->int_lock, flags);
|
||||
}
|
||||
|
||||
if (mwifiex_pcie_ok_to_access_hw(adapter)) {
|
||||
if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
|
||||
&pcie_ireg)) {
|
||||
|
@ -2258,7 +2305,7 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
|
|||
mwifiex_dbg(adapter, INTR,
|
||||
"info: cmd_sent=%d data_sent=%d\n",
|
||||
adapter->cmd_sent, adapter->data_sent);
|
||||
if (adapter->ps_state != PS_STATE_SLEEP)
|
||||
if (!card->msi_enable && adapter->ps_state != PS_STATE_SLEEP)
|
||||
mwifiex_pcie_enable_host_int(adapter);
|
||||
|
||||
return 0;
|
||||
|
@ -2841,20 +2888,20 @@ static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
|
|||
version &= 0x7;
|
||||
switch (revision_id) {
|
||||
case PCIE8997_V2:
|
||||
if (version == CHIP_VER_PCIEUSB)
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUSB8997_FW_NAME_V2);
|
||||
else
|
||||
if (version == CHIP_VER_PCIEUART)
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUART8997_FW_NAME_V2);
|
||||
break;
|
||||
case PCIE8997_Z:
|
||||
if (version == CHIP_VER_PCIEUSB)
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUSB8997_FW_NAME_Z);
|
||||
else
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUSB8997_FW_NAME_V2);
|
||||
break;
|
||||
case PCIE8997_Z:
|
||||
if (version == CHIP_VER_PCIEUART)
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUART8997_FW_NAME_Z);
|
||||
else
|
||||
strcpy(adapter->fw_name,
|
||||
PCIEUSB8997_FW_NAME_Z);
|
||||
break;
|
||||
default:
|
||||
strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME);
|
||||
|
@ -2946,6 +2993,7 @@ static struct mwifiex_if_ops pcie_ops = {
|
|||
.register_dev = mwifiex_register_dev,
|
||||
.unregister_dev = mwifiex_unregister_dev,
|
||||
.enable_int = mwifiex_pcie_enable_host_int,
|
||||
.disable_int = mwifiex_pcie_disable_host_int_noerr,
|
||||
.process_int_status = mwifiex_process_int_status,
|
||||
.host_to_card = mwifiex_pcie_host_to_card,
|
||||
.wakeup = mwifiex_pm_wakeup_card,
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
|
||||
#define PCIE8897_A0_FW_NAME "mrvl/pcie8897_uapsta_a0.bin"
|
||||
#define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin"
|
||||
#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieuart8997_combo_v2.bin"
|
||||
#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieusb8997_combo_v2.bin"
|
||||
#define PCIEUART8997_FW_NAME_Z "mrvl/pcieuart8997_combo.bin"
|
||||
#define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin"
|
||||
#define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
|
||||
|
@ -48,7 +48,7 @@
|
|||
#define PCIE8897_B0 0x1200
|
||||
#define PCIE8997_Z 0x0
|
||||
#define PCIE8997_V2 0x471
|
||||
#define CHIP_VER_PCIEUSB 0x2
|
||||
#define CHIP_VER_PCIEUART 0x3
|
||||
|
||||
/* Constants for Buffer Descriptor (BD) rings */
|
||||
#define MWIFIEX_MAX_TXRX_BD 0x20
|
||||
|
@ -258,7 +258,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
|
|||
.fw_dump_end = 0xcff,
|
||||
.fw_dump_host_ready = 0xcc,
|
||||
.fw_dump_read_done = 0xdd,
|
||||
.msix_support = 1,
|
||||
.msix_support = 0,
|
||||
};
|
||||
|
||||
static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = {
|
||||
|
|
|
@ -1896,7 +1896,8 @@ mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
|
|||
u8 id = 0;
|
||||
struct mwifiex_user_scan_cfg *user_scan_cfg;
|
||||
|
||||
if (adapter->active_scan_triggered || !priv->scan_request) {
|
||||
if (adapter->active_scan_triggered || !priv->scan_request ||
|
||||
priv->scan_aborting) {
|
||||
adapter->active_scan_triggered = false;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1964,6 +1965,7 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
|
|||
"info: notifying scan done\n");
|
||||
cfg80211_scan_done(priv->scan_request, &info);
|
||||
priv->scan_request = NULL;
|
||||
priv->scan_aborting = false;
|
||||
} else {
|
||||
priv->scan_aborting = false;
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
|
@ -1989,6 +1991,7 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
|
|||
"info: aborting scan\n");
|
||||
cfg80211_scan_done(priv->scan_request, &info);
|
||||
priv->scan_request = NULL;
|
||||
priv->scan_aborting = false;
|
||||
} else {
|
||||
priv->scan_aborting = false;
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
|
@ -2009,6 +2012,37 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
|
|||
return;
|
||||
}
|
||||
|
||||
void mwifiex_cancel_scan(struct mwifiex_adapter *adapter)
|
||||
{
|
||||
struct mwifiex_private *priv;
|
||||
unsigned long cmd_flags;
|
||||
int i;
|
||||
|
||||
mwifiex_cancel_pending_scan_cmd(adapter);
|
||||
|
||||
if (adapter->scan_processing) {
|
||||
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
adapter->scan_processing = false;
|
||||
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
|
||||
for (i = 0; i < adapter->priv_num; i++) {
|
||||
priv = adapter->priv[i];
|
||||
if (!priv)
|
||||
continue;
|
||||
if (priv->scan_request) {
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
"info: aborting scan\n");
|
||||
cfg80211_scan_done(priv->scan_request, &info);
|
||||
priv->scan_request = NULL;
|
||||
priv->scan_aborting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the command response of scan.
|
||||
*
|
||||
|
|
|
@ -313,23 +313,41 @@ static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv,
|
|||
|
||||
cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA);
|
||||
|
||||
if (cmd_action != HostCmd_ACT_GEN_SET)
|
||||
return 0;
|
||||
|
||||
if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
|
||||
cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_mimo) +
|
||||
S_DS_GEN);
|
||||
ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX);
|
||||
ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant);
|
||||
ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX);
|
||||
ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->rx_ant);
|
||||
} else {
|
||||
cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_siso) +
|
||||
S_DS_GEN);
|
||||
ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH);
|
||||
ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant);
|
||||
switch (cmd_action) {
|
||||
case HostCmd_ACT_GEN_SET:
|
||||
if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
|
||||
cmd->size = cpu_to_le16(sizeof(struct
|
||||
host_cmd_ds_rf_ant_mimo)
|
||||
+ S_DS_GEN);
|
||||
ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX);
|
||||
ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->
|
||||
tx_ant);
|
||||
ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX);
|
||||
ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->
|
||||
rx_ant);
|
||||
} else {
|
||||
cmd->size = cpu_to_le16(sizeof(struct
|
||||
host_cmd_ds_rf_ant_siso) +
|
||||
S_DS_GEN);
|
||||
ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH);
|
||||
ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant);
|
||||
}
|
||||
break;
|
||||
case HostCmd_ACT_GEN_GET:
|
||||
if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
|
||||
cmd->size = cpu_to_le16(sizeof(struct
|
||||
host_cmd_ds_rf_ant_mimo) +
|
||||
S_DS_GEN);
|
||||
ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_GET_TX);
|
||||
ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_GET_RX);
|
||||
} else {
|
||||
cmd->size = cpu_to_le16(sizeof(struct
|
||||
host_cmd_ds_rf_ant_siso) +
|
||||
S_DS_GEN);
|
||||
ant_siso->action = cpu_to_le16(HostCmd_ACT_GET_BOTH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -469,7 +469,9 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv,
|
|||
struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso;
|
||||
struct mwifiex_adapter *adapter = priv->adapter;
|
||||
|
||||
if (adapter->hw_dev_mcs_support == HT_STREAM_2X2)
|
||||
if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) {
|
||||
priv->tx_ant = le16_to_cpu(ant_mimo->tx_ant_mode);
|
||||
priv->rx_ant = le16_to_cpu(ant_mimo->rx_ant_mode);
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
"RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x\t"
|
||||
"Rx action = 0x%x, Rx Mode = 0x%04x\n",
|
||||
|
@ -477,12 +479,14 @@ static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv,
|
|||
le16_to_cpu(ant_mimo->tx_ant_mode),
|
||||
le16_to_cpu(ant_mimo->action_rx),
|
||||
le16_to_cpu(ant_mimo->rx_ant_mode));
|
||||
else
|
||||
} else {
|
||||
priv->tx_ant = le16_to_cpu(ant_siso->ant_mode);
|
||||
priv->rx_ant = le16_to_cpu(ant_siso->ant_mode);
|
||||
mwifiex_dbg(adapter, INFO,
|
||||
"RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n",
|
||||
le16_to_cpu(ant_siso->action),
|
||||
le16_to_cpu(ant_siso->ant_mode));
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -474,8 +474,8 @@ void mwifiex_bt_coex_wlan_param_update_event(struct mwifiex_private *priv,
|
|||
scantlv =
|
||||
(struct mwifiex_ie_types_btcoex_scan_time *)tlv;
|
||||
adapter->coex_scan = scantlv->coex_scan;
|
||||
adapter->coex_min_scan_time = scantlv->min_scan_time;
|
||||
adapter->coex_max_scan_time = scantlv->max_scan_time;
|
||||
adapter->coex_min_scan_time = le16_to_cpu(scantlv->min_scan_time);
|
||||
adapter->coex_max_scan_time = le16_to_cpu(scantlv->max_scan_time);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -708,7 +708,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
|
|||
|
||||
case EVENT_EXT_SCAN_REPORT:
|
||||
mwifiex_dbg(adapter, EVENT, "event: EXT_SCAN Report\n");
|
||||
if (adapter->ext_scan)
|
||||
if (adapter->ext_scan && !priv->scan_aborting)
|
||||
ret = mwifiex_handle_event_ext_scan_report(priv,
|
||||
adapter->event_skb->data);
|
||||
|
||||
|
|
|
@ -426,6 +426,10 @@ done:
|
|||
if (bss_desc)
|
||||
kfree(bss_desc->beacon_buf);
|
||||
kfree(bss_desc);
|
||||
|
||||
if (ret < 0)
|
||||
priv->attempted_bss_desc = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "main.h"
|
||||
#include "11ac.h"
|
||||
#include "11n.h"
|
||||
|
||||
/* This function parses security related parameters from cfg80211_ap_settings
|
||||
* and sets into FW understandable bss_config structure.
|
||||
|
@ -521,9 +522,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
|
|||
tlv += sizeof(struct host_cmd_tlv_rates) + i;
|
||||
}
|
||||
if (bss_cfg->channel &&
|
||||
((bss_cfg->band_cfg == BAND_CONFIG_BG &&
|
||||
(((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG &&
|
||||
bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
|
||||
(bss_cfg->band_cfg == BAND_CONFIG_A &&
|
||||
((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A &&
|
||||
bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
|
||||
chan_band = (struct host_cmd_tlv_channel_band *)tlv;
|
||||
chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
|
||||
|
@ -833,6 +834,31 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv,
|
|||
config_bands |= BAND_AAC;
|
||||
}
|
||||
|
||||
switch (chandef.width) {
|
||||
case NL80211_CHAN_WIDTH_5:
|
||||
case NL80211_CHAN_WIDTH_10:
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
if (chandef.center_freq1 < chandef.chan->center_freq)
|
||||
bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_BELOW;
|
||||
else
|
||||
bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_ABOVE;
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
case NL80211_CHAN_WIDTH_80P80:
|
||||
case NL80211_CHAN_WIDTH_160:
|
||||
bss_cfg->band_cfg |=
|
||||
mwifiex_get_sec_chan_offset(bss_cfg->channel) << 4;
|
||||
break;
|
||||
default:
|
||||
mwifiex_dbg(priv->adapter,
|
||||
WARN, "Unknown channel width: %d\n",
|
||||
chandef.width);
|
||||
break;
|
||||
}
|
||||
|
||||
priv->adapter->config_bands = config_bands;
|
||||
|
||||
if (old_bands != config_bands) {
|
||||
|
|
|
@ -135,7 +135,8 @@ struct rtl8xxxu_rxdesc16 {
|
|||
|
||||
u32 seq:12;
|
||||
u32 frag:4;
|
||||
u32 nextpktlen:14;
|
||||
u32 pkt_cnt:8;
|
||||
u32 reserved:6;
|
||||
u32 nextind:1;
|
||||
u32 reserved0:1;
|
||||
|
||||
|
@ -198,7 +199,8 @@ struct rtl8xxxu_rxdesc16 {
|
|||
|
||||
u32 reserved0:1;
|
||||
u32 nextind:1;
|
||||
u32 nextpktlen:14;
|
||||
u32 reserved:6;
|
||||
u32 pkt_cnt:8;
|
||||
u32 frag:4;
|
||||
u32 seq:12;
|
||||
|
||||
|
@ -1245,6 +1247,7 @@ struct rtl8xxxu_priv {
|
|||
u32 ep_tx_normal_queue:1;
|
||||
u32 ep_tx_low_queue:1;
|
||||
u32 has_xtalk:1;
|
||||
u32 rx_buf_aggregation:1;
|
||||
u8 xtalk;
|
||||
unsigned int pipe_interrupt;
|
||||
unsigned int pipe_in;
|
||||
|
@ -1315,8 +1318,7 @@ struct rtl8xxxu_fileops {
|
|||
void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv);
|
||||
void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv);
|
||||
void (*config_channel) (struct ieee80211_hw *hw);
|
||||
int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int (*parse_rx_desc) (struct rtl8xxxu_priv *priv, struct sk_buff *skb);
|
||||
void (*init_aggregation) (struct rtl8xxxu_priv *priv);
|
||||
void (*init_statistics) (struct rtl8xxxu_priv *priv);
|
||||
void (*enable_rf) (struct rtl8xxxu_priv *priv);
|
||||
|
@ -1329,6 +1331,7 @@ struct rtl8xxxu_fileops {
|
|||
void (*report_connect) (struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect);
|
||||
int writeN_block_size;
|
||||
int rx_agg_buf_size;
|
||||
char tx_desc_size;
|
||||
char rx_desc_size;
|
||||
char has_s0s1;
|
||||
|
@ -1409,13 +1412,12 @@ void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv,
|
|||
u8 macid, bool connect);
|
||||
void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
|
||||
u8 macid, bool connect);
|
||||
void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv);
|
||||
void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv);
|
||||
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status);
|
||||
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb);
|
||||
int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb);
|
||||
int rtl8xxxu_gen2_channel_to_group(int channel);
|
||||
bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv,
|
||||
int result[][8], int c1, int c2);
|
||||
|
|
|
@ -413,13 +413,8 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
|
|||
dev_info(&priv->udev->dev,
|
||||
"%s: dumping efuse (0x%02zx bytes):\n",
|
||||
__func__, sizeof(struct rtl8192cu_efuse));
|
||||
for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
|
||||
dev_info(&priv->udev->dev, "%02x: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
||||
raw[i], raw[i + 1], raw[i + 2],
|
||||
raw[i + 3], raw[i + 4], raw[i + 5],
|
||||
raw[i + 6], raw[i + 7]);
|
||||
}
|
||||
for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8)
|
||||
dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,6 +560,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = {
|
|||
.phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
|
||||
.config_channel = rtl8xxxu_gen1_config_channel,
|
||||
.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
|
||||
.init_aggregation = rtl8xxxu_gen1_init_aggregation,
|
||||
.enable_rf = rtl8xxxu_gen1_enable_rf,
|
||||
.disable_rf = rtl8xxxu_gen1_disable_rf,
|
||||
.usb_quirks = rtl8xxxu_gen1_usb_quirks,
|
||||
|
@ -572,6 +568,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = {
|
|||
.update_rate_mask = rtl8xxxu_update_rate_mask,
|
||||
.report_connect = rtl8xxxu_gen1_report_connect,
|
||||
.writeN_block_size = 128,
|
||||
.rx_agg_buf_size = 16000,
|
||||
.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
|
||||
.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
|
||||
.adda_1t_init = 0x0b1b25a0,
|
||||
|
|
|
@ -622,13 +622,8 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
|
|||
dev_info(&priv->udev->dev,
|
||||
"%s: dumping efuse (0x%02zx bytes):\n",
|
||||
__func__, sizeof(struct rtl8192eu_efuse));
|
||||
for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8) {
|
||||
dev_info(&priv->udev->dev, "%02x: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
||||
raw[i], raw[i + 1], raw[i + 2],
|
||||
raw[i + 3], raw[i + 4], raw[i + 5],
|
||||
raw[i + 6], raw[i + 7]);
|
||||
}
|
||||
for (i = 0; i < sizeof(struct rtl8192eu_efuse); i += 8)
|
||||
dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1249,11 +1244,9 @@ static void rtl8192eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
|
|||
reg_e94 = result[i][0];
|
||||
reg_e9c = result[i][1];
|
||||
reg_ea4 = result[i][2];
|
||||
reg_eac = result[i][3];
|
||||
reg_eb4 = result[i][4];
|
||||
reg_ebc = result[i][5];
|
||||
reg_ec4 = result[i][6];
|
||||
reg_ecc = result[i][7];
|
||||
}
|
||||
|
||||
if (candidate >= 0) {
|
||||
|
|
|
@ -377,6 +377,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = {
|
|||
.phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
|
||||
.config_channel = rtl8xxxu_gen1_config_channel,
|
||||
.parse_rx_desc = rtl8xxxu_parse_rxdesc16,
|
||||
.init_aggregation = rtl8xxxu_gen1_init_aggregation,
|
||||
.enable_rf = rtl8xxxu_gen1_enable_rf,
|
||||
.disable_rf = rtl8xxxu_gen1_disable_rf,
|
||||
.usb_quirks = rtl8xxxu_gen1_usb_quirks,
|
||||
|
@ -384,6 +385,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = {
|
|||
.update_rate_mask = rtl8xxxu_update_rate_mask,
|
||||
.report_connect = rtl8xxxu_gen1_report_connect,
|
||||
.writeN_block_size = 1024,
|
||||
.rx_agg_buf_size = 16000,
|
||||
.tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
|
||||
.rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
|
||||
.adda_1t_init = 0x0b1b25a0,
|
||||
|
|
|
@ -466,13 +466,8 @@ static int rtl8723bu_parse_efuse(struct rtl8xxxu_priv *priv)
|
|||
dev_info(&priv->udev->dev,
|
||||
"%s: dumping efuse (0x%02zx bytes):\n",
|
||||
__func__, sizeof(struct rtl8723bu_efuse));
|
||||
for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8) {
|
||||
dev_info(&priv->udev->dev, "%02x: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
||||
raw[i], raw[i + 1], raw[i + 2],
|
||||
raw[i + 3], raw[i + 4], raw[i + 5],
|
||||
raw[i + 6], raw[i + 7]);
|
||||
}
|
||||
for (i = 0; i < sizeof(struct rtl8723bu_efuse); i += 8)
|
||||
dev_info(&priv->udev->dev, "%02x: %8ph\n", i, &raw[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
|
||||
int rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE;
|
||||
static bool rtl8xxxu_ht40_2g;
|
||||
static bool rtl8xxxu_dma_aggregation;
|
||||
static int rtl8xxxu_dma_agg_timeout = -1;
|
||||
static int rtl8xxxu_dma_agg_pages = -1;
|
||||
|
||||
MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
|
||||
MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver");
|
||||
|
@ -62,10 +65,14 @@ module_param_named(debug, rtl8xxxu_debug, int, 0600);
|
|||
MODULE_PARM_DESC(debug, "Set debug mask");
|
||||
module_param_named(ht40_2g, rtl8xxxu_ht40_2g, bool, 0600);
|
||||
MODULE_PARM_DESC(ht40_2g, "Enable HT40 support on the 2.4GHz band");
|
||||
module_param_named(dma_aggregation, rtl8xxxu_dma_aggregation, bool, 0600);
|
||||
MODULE_PARM_DESC(dma_aggregation, "Enable DMA packet aggregation");
|
||||
module_param_named(dma_agg_timeout, rtl8xxxu_dma_agg_timeout, int, 0600);
|
||||
MODULE_PARM_DESC(dma_agg_timeout, "Set DMA aggregation timeout (range 1-127)");
|
||||
module_param_named(dma_agg_pages, rtl8xxxu_dma_agg_pages, int, 0600);
|
||||
MODULE_PARM_DESC(dma_agg_pages, "Set DMA aggregation pages (range 1-127, 0 to disable)");
|
||||
|
||||
#define USB_VENDOR_ID_REALTEK 0x0bda
|
||||
/* Minimum IEEE80211_MAX_FRAME_LEN */
|
||||
#define RTL_RX_BUFFER_SIZE IEEE80211_MAX_FRAME_LEN
|
||||
#define RTL8XXXU_RX_URBS 32
|
||||
#define RTL8XXXU_RX_URB_PENDING_WATER 8
|
||||
#define RTL8XXXU_TX_URBS 64
|
||||
|
@ -4407,6 +4414,73 @@ void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
|
|||
rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.media_status_rpt));
|
||||
}
|
||||
|
||||
void rtl8xxxu_gen1_init_aggregation(struct rtl8xxxu_priv *priv)
|
||||
{
|
||||
u8 agg_ctrl, usb_spec, page_thresh, timeout;
|
||||
|
||||
usb_spec = rtl8xxxu_read8(priv, REG_USB_SPECIAL_OPTION);
|
||||
usb_spec &= ~USB_SPEC_USB_AGG_ENABLE;
|
||||
rtl8xxxu_write8(priv, REG_USB_SPECIAL_OPTION, usb_spec);
|
||||
|
||||
agg_ctrl = rtl8xxxu_read8(priv, REG_TRXDMA_CTRL);
|
||||
agg_ctrl &= ~TRXDMA_CTRL_RXDMA_AGG_EN;
|
||||
|
||||
if (!rtl8xxxu_dma_aggregation) {
|
||||
rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
agg_ctrl |= TRXDMA_CTRL_RXDMA_AGG_EN;
|
||||
rtl8xxxu_write8(priv, REG_TRXDMA_CTRL, agg_ctrl);
|
||||
|
||||
/*
|
||||
* The number of packets we can take looks to be buffer size / 512
|
||||
* which matches the 512 byte rounding we have to do when de-muxing
|
||||
* the packets.
|
||||
*
|
||||
* Sample numbers from the vendor driver:
|
||||
* USB High-Speed mode values:
|
||||
* RxAggBlockCount = 8 : 512 byte unit
|
||||
* RxAggBlockTimeout = 6
|
||||
* RxAggPageCount = 48 : 128 byte unit
|
||||
* RxAggPageTimeout = 4 or 6 (absolute time 34ms/(2^6))
|
||||
*/
|
||||
|
||||
page_thresh = (priv->fops->rx_agg_buf_size / 512);
|
||||
if (rtl8xxxu_dma_agg_pages >= 0) {
|
||||
if (rtl8xxxu_dma_agg_pages <= page_thresh)
|
||||
timeout = page_thresh;
|
||||
else if (rtl8xxxu_dma_agg_pages <= 6)
|
||||
dev_err(&priv->udev->dev,
|
||||
"%s: dma_agg_pages=%i too small, minium is 6\n",
|
||||
__func__, rtl8xxxu_dma_agg_pages);
|
||||
else
|
||||
dev_err(&priv->udev->dev,
|
||||
"%s: dma_agg_pages=%i larger than limit %i\n",
|
||||
__func__, rtl8xxxu_dma_agg_pages, page_thresh);
|
||||
}
|
||||
rtl8xxxu_write8(priv, REG_RXDMA_AGG_PG_TH, page_thresh);
|
||||
/*
|
||||
* REG_RXDMA_AGG_PG_TH + 1 seems to be the timeout register on
|
||||
* gen2 chips and rtl8188eu. The rtl8723au seems unhappy if we
|
||||
* don't set it, so better set both.
|
||||
*/
|
||||
timeout = 4;
|
||||
|
||||
if (rtl8xxxu_dma_agg_timeout >= 0) {
|
||||
if (rtl8xxxu_dma_agg_timeout <= 127)
|
||||
timeout = rtl8xxxu_dma_agg_timeout;
|
||||
else
|
||||
dev_err(&priv->udev->dev,
|
||||
"%s: Invalid dma_agg_timeout: %i\n",
|
||||
__func__, rtl8xxxu_dma_agg_timeout);
|
||||
}
|
||||
|
||||
rtl8xxxu_write8(priv, REG_RXDMA_AGG_PG_TH + 1, timeout);
|
||||
rtl8xxxu_write8(priv, REG_USB_DMA_AGG_TO, timeout);
|
||||
priv->rx_buf_aggregation = 1;
|
||||
}
|
||||
|
||||
static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
|
||||
{
|
||||
u32 val32;
|
||||
|
@ -5045,104 +5119,6 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct rtl8xxxu_rxdesc16 *rx_desc =
|
||||
(struct rtl8xxxu_rxdesc16 *)skb->data;
|
||||
struct rtl8723au_phy_stats *phy_stats;
|
||||
__le32 *_rx_desc_le = (__le32 *)skb->data;
|
||||
u32 *_rx_desc = (u32 *)skb->data;
|
||||
int drvinfo_sz, desc_shift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc16) / sizeof(u32)); i++)
|
||||
_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
|
||||
|
||||
skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16));
|
||||
|
||||
phy_stats = (struct rtl8723au_phy_stats *)skb->data;
|
||||
|
||||
drvinfo_sz = rx_desc->drvinfo_sz * 8;
|
||||
desc_shift = rx_desc->shift;
|
||||
skb_pull(skb, drvinfo_sz + desc_shift);
|
||||
|
||||
if (rx_desc->phy_stats)
|
||||
rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
|
||||
rx_desc->rxmcs);
|
||||
|
||||
rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
|
||||
rx_status->flag |= RX_FLAG_MACTIME_START;
|
||||
|
||||
if (!rx_desc->swdec)
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED;
|
||||
if (rx_desc->crc32)
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
if (rx_desc->bw)
|
||||
rx_status->flag |= RX_FLAG_40MHZ;
|
||||
|
||||
if (rx_desc->rxht) {
|
||||
rx_status->flag |= RX_FLAG_HT;
|
||||
rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
|
||||
} else {
|
||||
rx_status->rate_idx = rx_desc->rxmcs;
|
||||
}
|
||||
|
||||
return RX_TYPE_DATA_PKT;
|
||||
}
|
||||
|
||||
int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
struct rtl8xxxu_rxdesc24 *rx_desc =
|
||||
(struct rtl8xxxu_rxdesc24 *)skb->data;
|
||||
struct rtl8723au_phy_stats *phy_stats;
|
||||
__le32 *_rx_desc_le = (__le32 *)skb->data;
|
||||
u32 *_rx_desc = (u32 *)skb->data;
|
||||
int drvinfo_sz, desc_shift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++)
|
||||
_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
|
||||
|
||||
skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24));
|
||||
|
||||
phy_stats = (struct rtl8723au_phy_stats *)skb->data;
|
||||
|
||||
drvinfo_sz = rx_desc->drvinfo_sz * 8;
|
||||
desc_shift = rx_desc->shift;
|
||||
skb_pull(skb, drvinfo_sz + desc_shift);
|
||||
|
||||
if (rx_desc->rpt_sel) {
|
||||
struct device *dev = &priv->udev->dev;
|
||||
dev_dbg(dev, "%s: C2H packet\n", __func__);
|
||||
return RX_TYPE_C2H;
|
||||
}
|
||||
|
||||
if (rx_desc->phy_stats)
|
||||
rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
|
||||
rx_desc->rxmcs);
|
||||
|
||||
rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
|
||||
rx_status->flag |= RX_FLAG_MACTIME_START;
|
||||
|
||||
if (!rx_desc->swdec)
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED;
|
||||
if (rx_desc->crc32)
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
if (rx_desc->bw)
|
||||
rx_status->flag |= RX_FLAG_40MHZ;
|
||||
|
||||
if (rx_desc->rxmcs >= DESC_RATE_MCS0) {
|
||||
rx_status->flag |= RX_FLAG_HT;
|
||||
rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
|
||||
} else {
|
||||
rx_status->rate_idx = rx_desc->rxmcs;
|
||||
}
|
||||
|
||||
return RX_TYPE_DATA_PKT;
|
||||
}
|
||||
|
||||
static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
@ -5188,6 +5164,155 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw = priv->hw;
|
||||
struct ieee80211_rx_status *rx_status;
|
||||
struct rtl8xxxu_rxdesc16 *rx_desc;
|
||||
struct rtl8723au_phy_stats *phy_stats;
|
||||
struct sk_buff *next_skb = NULL;
|
||||
__le32 *_rx_desc_le;
|
||||
u32 *_rx_desc;
|
||||
int drvinfo_sz, desc_shift;
|
||||
int i, pkt_cnt, pkt_len, urb_len, pkt_offset;
|
||||
|
||||
urb_len = skb->len;
|
||||
pkt_cnt = 0;
|
||||
|
||||
do {
|
||||
rx_desc = (struct rtl8xxxu_rxdesc16 *)skb->data;
|
||||
_rx_desc_le = (__le32 *)skb->data;
|
||||
_rx_desc = (u32 *)skb->data;
|
||||
|
||||
for (i = 0;
|
||||
i < (sizeof(struct rtl8xxxu_rxdesc16) / sizeof(u32)); i++)
|
||||
_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
|
||||
|
||||
/*
|
||||
* Only read pkt_cnt from the header if we're parsing the
|
||||
* first packet
|
||||
*/
|
||||
if (!pkt_cnt)
|
||||
pkt_cnt = rx_desc->pkt_cnt;
|
||||
pkt_len = rx_desc->pktlen;
|
||||
|
||||
drvinfo_sz = rx_desc->drvinfo_sz * 8;
|
||||
desc_shift = rx_desc->shift;
|
||||
pkt_offset = roundup(pkt_len + drvinfo_sz + desc_shift +
|
||||
sizeof(struct rtl8xxxu_rxdesc16), 128);
|
||||
|
||||
if (pkt_cnt > 1)
|
||||
next_skb = skb_clone(skb, GFP_ATOMIC);
|
||||
|
||||
rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
|
||||
|
||||
skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16));
|
||||
|
||||
phy_stats = (struct rtl8723au_phy_stats *)skb->data;
|
||||
|
||||
skb_pull(skb, drvinfo_sz + desc_shift);
|
||||
|
||||
skb_trim(skb, pkt_len);
|
||||
|
||||
if (rx_desc->phy_stats)
|
||||
rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
|
||||
rx_desc->rxmcs);
|
||||
|
||||
rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
|
||||
rx_status->flag |= RX_FLAG_MACTIME_START;
|
||||
|
||||
if (!rx_desc->swdec)
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED;
|
||||
if (rx_desc->crc32)
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
if (rx_desc->bw)
|
||||
rx_status->flag |= RX_FLAG_40MHZ;
|
||||
|
||||
if (rx_desc->rxht) {
|
||||
rx_status->flag |= RX_FLAG_HT;
|
||||
rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
|
||||
} else {
|
||||
rx_status->rate_idx = rx_desc->rxmcs;
|
||||
}
|
||||
|
||||
rx_status->freq = hw->conf.chandef.chan->center_freq;
|
||||
rx_status->band = hw->conf.chandef.chan->band;
|
||||
|
||||
ieee80211_rx_irqsafe(hw, skb);
|
||||
|
||||
skb = next_skb;
|
||||
if (skb)
|
||||
skb_pull(next_skb, pkt_offset);
|
||||
|
||||
pkt_cnt--;
|
||||
urb_len -= pkt_offset;
|
||||
} while (skb && urb_len > 0 && pkt_cnt > 0);
|
||||
|
||||
return RX_TYPE_DATA_PKT;
|
||||
}
|
||||
|
||||
int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hw *hw = priv->hw;
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct rtl8xxxu_rxdesc24 *rx_desc =
|
||||
(struct rtl8xxxu_rxdesc24 *)skb->data;
|
||||
struct rtl8723au_phy_stats *phy_stats;
|
||||
__le32 *_rx_desc_le = (__le32 *)skb->data;
|
||||
u32 *_rx_desc = (u32 *)skb->data;
|
||||
int drvinfo_sz, desc_shift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++)
|
||||
_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
|
||||
|
||||
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
|
||||
|
||||
skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24));
|
||||
|
||||
phy_stats = (struct rtl8723au_phy_stats *)skb->data;
|
||||
|
||||
drvinfo_sz = rx_desc->drvinfo_sz * 8;
|
||||
desc_shift = rx_desc->shift;
|
||||
skb_pull(skb, drvinfo_sz + desc_shift);
|
||||
|
||||
if (rx_desc->rpt_sel) {
|
||||
struct device *dev = &priv->udev->dev;
|
||||
dev_dbg(dev, "%s: C2H packet\n", __func__);
|
||||
rtl8723bu_handle_c2h(priv, skb);
|
||||
dev_kfree_skb(skb);
|
||||
return RX_TYPE_C2H;
|
||||
}
|
||||
|
||||
if (rx_desc->phy_stats)
|
||||
rtl8xxxu_rx_parse_phystats(priv, rx_status, phy_stats,
|
||||
rx_desc->rxmcs);
|
||||
|
||||
rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
|
||||
rx_status->flag |= RX_FLAG_MACTIME_START;
|
||||
|
||||
if (!rx_desc->swdec)
|
||||
rx_status->flag |= RX_FLAG_DECRYPTED;
|
||||
if (rx_desc->crc32)
|
||||
rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
|
||||
if (rx_desc->bw)
|
||||
rx_status->flag |= RX_FLAG_40MHZ;
|
||||
|
||||
if (rx_desc->rxmcs >= DESC_RATE_MCS0) {
|
||||
rx_status->flag |= RX_FLAG_HT;
|
||||
rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
|
||||
} else {
|
||||
rx_status->rate_idx = rx_desc->rxmcs;
|
||||
}
|
||||
|
||||
rx_status->freq = hw->conf.chandef.chan->center_freq;
|
||||
rx_status->band = hw->conf.chandef.chan->band;
|
||||
|
||||
ieee80211_rx_irqsafe(hw, skb);
|
||||
return RX_TYPE_DATA_PKT;
|
||||
}
|
||||
|
||||
static void rtl8xxxu_rx_complete(struct urb *urb)
|
||||
{
|
||||
struct rtl8xxxu_rx_urb *rx_urb =
|
||||
|
@ -5195,26 +5320,12 @@ static void rtl8xxxu_rx_complete(struct urb *urb)
|
|||
struct ieee80211_hw *hw = rx_urb->hw;
|
||||
struct rtl8xxxu_priv *priv = hw->priv;
|
||||
struct sk_buff *skb = (struct sk_buff *)urb->context;
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct device *dev = &priv->udev->dev;
|
||||
int rx_type;
|
||||
|
||||
skb_put(skb, urb->actual_length);
|
||||
|
||||
if (urb->status == 0) {
|
||||
memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
|
||||
|
||||
rx_type = priv->fops->parse_rx_desc(priv, skb, rx_status);
|
||||
|
||||
rx_status->freq = hw->conf.chandef.chan->center_freq;
|
||||
rx_status->band = hw->conf.chandef.chan->band;
|
||||
|
||||
if (rx_type == RX_TYPE_DATA_PKT)
|
||||
ieee80211_rx_irqsafe(hw, skb);
|
||||
else {
|
||||
rtl8723bu_handle_c2h(priv, skb);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
priv->fops->parse_rx_desc(priv, skb);
|
||||
|
||||
skb = NULL;
|
||||
rx_urb->urb.context = NULL;
|
||||
|
@ -5234,12 +5345,20 @@ cleanup:
|
|||
static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
|
||||
struct rtl8xxxu_rx_urb *rx_urb)
|
||||
{
|
||||
struct rtl8xxxu_fileops *fops = priv->fops;
|
||||
struct sk_buff *skb;
|
||||
int skb_size;
|
||||
int ret, rx_desc_sz;
|
||||
|
||||
rx_desc_sz = priv->fops->rx_desc_size;
|
||||
skb_size = rx_desc_sz + RTL_RX_BUFFER_SIZE;
|
||||
rx_desc_sz = fops->rx_desc_size;
|
||||
|
||||
if (priv->rx_buf_aggregation && fops->rx_agg_buf_size) {
|
||||
skb_size = fops->rx_agg_buf_size;
|
||||
skb_size += (rx_desc_sz + sizeof(struct rtl8723au_phy_stats));
|
||||
} else {
|
||||
skb_size = IEEE80211_MAX_FRAME_LEN;
|
||||
}
|
||||
|
||||
skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
@ -5267,7 +5386,7 @@ static void rtl8xxxu_int_complete(struct urb *urb)
|
|||
if (ret)
|
||||
usb_unanchor_urb(urb);
|
||||
} else {
|
||||
dev_info(dev, "%s: Error %i\n", __func__, urb->status);
|
||||
dev_dbg(dev, "%s: Error %i\n", __func__, urb->status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -405,7 +405,11 @@
|
|||
#define REG_DWBCN1_CTRL_8723B 0x0228
|
||||
|
||||
/* 0x0280 ~ 0x02FF RXDMA Configuration */
|
||||
#define REG_RXDMA_AGG_PG_TH 0x0280
|
||||
#define REG_RXDMA_AGG_PG_TH 0x0280 /* 0-7 : USB DMA size bits
|
||||
8-14: USB DMA timeout
|
||||
15 : Aggregation enable
|
||||
Only seems to be used
|
||||
on 8723bu/8192eu */
|
||||
#define RXDMA_USB_AGG_ENABLE BIT(31)
|
||||
#define REG_RXPKT_NUM 0x0284
|
||||
#define RXPKT_NUM_RXDMA_IDLE BIT(17)
|
||||
|
@ -1052,10 +1056,14 @@
|
|||
#define USB_HIMR_ROK BIT(0) /* Receive DMA OK Interrupt */
|
||||
|
||||
#define REG_USB_SPECIAL_OPTION 0xfe55
|
||||
#define USB_SPEC_USB_AGG_ENABLE BIT(3) /* Enable USB aggregation */
|
||||
#define USB_SPEC_INT_BULK_SELECT BIT(4) /* Use interrupt endpoint to
|
||||
deliver interrupt packet.
|
||||
0: Use int, 1: use bulk */
|
||||
#define REG_USB_HRPWM 0xfe58
|
||||
#define REG_USB_DMA_AGG_TO 0xfe5b
|
||||
#define REG_USB_AGG_TO 0xfe5c
|
||||
#define REG_USB_AGG_TH 0xfe5d
|
||||
#define REG_USB_AGG_TIMEOUT 0xfe5c
|
||||
#define REG_USB_AGG_THRESH 0xfe5d
|
||||
|
||||
#define REG_NORMAL_SIE_VID 0xfe60 /* 0xfe60 - 0xfe61 */
|
||||
#define REG_NORMAL_SIE_PID 0xfe62 /* 0xfe62 - 0xfe63 */
|
||||
|
|
|
@ -901,7 +901,7 @@ void exhalbtc_stack_update_profile_info(void)
|
|||
{
|
||||
}
|
||||
|
||||
void exhalbtc_update_min_bt_rssi(char bt_rssi)
|
||||
void exhalbtc_update_min_bt_rssi(s8 bt_rssi)
|
||||
{
|
||||
struct btc_coexist *btcoexist = &gl_bt_coexist;
|
||||
|
||||
|
|
|
@ -433,7 +433,7 @@ struct btc_stack_info {
|
|||
u8 num_of_hid;
|
||||
bool pan_exist;
|
||||
bool unknown_acl_exist;
|
||||
char min_bt_rssi;
|
||||
s8 min_bt_rssi;
|
||||
};
|
||||
|
||||
struct btc_statistics {
|
||||
|
@ -537,7 +537,7 @@ void exhalbtc_dbg_control(struct btc_coexist *btcoexist, u8 code, u8 len,
|
|||
void exhalbtc_stack_update_profile_info(void);
|
||||
void exhalbtc_set_hci_version(u16 hci_version);
|
||||
void exhalbtc_set_bt_patch_version(u16 bt_hci_version, u16 bt_patch_version);
|
||||
void exhalbtc_update_min_bt_rssi(char bt_rssi);
|
||||
void exhalbtc_update_min_bt_rssi(s8 bt_rssi);
|
||||
void exhalbtc_set_bt_exist(bool bt_exist);
|
||||
void exhalbtc_set_chip_type(u8 chip_type);
|
||||
void exhalbtc_set_ant_num(struct rtl_priv *rtlpriv, u8 type, u8 ant_num);
|
||||
|
|
|
@ -526,7 +526,7 @@ static void _rtl_add_wowlan_patterns(struct ieee80211_hw *hw,
|
|||
/* 3. calculate crc */
|
||||
rtl_pattern.crc = _calculate_wol_pattern_crc(content, len);
|
||||
RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
|
||||
"CRC_Remainder = 0x%x", rtl_pattern.crc);
|
||||
"CRC_Remainder = 0x%x\n", rtl_pattern.crc);
|
||||
|
||||
/* 4. write crc & mask_for_hw to hw */
|
||||
rtlpriv->cfg->ops->add_wowlan_pattern(hw, &rtl_pattern, i);
|
||||
|
|
|
@ -48,3 +48,28 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
|
|||
/*Init Debug flag enable condition */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init);
|
||||
|
||||
#ifdef CONFIG_RTLWIFI_DEBUG
|
||||
void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level,
|
||||
const char *modname, const char *fmt, ...)
|
||||
{
|
||||
if (unlikely((comp & rtlpriv->dbg.global_debugcomponents) &&
|
||||
(level <= rtlpriv->dbg.global_debuglevel))) {
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
printk(KERN_DEBUG "%s:%ps:<%lx-%x> %pV",
|
||||
modname, __builtin_return_address(0),
|
||||
in_interrupt(), in_atomic(),
|
||||
&vaf);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_rtl_dbg_trace);
|
||||
#endif
|
||||
|
|
|
@ -174,15 +174,16 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
struct rtl_priv;
|
||||
|
||||
__printf(5, 6)
|
||||
void _rtl_dbg_trace(struct rtl_priv *rtlpriv, int comp, int level,
|
||||
const char *modname, const char *fmt, ...);
|
||||
|
||||
#define RT_TRACE(rtlpriv, comp, level, fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(((comp) & rtlpriv->dbg.global_debugcomponents) && \
|
||||
((level) <= rtlpriv->dbg.global_debuglevel))) { \
|
||||
printk(KERN_DEBUG KBUILD_MODNAME ":%s():<%lx-%x> " fmt, \
|
||||
__func__, in_interrupt(), in_atomic(), \
|
||||
##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
_rtl_dbg_trace(rtlpriv, comp, level, \
|
||||
KBUILD_MODNAME, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define RTPRINT(rtlpriv, dbgtype, dbgflag, fmt, ...) \
|
||||
do { \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*****************************************************************************/
|
||||
#include "wifi.h"
|
||||
#include "efuse.h"
|
||||
#include "pci.h"
|
||||
#include <linux/export.h>
|
||||
|
||||
static const u8 MAX_PGPKT_SIZE = 9;
|
||||
|
@ -1243,3 +1244,80 @@ static u8 efuse_calculate_word_cnts(u8 word_en)
|
|||
return word_cnts;
|
||||
}
|
||||
|
||||
int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv,
|
||||
int max_size, u8 *hwinfo, int *params)
|
||||
{
|
||||
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
|
||||
struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
|
||||
struct device *dev = &rtlpcipriv->dev.pdev->dev;
|
||||
u16 eeprom_id;
|
||||
u16 i, usvalue;
|
||||
|
||||
switch (rtlefuse->epromtype) {
|
||||
case EEPROM_BOOT_EFUSE:
|
||||
rtl_efuse_shadow_map_update(hw);
|
||||
break;
|
||||
|
||||
case EEPROM_93C46:
|
||||
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
|
||||
"RTL8XXX did not boot from eeprom, check it !!\n");
|
||||
return 1;
|
||||
|
||||
default:
|
||||
dev_warn(dev, "no efuse data\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], max_size);
|
||||
|
||||
RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, "MAP",
|
||||
hwinfo, max_size);
|
||||
|
||||
eeprom_id = *((u16 *)&hwinfo[0]);
|
||||
if (eeprom_id != params[0]) {
|
||||
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
|
||||
"EEPROM ID(%#x) is invalid!!\n", eeprom_id);
|
||||
rtlefuse->autoload_failflag = true;
|
||||
} else {
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
|
||||
rtlefuse->autoload_failflag = false;
|
||||
}
|
||||
|
||||
if (rtlefuse->autoload_failflag)
|
||||
return 1;
|
||||
|
||||
rtlefuse->eeprom_vid = *(u16 *)&hwinfo[params[1]];
|
||||
rtlefuse->eeprom_did = *(u16 *)&hwinfo[params[2]];
|
||||
rtlefuse->eeprom_svid = *(u16 *)&hwinfo[params[3]];
|
||||
rtlefuse->eeprom_smid = *(u16 *)&hwinfo[params[4]];
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROMId = 0x%4x\n", eeprom_id);
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
|
||||
|
||||
for (i = 0; i < 6; i += 2) {
|
||||
usvalue = *(u16 *)&hwinfo[params[5] + i];
|
||||
*((u16 *)(&rtlefuse->dev_addr[i])) = usvalue;
|
||||
}
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "%pM\n", rtlefuse->dev_addr);
|
||||
|
||||
rtlefuse->eeprom_channelplan = *&hwinfo[params[6]];
|
||||
rtlefuse->eeprom_version = *(u16 *)&hwinfo[params[7]];
|
||||
rtlefuse->txpwr_fromeprom = true;
|
||||
rtlefuse->eeprom_oemid = *&hwinfo[params[8]];
|
||||
|
||||
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
|
||||
"EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
|
||||
|
||||
/* set channel plan to world wide 13 */
|
||||
rtlefuse->channel_plan = params[9];
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtl_get_hwinfo);
|
||||
|
|
|
@ -109,5 +109,7 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw);
|
|||
void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw);
|
||||
void efuse_force_write_vendor_Id(struct ieee80211_hw *hw);
|
||||
void efuse_re_pg_section(struct ieee80211_hw *hw, u8 section_idx);
|
||||
int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv,
|
||||
int max_size, u8 *hwinfo, int *params);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -76,9 +76,9 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
|
|||
}
|
||||
EXPORT_SYMBOL(rtl_ps_disable_nic);
|
||||
|
||||
bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
|
||||
enum rf_pwrstate state_toset,
|
||||
u32 changesource, bool protect_or_not)
|
||||
static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
|
||||
enum rf_pwrstate state_toset,
|
||||
u32 changesource)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
|
||||
|
@ -86,9 +86,6 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
|
|||
bool actionallowed = false;
|
||||
u16 rfwait_cnt = 0;
|
||||
|
||||
if (protect_or_not)
|
||||
goto no_protect;
|
||||
|
||||
/*Only one thread can change
|
||||
*the RF state at one time, and others
|
||||
*should wait to be executed.
|
||||
|
@ -119,7 +116,6 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
no_protect:
|
||||
rtstate = ppsc->rfpwr_state;
|
||||
|
||||
switch (state_toset) {
|
||||
|
@ -162,15 +158,12 @@ no_protect:
|
|||
if (actionallowed)
|
||||
rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
|
||||
|
||||
if (!protect_or_not) {
|
||||
spin_lock(&rtlpriv->locks.rf_ps_lock);
|
||||
ppsc->rfchange_inprogress = false;
|
||||
spin_unlock(&rtlpriv->locks.rf_ps_lock);
|
||||
}
|
||||
spin_lock(&rtlpriv->locks.rf_ps_lock);
|
||||
ppsc->rfchange_inprogress = false;
|
||||
spin_unlock(&rtlpriv->locks.rf_ps_lock);
|
||||
|
||||
return actionallowed;
|
||||
}
|
||||
EXPORT_SYMBOL(rtl_ps_set_rf_state);
|
||||
|
||||
static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
|
||||
{
|
||||
|
@ -191,7 +184,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
rtl_ps_set_rf_state(hw, ppsc->inactive_pwrstate,
|
||||
RF_CHANGE_BY_IPS, false);
|
||||
RF_CHANGE_BY_IPS);
|
||||
|
||||
if (ppsc->inactive_pwrstate == ERFOFF &&
|
||||
rtlhal->interface == INTF_PCI) {
|
||||
|
@ -587,7 +580,7 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
|
|||
}
|
||||
|
||||
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
|
||||
rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
|
||||
rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS);
|
||||
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
|
||||
}
|
||||
|
||||
|
@ -630,7 +623,7 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
|
|||
spin_unlock(&rtlpriv->locks.rf_ps_lock);
|
||||
|
||||
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
|
||||
rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS , false);
|
||||
rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS);
|
||||
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
|
||||
|
||||
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
|
||||
|
|
|
@ -28,9 +28,6 @@
|
|||
|
||||
#define MAX_SW_LPS_SLEEP_INTV 5
|
||||
|
||||
bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
|
||||
enum rf_pwrstate state_toset, u32 changesource,
|
||||
bool protect_or_not);
|
||||
bool rtl_ps_enable_nic(struct ieee80211_hw *hw);
|
||||
bool rtl_ps_disable_nic(struct ieee80211_hw *hw);
|
||||
void rtl_ips_nic_off(struct ieee80211_hw *hw);
|
||||
|
|
|
@ -94,7 +94,7 @@ static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
|
|||
struct ieee80211_sta *sta,
|
||||
struct ieee80211_tx_rate *rate,
|
||||
struct ieee80211_tx_rate_control *txrc,
|
||||
u8 tries, char rix, int rtsctsenable,
|
||||
u8 tries, s8 rix, int rtsctsenable,
|
||||
bool not_data)
|
||||
{
|
||||
struct rtl_mac *mac = rtl_mac(rtlpriv);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue